Buttons are now always enabled (visually).

Disabled buttons states are useless and make it difficult to modify app theme.
This commit is contained in:
Sad Ellie 2022-12-08 16:11:39 +04:00
parent ffd4284f55
commit 51961d5f68
6 changed files with 57 additions and 35 deletions

View File

@ -147,8 +147,6 @@ private fun PortraitMainScreenContent(
addDigit = processInput, addDigit = processInput,
deleteDigit = deleteDigit, deleteDigit = deleteDigit,
clearInput = clearInput, clearInput = clearInput,
deleteButtonEnabled = mainScreenUIState.deleteButtonEnabled,
dotButtonEnabled = mainScreenUIState.dotButtonEnabled,
) )
} }
} else { } else {
@ -182,7 +180,6 @@ private fun PortraitMainScreenContent(
addDigit = processInput, addDigit = processInput,
deleteDigit = deleteDigit, deleteDigit = deleteDigit,
clearInput = clearInput, clearInput = clearInput,
deleteButtonEnabled = mainScreenUIState.deleteButtonEnabled,
) )
} }
} }

View File

@ -27,9 +27,6 @@ import com.sadellie.unitto.data.KEY_0
* @property resultValue Current output value * @property resultValue Current output value
* @property calculatedValue Currently calculated value. Can be null if not needed (same as input or * @property calculatedValue Currently calculated value. Can be null if not needed (same as input or
* expression in input is invalid) * expression in input is invalid)
* @property deleteButtonEnabled Delete last symbol from input button state
* @property dotButtonEnabled Add dot to input button state
* @property negateButtonEnabled Switch input between positive and negative button state
* @property isLoadingDatabase Whether we are loading data from Database. Need on app launch, once * @property isLoadingDatabase Whether we are loading data from Database. Need on app launch, once
* we are done loading list on Units list can be sorted by usage properly/ * we are done loading list on Units list can be sorted by usage properly/
* @property isLoadingNetwork Whether we are loading data from network * @property isLoadingNetwork Whether we are loading data from network
@ -38,9 +35,6 @@ import com.sadellie.unitto.data.KEY_0
data class MainScreenUIState( data class MainScreenUIState(
var inputValue: String = KEY_0, var inputValue: String = KEY_0,
var resultValue: String = KEY_0, var resultValue: String = KEY_0,
var deleteButtonEnabled: Boolean = false,
var dotButtonEnabled: Boolean = true,
var negateButtonEnabled: Boolean = false,
var isLoadingDatabase: Boolean = true, var isLoadingDatabase: Boolean = true,
var isLoadingNetwork: Boolean = false, var isLoadingNetwork: Boolean = false,
var showError: Boolean = false, var showError: Boolean = false,

View File

@ -82,8 +82,6 @@ class MainViewModel @Inject constructor(
val inputValue: MutableStateFlow<String> = MutableStateFlow(KEY_0) val inputValue: MutableStateFlow<String> = MutableStateFlow(KEY_0)
private val latestInputStack: MutableList<String> = mutableListOf(KEY_0) private val latestInputStack: MutableList<String> = mutableListOf(KEY_0)
private val _inputDisplayValue: MutableStateFlow<String> = MutableStateFlow(KEY_0) private val _inputDisplayValue: MutableStateFlow<String> = MutableStateFlow(KEY_0)
private val _deleteButtonEnabled: MutableStateFlow<Boolean> = MutableStateFlow(false)
private val _negateButtonEnabled: MutableStateFlow<Boolean> = MutableStateFlow(false)
private val _isLoadingDatabase: MutableStateFlow<Boolean> = MutableStateFlow(true) private val _isLoadingDatabase: MutableStateFlow<Boolean> = MutableStateFlow(true)
private val _isLoadingNetwork: MutableStateFlow<Boolean> = MutableStateFlow(false) private val _isLoadingNetwork: MutableStateFlow<Boolean> = MutableStateFlow(false)
private val _showError: MutableStateFlow<Boolean> = MutableStateFlow(false) private val _showError: MutableStateFlow<Boolean> = MutableStateFlow(false)
@ -100,9 +98,6 @@ class MainViewModel @Inject constructor(
return@combine MainScreenUIState( return@combine MainScreenUIState(
inputValue = inputDisplayValue, inputValue = inputDisplayValue,
resultValue = convertValue(), resultValue = convertValue(),
deleteButtonEnabled = inputValue.value != KEY_0,
dotButtonEnabled = canEnterDot(),
negateButtonEnabled = _negateButtonEnabled.value,
isLoadingDatabase = isLoadingDatabase, isLoadingDatabase = isLoadingDatabase,
isLoadingNetwork = isLoadingNetwork, isLoadingNetwork = isLoadingNetwork,
showError = showError, showError = showError,
@ -189,8 +184,6 @@ class MainViewModel @Inject constructor(
// First we change unit // First we change unit
unitFrom = clickedUnit unitFrom = clickedUnit
// Now we check for negate button
_negateButtonEnabled.update { clickedUnit.group.canNegate }
// Now we change to positive if the group we switched to supports negate // Now we change to positive if the group we switched to supports negate
if (!clickedUnit.group.canNegate) { if (!clickedUnit.group.canNegate) {
inputValue.update { inputValue.value.removePrefix(KEY_MINUS) } inputValue.update { inputValue.value.removePrefix(KEY_MINUS) }
@ -307,7 +300,6 @@ class MainViewModel @Inject constructor(
val lastTwoSymbols = latestInputStack.takeLast(2) val lastTwoSymbols = latestInputStack.takeLast(2)
val lastSymbol: String = lastTwoSymbols.getOrNull(1) ?: lastTwoSymbols[0] val lastSymbol: String = lastTwoSymbols.getOrNull(1) ?: lastTwoSymbols[0]
val lastSecondSymbol: String? = lastTwoSymbols.getOrNull(0) val lastSecondSymbol: String? = lastTwoSymbols.getOrNull(0)
_deleteButtonEnabled.update { true }
when (symbolToAdd) { when (symbolToAdd) {
KEY_PLUS, KEY_DIVIDE, KEY_MULTIPLY, KEY_EXPONENT -> { KEY_PLUS, KEY_DIVIDE, KEY_MULTIPLY, KEY_EXPONENT -> {
@ -368,7 +360,9 @@ class MainViewModel @Inject constructor(
} }
} }
KEY_DOT -> { KEY_DOT -> {
setInputSymbols(symbolToAdd) if (canEnterDot()) {
setInputSymbols(symbolToAdd)
}
} }
KEY_LEFT_BRACKET, KEY_RIGHT_BRACKET -> { KEY_LEFT_BRACKET, KEY_RIGHT_BRACKET -> {
when { when {
@ -411,6 +405,9 @@ class MainViewModel @Inject constructor(
* Deletes last symbol from input and handles buttons state (enabled/disabled) * Deletes last symbol from input and handles buttons state (enabled/disabled)
*/ */
fun deleteDigit() { fun deleteDigit() {
// Default input, don't delete
if (inputValue.value == KEY_0) return
val lastSymbol = latestInputStack.removeLast() val lastSymbol = latestInputStack.removeLast()
// We will need to delete last symbol from both values // We will need to delete last symbol from both values
@ -443,6 +440,7 @@ class MainViewModel @Inject constructor(
else -> { else -> {
inputValue.update { symbol } inputValue.update { symbol }
_inputDisplayValue.update { displaySymbol } _inputDisplayValue.update { displaySymbol }
latestInputStack.clear()
latestInputStack.add(symbol) latestInputStack.add(symbol)
} }
} }
@ -452,7 +450,6 @@ class MainViewModel @Inject constructor(
* Clears input value and sets it to default (ZERO) * Clears input value and sets it to default (ZERO)
*/ */
fun clearInput() { fun clearInput() {
_deleteButtonEnabled.update { false }
setInputSymbols(KEY_0, false) setInputSymbols(KEY_0, false)
} }
@ -497,7 +494,6 @@ class MainViewModel @Inject constructor(
allUnitsRepository.loadFromDatabase(mContext, allBasedUnits) allUnitsRepository.loadFromDatabase(mContext, allBasedUnits)
// User is free to convert values and units on units screen can be sorted properly // User is free to convert values and units on units screen can be sorted properly
_negateButtonEnabled.update { unitFrom.group.canNegate }
_isLoadingDatabase.update { false } _isLoadingDatabase.update { false }
updateCurrenciesBasicUnits() updateCurrenciesBasicUnits()
} }

View File

@ -57,8 +57,6 @@ import com.sadellie.unitto.screens.Formatter
* @param addDigit Function that is called when clicking number and dot buttons * @param addDigit Function that is called when clicking number and dot buttons
* @param deleteDigit Function that is called when clicking delete "<" button * @param deleteDigit Function that is called when clicking delete "<" button
* @param clearInput Function that is called when clicking clear "AC" button * @param clearInput Function that is called when clicking clear "AC" button
* @param deleteButtonEnabled Current state of delete "<" button
* @param dotButtonEnabled Current state of clear "AC" button
*/ */
@Composable @Composable
fun Keyboard( fun Keyboard(
@ -66,8 +64,6 @@ fun Keyboard(
addDigit: (String) -> Unit = {}, addDigit: (String) -> Unit = {},
deleteDigit: () -> Unit = {}, deleteDigit: () -> Unit = {},
clearInput: () -> Unit = {}, clearInput: () -> Unit = {},
deleteButtonEnabled: Boolean = false,
dotButtonEnabled: Boolean = true
) { ) {
Row( Row(
modifier = modifier.fillMaxSize() modifier = modifier.fillMaxSize()
@ -91,14 +87,14 @@ fun Keyboard(
KeyboardButton(bModifier, KEY_8, onClick = addDigit) KeyboardButton(bModifier, KEY_8, onClick = addDigit)
KeyboardButton(bModifier, KEY_5, onClick = addDigit) KeyboardButton(bModifier, KEY_5, onClick = addDigit)
KeyboardButton(bModifier, KEY_2, onClick = addDigit) KeyboardButton(bModifier, KEY_2, onClick = addDigit)
KeyboardButton(bModifier, Formatter.fractional, enabled = dotButtonEnabled) { addDigit(KEY_DOT) } KeyboardButton(bModifier, Formatter.fractional) { addDigit(KEY_DOT) }
} }
Column(cModifier) { Column(cModifier) {
KeyboardButton(bModifier, KEY_EXPONENT, isPrimary = false, onClick = { addDigit(KEY_EXPONENT) }) KeyboardButton(bModifier, KEY_EXPONENT, isPrimary = false, onClick = { addDigit(KEY_EXPONENT) })
KeyboardButton(bModifier, KEY_9, onClick = addDigit) KeyboardButton(bModifier, KEY_9, onClick = addDigit)
KeyboardButton(bModifier, KEY_6, onClick = addDigit) KeyboardButton(bModifier, KEY_6, onClick = addDigit)
KeyboardButton(bModifier, KEY_3, onClick = addDigit) KeyboardButton(bModifier, KEY_3, onClick = addDigit)
KeyboardButton(bModifier, KEY_CLEAR, enabled = deleteButtonEnabled, onLongClick = clearInput) { deleteDigit() } KeyboardButton(bModifier, KEY_CLEAR, onLongClick = clearInput) { deleteDigit() }
} }
Column(cModifier) { Column(cModifier) {
KeyboardButton(bModifier, KEY_SQRT, isPrimary = false, onClick = { addDigit(KEY_SQRT) }) KeyboardButton(bModifier, KEY_SQRT, isPrimary = false, onClick = { addDigit(KEY_SQRT) })

View File

@ -41,7 +41,6 @@ import com.sadellie.unitto.ui.theme.NumbersTextStyleTitleLarge
* *
* @param modifier Modifier that is applied to a [Button] component. * @param modifier Modifier that is applied to a [Button] component.
* @param digit Symbol to show on button. * @param digit Symbol to show on button.
* @param enabled Current state of this button.
* @param isPrimary If true will use `inverseOnSurface` color, else `secondaryContainer`. * @param isPrimary If true will use `inverseOnSurface` color, else `secondaryContainer`.
* @param onLongClick Action to perform when holding this button. * @param onLongClick Action to perform when holding this button.
* @param onClick Action to perform when clicking this button. * @param onClick Action to perform when clicking this button.
@ -50,7 +49,6 @@ import com.sadellie.unitto.ui.theme.NumbersTextStyleTitleLarge
fun KeyboardButton( fun KeyboardButton(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
digit: String, digit: String,
enabled: Boolean = true,
isPrimary: Boolean = true, isPrimary: Boolean = true,
onLongClick: () -> Unit = {}, onLongClick: () -> Unit = {},
onClick: (String) -> Unit = {} onClick: (String) -> Unit = {}
@ -67,12 +65,11 @@ fun KeyboardButton(
interactionSource = interactionSource, interactionSource = interactionSource,
shape = RoundedCornerShape(cornerRadius), shape = RoundedCornerShape(cornerRadius),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = if (isPrimary) MaterialTheme.colorScheme.inverseOnSurface else MaterialTheme.colorScheme.secondaryContainer, containerColor = if (isPrimary) MaterialTheme.colorScheme.surfaceVariant else MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer, contentColor = MaterialTheme.colorScheme.onSecondaryContainer,
disabledContentColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.3f) disabledContentColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.3f)
), ),
onClick = { onClick(digit) }, onClick = { onClick(digit) },
enabled = enabled,
contentPadding = PaddingValues(0.dp) contentPadding = PaddingValues(0.dp)
) { ) {
Text( Text(

View File

@ -244,33 +244,73 @@ class MainViewModelTest {
} }
private fun `test dot`() { private fun `test dot`() {
// 0 | . | 0. // 0 | ... | 0.
viewModel.processInput(KEY_DOT)
viewModel.processInput(KEY_DOT)
viewModel.processInput(KEY_DOT) viewModel.processInput(KEY_DOT)
assertEquals("0.", viewModel.inputValue.value) assertEquals("0.", viewModel.inputValue.value)
assertEquals("0.", viewModel.mainFlow.value.inputValue) assertEquals("0.", viewModel.mainFlow.value.inputValue)
viewModel.clearInput() viewModel.clearInput()
// 1 | . | 1. // 1 | ... | 1.
viewModel.processInput(KEY_1) viewModel.processInput(KEY_1)
viewModel.processInput(KEY_DOT) viewModel.processInput(KEY_DOT)
viewModel.processInput(KEY_DOT)
viewModel.processInput(KEY_DOT)
assertEquals("1.", viewModel.inputValue.value) assertEquals("1.", viewModel.inputValue.value)
assertEquals("1.", viewModel.mainFlow.value.inputValue) assertEquals("1.", viewModel.mainFlow.value.inputValue)
viewModel.clearInput() viewModel.clearInput()
// 1+ | . | 1+. // 1+ | ... | 1+.
viewModel.processInput(KEY_1) viewModel.processInput(KEY_1)
viewModel.processInput(KEY_PLUS) viewModel.processInput(KEY_PLUS)
viewModel.processInput(KEY_DOT) viewModel.processInput(KEY_DOT)
viewModel.processInput(KEY_DOT)
viewModel.processInput(KEY_DOT)
assertEquals("1+.", viewModel.inputValue.value) assertEquals("1+.", viewModel.inputValue.value)
assertEquals("1+.", viewModel.mainFlow.value.inputValue) assertEquals("1+.", viewModel.mainFlow.value.inputValue)
viewModel.clearInput() viewModel.clearInput()
// √ | . | √. // √ | ... | √.
viewModel.processInput(KEY_SQRT) viewModel.processInput(KEY_SQRT)
viewModel.processInput(KEY_DOT) viewModel.processInput(KEY_DOT)
viewModel.processInput(KEY_DOT)
viewModel.processInput(KEY_DOT)
assertEquals("√.", viewModel.inputValue.value) assertEquals("√.", viewModel.inputValue.value)
assertEquals("√.", viewModel.mainFlow.value.inputValue) assertEquals("√.", viewModel.mainFlow.value.inputValue)
viewModel.clearInput() viewModel.clearInput()
// √21 | ... | √21.
viewModel.processInput(KEY_SQRT)
viewModel.processInput(KEY_2)
viewModel.processInput(KEY_1)
viewModel.processInput(KEY_DOT)
viewModel.processInput(KEY_DOT)
viewModel.processInput(KEY_DOT)
assertEquals("√21.", viewModel.inputValue.value)
assertEquals("√21.", viewModel.mainFlow.value.inputValue)
viewModel.clearInput()
// √21+1.01-.23 | ... | √21+1.01-.23
viewModel.processInput(KEY_SQRT)
viewModel.processInput(KEY_2)
viewModel.processInput(KEY_1)
viewModel.processInput(KEY_PLUS)
viewModel.processInput(KEY_1)
viewModel.processInput(KEY_DOT)
viewModel.processInput(KEY_0)
viewModel.processInput(KEY_1)
viewModel.processInput(KEY_MINUS)
viewModel.processInput(KEY_DOT)
viewModel.processInput(KEY_2)
viewModel.processInput(KEY_3)
viewModel.processInput(KEY_DOT)
viewModel.processInput(KEY_DOT)
viewModel.processInput(KEY_DOT)
assertEquals("√21+1.01-.23", viewModel.inputValue.value)
assertEquals("√21+1.01.23", viewModel.mainFlow.value.inputValue)
viewModel.clearInput()
} }
private fun `test minus`() { private fun `test minus`() {
@ -399,6 +439,9 @@ class MainViewModelTest {
} }
viewModel.clearInput() viewModel.clearInput()
// This should not delete default input (0)
viewModel.deleteDigit()
// Now we check that we can delete multiple values // Now we check that we can delete multiple values
viewModel.processInput(KEY_3) viewModel.processInput(KEY_3)
viewModel.processInput(KEY_SQRT) viewModel.processInput(KEY_SQRT)
@ -409,5 +452,4 @@ class MainViewModelTest {
Dispatchers.resetMain() Dispatchers.resetMain()
} }
} }