feat: добавил визуальную индикацию ожидающей операции
This commit is contained in:
@@ -54,21 +54,41 @@ fun CalculatorScreen(viewModel: CalculatorViewModel) {
|
|||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
verticalArrangement = Arrangement.SpaceBetween,
|
verticalArrangement = Arrangement.SpaceBetween,
|
||||||
) {
|
) {
|
||||||
DisplaySection(display = uiState.display)
|
DisplaySection(
|
||||||
ButtonGrid(viewModel = viewModel)
|
display = uiState.display,
|
||||||
|
pendingExpression = uiState.pendingExpression,
|
||||||
|
)
|
||||||
|
ButtonGrid(
|
||||||
|
viewModel = viewModel,
|
||||||
|
pendingOperation = uiState.pendingOperation,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DisplaySection(display: String) {
|
private fun DisplaySection(
|
||||||
|
display: String,
|
||||||
|
pendingExpression: String?,
|
||||||
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 24.dp),
|
.padding(vertical = 24.dp),
|
||||||
horizontalAlignment = Alignment.End,
|
horizontalAlignment = Alignment.End,
|
||||||
) {
|
) {
|
||||||
|
if (pendingExpression != null) {
|
||||||
|
Text(
|
||||||
|
text = pendingExpression,
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.6f),
|
||||||
|
textAlign = TextAlign.End,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
)
|
||||||
|
}
|
||||||
Text(
|
Text(
|
||||||
text = display,
|
text = display,
|
||||||
style = MaterialTheme.typography.headlineLarge,
|
style = MaterialTheme.typography.headlineLarge,
|
||||||
@@ -82,7 +102,10 @@ private fun DisplaySection(display: String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ButtonGrid(viewModel: CalculatorViewModel) {
|
private fun ButtonGrid(
|
||||||
|
viewModel: CalculatorViewModel,
|
||||||
|
pendingOperation: CalculatorOperation?,
|
||||||
|
) {
|
||||||
val rows = listOf(
|
val rows = listOf(
|
||||||
listOf("C" to CalculatorButtonType.Clear, "÷" to CalculatorButtonType.Operator),
|
listOf("C" to CalculatorButtonType.Clear, "÷" to CalculatorButtonType.Operator),
|
||||||
listOf("7" to CalculatorButtonType.Digit, "8" to CalculatorButtonType.Digit, "9" to CalculatorButtonType.Digit, "×" to CalculatorButtonType.Operator),
|
listOf("7" to CalculatorButtonType.Digit, "8" to CalculatorButtonType.Digit, "9" to CalculatorButtonType.Digit, "×" to CalculatorButtonType.Operator),
|
||||||
@@ -111,6 +134,7 @@ private fun ButtonGrid(viewModel: CalculatorViewModel) {
|
|||||||
label = "÷",
|
label = "÷",
|
||||||
type = CalculatorButtonType.Operator,
|
type = CalculatorButtonType.Operator,
|
||||||
onClick = { viewModel.onOperation(CalculatorOperation.Divide) },
|
onClick = { viewModel.onOperation(CalculatorOperation.Divide) },
|
||||||
|
isSelected = pendingOperation == CalculatorOperation.Divide,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.aspectRatio(1f),
|
.aspectRatio(1f),
|
||||||
@@ -128,6 +152,7 @@ private fun ButtonGrid(viewModel: CalculatorViewModel) {
|
|||||||
label = label,
|
label = label,
|
||||||
type = type,
|
type = type,
|
||||||
onClick = { handleButtonClick(label, viewModel) },
|
onClick = { handleButtonClick(label, viewModel) },
|
||||||
|
isSelected = labelToOperation(label) == pendingOperation,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(weight)
|
.weight(weight)
|
||||||
.aspectRatio(if (label == "0") 2.15f else 1f),
|
.aspectRatio(if (label == "0") 2.15f else 1f),
|
||||||
@@ -139,6 +164,14 @@ private fun ButtonGrid(viewModel: CalculatorViewModel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun labelToOperation(label: String): CalculatorOperation? = when (label) {
|
||||||
|
"+" -> CalculatorOperation.Add
|
||||||
|
"−" -> CalculatorOperation.Subtract
|
||||||
|
"×" -> CalculatorOperation.Multiply
|
||||||
|
"÷" -> CalculatorOperation.Divide
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleButtonClick(label: String, viewModel: CalculatorViewModel) {
|
private fun handleButtonClick(label: String, viewModel: CalculatorViewModel) {
|
||||||
when (label) {
|
when (label) {
|
||||||
"C" -> viewModel.onClear()
|
"C" -> viewModel.onClear()
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.heller.calculator
|
package com.heller.calculator
|
||||||
|
|
||||||
enum class CalculatorOperation(val symbol: String) {
|
enum class CalculatorOperation(val symbol: String, val displaySymbol: String) {
|
||||||
Add("+"),
|
Add("+", "+"),
|
||||||
Subtract("-"),
|
Subtract("-", "−"),
|
||||||
Multiply("*"),
|
Multiply("*", "×"),
|
||||||
Divide("/");
|
Divide("/", "÷");
|
||||||
|
|
||||||
fun apply(a: Double, b: Double): Double = when (this) {
|
fun apply(a: Double, b: Double): Double = when (this) {
|
||||||
Add -> a + b
|
Add -> a + b
|
||||||
@@ -17,4 +17,6 @@ enum class CalculatorOperation(val symbol: String) {
|
|||||||
data class CalculatorUiState(
|
data class CalculatorUiState(
|
||||||
val display: String = "0",
|
val display: String = "0",
|
||||||
val error: String? = null,
|
val error: String? = null,
|
||||||
|
val pendingOperation: CalculatorOperation? = null,
|
||||||
|
val pendingExpression: String? = null,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ class CalculatorViewModel : ViewModel() {
|
|||||||
|
|
||||||
pendingOperation = operation
|
pendingOperation = operation
|
||||||
waitingForOperand = true
|
waitingForOperand = true
|
||||||
|
syncUiState()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onEquals() {
|
fun onEquals() {
|
||||||
@@ -69,7 +70,7 @@ class CalculatorViewModel : ViewModel() {
|
|||||||
storedValue = null
|
storedValue = null
|
||||||
pendingOperation = null
|
pendingOperation = null
|
||||||
waitingForOperand = true
|
waitingForOperand = true
|
||||||
updateDisplay(formatResult(result))
|
syncUiState(display = formatResult(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onClear() {
|
fun onClear() {
|
||||||
@@ -106,6 +107,33 @@ class CalculatorViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateDisplay(display: String) {
|
private fun updateDisplay(display: String) {
|
||||||
_uiState.update { it.copy(display = display) }
|
syncUiState(display = display)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun syncUiState(
|
||||||
|
display: String? = null,
|
||||||
|
clearError: Boolean = false,
|
||||||
|
setError: String? = null,
|
||||||
|
) {
|
||||||
|
_uiState.update { state ->
|
||||||
|
val newDisplay = display ?: state.display
|
||||||
|
val newError = when {
|
||||||
|
setError != null -> setError
|
||||||
|
clearError -> null
|
||||||
|
else -> state.error
|
||||||
|
}
|
||||||
|
val expression = if (pendingOperation != null && storedValue != null) {
|
||||||
|
"${formatResult(storedValue!!)} ${pendingOperation!!.displaySymbol}"
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
state.copy(
|
||||||
|
display = newDisplay,
|
||||||
|
error = newError,
|
||||||
|
pendingOperation = pendingOperation,
|
||||||
|
pendingExpression = expression,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.heller.calculator.ui.components
|
package com.heller.calculator.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.BorderStroke
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
@@ -26,19 +27,22 @@ fun CalculatorButton(
|
|||||||
type: CalculatorButtonType,
|
type: CalculatorButtonType,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
isSelected: Boolean = false,
|
||||||
) {
|
) {
|
||||||
val containerColor = when (type) {
|
val containerColor = when {
|
||||||
CalculatorButtonType.Digit -> MaterialTheme.colorScheme.surfaceVariant
|
isSelected -> MaterialTheme.colorScheme.primary
|
||||||
CalculatorButtonType.Operator -> MaterialTheme.colorScheme.primaryContainer
|
type == CalculatorButtonType.Digit -> MaterialTheme.colorScheme.surfaceVariant
|
||||||
CalculatorButtonType.Equals -> MaterialTheme.colorScheme.primary
|
type == CalculatorButtonType.Operator -> MaterialTheme.colorScheme.primaryContainer
|
||||||
CalculatorButtonType.Clear -> MaterialTheme.colorScheme.errorContainer
|
type == CalculatorButtonType.Equals -> MaterialTheme.colorScheme.primary
|
||||||
|
else -> MaterialTheme.colorScheme.errorContainer
|
||||||
}
|
}
|
||||||
|
|
||||||
val contentColor = when (type) {
|
val contentColor = when {
|
||||||
CalculatorButtonType.Digit -> MaterialTheme.colorScheme.onSurfaceVariant
|
isSelected -> MaterialTheme.colorScheme.onPrimary
|
||||||
CalculatorButtonType.Operator -> MaterialTheme.colorScheme.onPrimaryContainer
|
type == CalculatorButtonType.Digit -> MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
CalculatorButtonType.Equals -> MaterialTheme.colorScheme.onPrimary
|
type == CalculatorButtonType.Operator -> MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
CalculatorButtonType.Clear -> MaterialTheme.colorScheme.onErrorContainer
|
type == CalculatorButtonType.Equals -> MaterialTheme.colorScheme.onPrimary
|
||||||
|
else -> MaterialTheme.colorScheme.onErrorContainer
|
||||||
}
|
}
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
@@ -49,7 +53,14 @@ fun CalculatorButton(
|
|||||||
containerColor = containerColor,
|
containerColor = containerColor,
|
||||||
contentColor = contentColor,
|
contentColor = contentColor,
|
||||||
),
|
),
|
||||||
elevation = ButtonDefaults.buttonElevation(defaultElevation = 2.dp),
|
border = if (isSelected) {
|
||||||
|
BorderStroke(2.dp, MaterialTheme.colorScheme.onPrimary)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
|
elevation = ButtonDefaults.buttonElevation(
|
||||||
|
defaultElevation = if (isSelected) 6.dp else 2.dp,
|
||||||
|
),
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
|||||||
Reference in New Issue
Block a user