mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-18 16:25:27 +02:00
parent
9ff7e39ece
commit
fb1b7fab2b
@ -81,6 +81,12 @@ Used in this dialog window. Should be short -->
|
||||
<string name="select_time_label">Select time</string>
|
||||
<string name="settings_about_unitto">About Unitto</string>
|
||||
<string name="settings_about_unitto_support">Learn about the app</string>
|
||||
|
||||
<!-- https://s3.eu-west-1.amazonaws.com/po-pub/i/p3aY3IWUI5m9Vjs6vZP3EXAo.png -->
|
||||
<string name="settings_ac_button">AC button</string>
|
||||
|
||||
<!-- https://s3.eu-west-1.amazonaws.com/po-pub/i/p3aY3IWUI5m9Vjs6vZP3EXAo.png -->
|
||||
<string name="settings_ac_button_support">Show separate clear button</string>
|
||||
<string name="settings_additional">Additional</string>
|
||||
<string name="settings_amoled_dark">AMOLED Dark</string>
|
||||
<string name="settings_amoled_dark_support">Use black background for dark themes</string>
|
||||
|
@ -140,3 +140,24 @@ fun KeyboardButtonAdditional(
|
||||
allowVibration = allowVibration,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun KeyboardButtonTertiary(
|
||||
modifier: Modifier,
|
||||
icon: ImageVector,
|
||||
allowVibration: Boolean,
|
||||
contentHeight: Float = if (isPortrait()) 0.578f else 0.793f,
|
||||
onLongClick: (() -> Unit)? = null,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
BasicKeyboardButton(
|
||||
modifier = modifier,
|
||||
contentHeight = contentHeight,
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
containerColor = MaterialTheme.colorScheme.tertiaryContainer,
|
||||
icon = icon,
|
||||
iconColor = MaterialTheme.colorScheme.onTertiaryContainer,
|
||||
allowVibration = allowVibration,
|
||||
)
|
||||
}
|
||||
|
@ -85,14 +85,14 @@ private fun Int.isAfterToken(str: String, token: String): Boolean {
|
||||
}
|
||||
|
||||
|
||||
// This can make [TextFieldValue.addTokens] better by checking tokens both ways. Needs more tests
|
||||
//fun String.tokenAfter(pos: Int): String {
|
||||
// Token.Func.allWithOpeningBracket.forEach {
|
||||
// if (pos.isBeforeToken(this, it)) return it
|
||||
// }
|
||||
//
|
||||
// return substring(pos, (pos + 1).coerceAtMost(this.length))
|
||||
//}
|
||||
// This can also make [TextFieldValue.addTokens] better by checking tokens both ways. Needs more tests
|
||||
fun String.tokenAfter(pos: Int): String {
|
||||
Token.Func.allWithOpeningBracket.forEach {
|
||||
if (pos.isBeforeToken(this, it)) return it
|
||||
}
|
||||
|
||||
return substring(pos, (pos + 1).coerceAtMost(this.length))
|
||||
}
|
||||
|
||||
//private fun String.numberNearby(cursor: Int): String {
|
||||
// val text = this
|
||||
@ -111,8 +111,8 @@ private fun Int.isAfterToken(str: String, token: String): Boolean {
|
||||
// return text.substring(aheadCursor, afterCursor)
|
||||
//}
|
||||
|
||||
//private fun Int.isBeforeToken(str: String, token: String): Boolean {
|
||||
// return str
|
||||
// .substring(this, (this + token.length).coerceAtMost(str.length))
|
||||
// .contains(token)
|
||||
//}
|
||||
private fun Int.isBeforeToken(str: String, token: String): Boolean {
|
||||
return str
|
||||
.substring(this, (this + token.length).coerceAtMost(str.length))
|
||||
.contains(token)
|
||||
}
|
||||
|
@ -53,15 +53,52 @@ fun TextFieldValue.addTokens(tokens: String): TextFieldValue {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>!!! Recursive !!!</b> (one wrong step and you are dead 💀)
|
||||
*/
|
||||
private fun TextFieldValue.deleteAheadAndAdd(tokens: String): TextFieldValue {
|
||||
var newValue = this
|
||||
if (!selection.collapsed) newValue = this.deleteTokens()
|
||||
return newValue
|
||||
.deleteTokens()
|
||||
.addTokens(tokens)
|
||||
fun TextFieldValue.addBracket(): TextFieldValue {
|
||||
val subStringBeforeCursor = text.substring(0..<selection.start)
|
||||
|
||||
// Always open when empty in front
|
||||
if (subStringBeforeCursor.isEmpty()) {
|
||||
return addTokens(Token.Operator.leftBracket)
|
||||
}
|
||||
|
||||
// Always close before operator
|
||||
val operators = listOf(
|
||||
Token.Operator.multiply,
|
||||
Token.Operator.divide,
|
||||
Token.Operator.plus,
|
||||
Token.Operator.minus,
|
||||
Token.Operator.power,
|
||||
)
|
||||
if (text.tokenAfter(selection.start) in operators) {
|
||||
return addTokens(Token.Operator.rightBracket)
|
||||
}
|
||||
|
||||
// Always open when balanced in front
|
||||
val leftBracketChar: Char = Token.Operator.leftBracket.first()
|
||||
val rightBracketChar: Char = Token.Operator.rightBracket.first()
|
||||
var balance = 0
|
||||
subStringBeforeCursor.forEach {
|
||||
if (it == leftBracketChar) balance += 1
|
||||
if (it == rightBracketChar) balance -= 1
|
||||
}
|
||||
if (balance == 0) {
|
||||
return addTokens(Token.Operator.leftBracket)
|
||||
}
|
||||
|
||||
// Always open after operator
|
||||
val operators2 = listOf(
|
||||
Token.Operator.multiply,
|
||||
Token.Operator.divide,
|
||||
Token.Operator.plus,
|
||||
Token.Operator.minus,
|
||||
Token.Operator.power,
|
||||
Token.Operator.leftBracket
|
||||
)
|
||||
if (text.tokenAhead(selection.start) in operators2) {
|
||||
return addTokens(Token.Operator.leftBracket)
|
||||
}
|
||||
|
||||
return addTokens(Token.Operator.rightBracket)
|
||||
}
|
||||
|
||||
fun TextFieldValue.deleteTokens(): TextFieldValue {
|
||||
@ -93,3 +130,14 @@ fun TextFieldValue.deleteTokens(): TextFieldValue {
|
||||
selection = TextRange((newText.length - distanceFromEnd).coerceAtLeast(0))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>!!! Recursive !!!</b> (one wrong step and you are dead 💀)
|
||||
*/
|
||||
private fun TextFieldValue.deleteAheadAndAdd(tokens: String): TextFieldValue {
|
||||
var newValue = this
|
||||
if (!selection.collapsed) newValue = this.deleteTokens()
|
||||
return newValue
|
||||
.deleteTokens()
|
||||
.addTokens(tokens)
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ package com.sadellie.unitto.core.ui
|
||||
import androidx.compose.ui.text.TextRange
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import com.sadellie.unitto.core.base.Token
|
||||
import com.sadellie.unitto.core.ui.common.textfield.addBracket
|
||||
import com.sadellie.unitto.core.ui.common.textfield.addTokens
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
@ -260,6 +261,60 @@ class TextFieldValueExtensionsTest {
|
||||
assertEquals(tf("123+45.[]78"), tf("123+45[6.]78").addTokens(Token.Digit.dot))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun auto() {
|
||||
// Open on empty in front
|
||||
assertEquals(tf("([]"), tf("[]").addBracket())
|
||||
assertEquals(tf("([]123("), tf("[]123(").addBracket())
|
||||
assertEquals(tf("([]("), tf("[123](").addBracket())
|
||||
assertEquals(tf("([]"), tf("[123(]").addBracket())
|
||||
|
||||
// Close before multiply
|
||||
assertEquals(tf("123)[]*456"), tf("123[]*456").addBracket())
|
||||
assertEquals(tf("(123)[]*456"), tf("(123[]*456").addBracket())
|
||||
assertEquals(tf(")123)[]*456"), tf(")123[]*456").addBracket())
|
||||
// Close before divide
|
||||
assertEquals(tf("123)[]/456"), tf("123[]/456").addBracket())
|
||||
assertEquals(tf("(123)[]/456"), tf("(123[]/456").addBracket())
|
||||
assertEquals(tf(")123)[]/456"), tf(")123[]/456").addBracket())
|
||||
// Close before plus
|
||||
assertEquals(tf("123)[]+456"), tf("123[]+456").addBracket())
|
||||
assertEquals(tf("(123)[]+456"), tf("(123[]+456").addBracket())
|
||||
assertEquals(tf(")123)[]+456"), tf(")123[]+456").addBracket())
|
||||
// Close before minus
|
||||
assertEquals(tf("123)[]-456"), tf("123[]-456").addBracket())
|
||||
assertEquals(tf("(123)[]-456"), tf("(123[]-456").addBracket())
|
||||
assertEquals(tf(")123)[]-456"), tf(")123[]-456").addBracket())
|
||||
// Close before power
|
||||
assertEquals(tf("123)[]^456"), tf("123[]^456").addBracket())
|
||||
assertEquals(tf("(123)[]^456"), tf("(123[]^456").addBracket())
|
||||
assertEquals(tf(")123)[]^456"), tf(")123[]^456").addBracket())
|
||||
|
||||
// Open on balanced in front
|
||||
assertEquals(tf("123([]"), tf("123[]").addBracket())
|
||||
assertEquals(tf("123([](((("), tf("123[]((((").addBracket())
|
||||
|
||||
// Open after multiply
|
||||
assertEquals(tf("123*([]456"), tf("123*[]456").addBracket())
|
||||
assertEquals(tf("123*([]"), tf("123*[456]").addBracket())
|
||||
// Open after divide
|
||||
assertEquals(tf("123/([]456"), tf("123/[]456").addBracket())
|
||||
assertEquals(tf("123/([]"), tf("123/[456]").addBracket())
|
||||
// Open after plus
|
||||
assertEquals(tf("123+([]456"), tf("123+[]456").addBracket())
|
||||
assertEquals(tf("123+([]"), tf("123+[456]").addBracket())
|
||||
// Open after minus
|
||||
assertEquals(tf("123-([]456"), tf("123-[]456").addBracket())
|
||||
assertEquals(tf("123-([]"), tf("123-[456]").addBracket())
|
||||
// Open after power
|
||||
assertEquals(tf("123^([]456"), tf("123^[]456").addBracket())
|
||||
assertEquals(tf("123^([]"), tf("123^[456]").addBracket())
|
||||
|
||||
// Default
|
||||
assertEquals(tf("123([]"), tf("123[]").addBracket())
|
||||
assertEquals(tf("123(456+789)[]"), tf("123(456+789[]").addBracket())
|
||||
}
|
||||
|
||||
// Use [] for selection
|
||||
private fun tf(
|
||||
text: String = "",
|
||||
@ -267,6 +322,9 @@ class TextFieldValueExtensionsTest {
|
||||
val selectionStart = text.indexOf("[")
|
||||
val selectionEnd = text.indexOf("]") - 1
|
||||
|
||||
if (selectionStart < 0) throw Exception("forgot selectionStart")
|
||||
if (selectionEnd < 0) throw Exception("forgot selectionEnd")
|
||||
|
||||
return TextFieldValue(
|
||||
text = text
|
||||
.replace("[", "")
|
||||
|
@ -45,6 +45,7 @@ data class CalculatorPreferences(
|
||||
val enableVibrations: Boolean,
|
||||
val separator: Int,
|
||||
val middleZero: Boolean,
|
||||
val acButton: Boolean,
|
||||
val partialHistoryView: Boolean,
|
||||
val precision: Int,
|
||||
val outputFormat: Int,
|
||||
@ -54,6 +55,7 @@ data class ConverterPreferences(
|
||||
val enableVibrations: Boolean,
|
||||
val separator: Int,
|
||||
val middleZero: Boolean,
|
||||
val acButton: Boolean,
|
||||
val precision: Int,
|
||||
val outputFormat: Int,
|
||||
val unitConverterFormatTime: Boolean,
|
||||
@ -68,6 +70,7 @@ data class ConverterPreferences(
|
||||
data class DisplayPreferences(
|
||||
val systemFont: Boolean,
|
||||
val middleZero: Boolean,
|
||||
val acButton: Boolean,
|
||||
)
|
||||
|
||||
data class FormattingPreferences(
|
||||
|
@ -46,4 +46,5 @@ internal object PrefsKeys {
|
||||
val MIDDLE_ZERO = booleanPreferencesKey("MIDDLE_ZERO_PREF_KEY")
|
||||
val SYSTEM_FONT = booleanPreferencesKey("SYSTEM_FONT_PREF_KEY")
|
||||
val PARTIAL_HISTORY_VIEW = booleanPreferencesKey("PARTIAL_HISTORY_VIEW_PREF_KEY")
|
||||
val AC_BUTTON = booleanPreferencesKey("AC_BUTTON_PREF_KEY")
|
||||
}
|
||||
|
@ -75,7 +75,8 @@ class UserPreferencesRepository @Inject constructor(
|
||||
middleZero = preferences.getMiddleZero(),
|
||||
partialHistoryView = preferences.getPartialHistoryView(),
|
||||
precision = preferences.getDigitsPrecision(),
|
||||
outputFormat = preferences.getOutputFormat()
|
||||
outputFormat = preferences.getOutputFormat(),
|
||||
acButton = preferences.getAcButton(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -94,6 +95,7 @@ class UserPreferencesRepository @Inject constructor(
|
||||
enableToolsExperiment = preferences.getEnableToolsExperiment(),
|
||||
latestLeftSideUnit = preferences.getLatestLeftSide(),
|
||||
latestRightSideUnit = preferences.getLatestRightSide(),
|
||||
acButton = preferences.getAcButton(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -102,6 +104,7 @@ class UserPreferencesRepository @Inject constructor(
|
||||
DisplayPreferences(
|
||||
systemFont = preferences.getSystemFont(),
|
||||
middleZero = preferences.getMiddleZero(),
|
||||
acButton = preferences.getAcButton(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -263,6 +266,12 @@ class UserPreferencesRepository @Inject constructor(
|
||||
preferences[PrefsKeys.PARTIAL_HISTORY_VIEW] = enabled
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateAcButton(enabled: Boolean) {
|
||||
dataStore.edit { preferences ->
|
||||
preferences[PrefsKeys.AC_BUTTON] = enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Preferences.getEnableDynamicTheme(): Boolean {
|
||||
@ -359,6 +368,10 @@ private fun Preferences.getLatestRightSide(): String {
|
||||
return this[PrefsKeys.LATEST_RIGHT_SIDE] ?: MyUnitIDS.mile
|
||||
}
|
||||
|
||||
private fun Preferences.getAcButton(): Boolean {
|
||||
return this[PrefsKeys.AC_BUTTON] ?: false
|
||||
}
|
||||
|
||||
private inline fun <T, R> T.letTryOrNull(block: (T) -> R): R? = try {
|
||||
this?.let(block)
|
||||
} catch (e: Exception) {
|
||||
|
@ -89,7 +89,8 @@ internal fun CalculatorRoute(
|
||||
onCursorChange = viewModel::onCursorChange,
|
||||
toggleCalculatorMode = viewModel::toggleCalculatorMode,
|
||||
evaluate = viewModel::evaluate,
|
||||
clearHistory = viewModel::clearHistory
|
||||
clearHistory = viewModel::clearHistory,
|
||||
addBracket = viewModel::addBracket
|
||||
)
|
||||
}
|
||||
|
||||
@ -99,6 +100,7 @@ internal fun CalculatorScreen(
|
||||
navigateToMenu: () -> Unit,
|
||||
navigateToSettings: () -> Unit,
|
||||
addTokens: (String) -> Unit,
|
||||
addBracket: () -> Unit,
|
||||
clearInput: () -> Unit,
|
||||
deleteTokens: () -> Unit,
|
||||
onCursorChange: (TextRange) -> Unit,
|
||||
@ -118,7 +120,8 @@ internal fun CalculatorScreen(
|
||||
onCursorChange = onCursorChange,
|
||||
toggleAngleMode = toggleCalculatorMode,
|
||||
evaluate = evaluate,
|
||||
clearHistory = clearHistory
|
||||
clearHistory = clearHistory,
|
||||
addBracket = addBracket
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -129,6 +132,7 @@ private fun Ready(
|
||||
navigateToMenu: () -> Unit,
|
||||
navigateToSettings: () -> Unit,
|
||||
addSymbol: (String) -> Unit,
|
||||
addBracket: () -> Unit,
|
||||
clearSymbols: () -> Unit,
|
||||
deleteSymbol: () -> Unit,
|
||||
onCursorChange: (TextRange) -> Unit,
|
||||
@ -264,6 +268,8 @@ private fun Ready(
|
||||
toggleAngleMode = toggleAngleMode,
|
||||
evaluate = evaluate,
|
||||
middleZero = uiState.middleZero,
|
||||
acButton = uiState.acButton,
|
||||
addBracket = addBracket
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -343,6 +349,7 @@ private fun PreviewCalculatorScreen() {
|
||||
onCursorChange = {},
|
||||
toggleCalculatorMode = {},
|
||||
evaluate = {},
|
||||
clearHistory = {}
|
||||
clearHistory = {},
|
||||
addBracket = {}
|
||||
)
|
||||
}
|
@ -35,6 +35,7 @@ internal sealed class CalculatorUIState {
|
||||
val allowVibration: Boolean = false,
|
||||
val formatterSymbols: FormatterSymbols = FormatterSymbols.Spaces,
|
||||
val middleZero: Boolean = false,
|
||||
val acButton: Boolean = false,
|
||||
val partialHistoryView: Boolean = true,
|
||||
) : CalculatorUIState()
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import com.sadellie.unitto.core.base.OutputFormat
|
||||
import com.sadellie.unitto.core.base.Separator
|
||||
import com.sadellie.unitto.core.base.Token
|
||||
import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols
|
||||
import com.sadellie.unitto.core.ui.common.textfield.addBracket
|
||||
import com.sadellie.unitto.core.ui.common.textfield.addTokens
|
||||
import com.sadellie.unitto.core.ui.common.textfield.deleteTokens
|
||||
import com.sadellie.unitto.data.calculator.CalculatorHistoryRepository
|
||||
@ -67,7 +68,8 @@ internal class CalculatorViewModel @Inject constructor(
|
||||
middleZero = false,
|
||||
partialHistoryView = true,
|
||||
precision = 3,
|
||||
outputFormat = OutputFormat.PLAIN
|
||||
outputFormat = OutputFormat.PLAIN,
|
||||
acButton = false,
|
||||
)
|
||||
)
|
||||
|
||||
@ -87,6 +89,7 @@ internal class CalculatorViewModel @Inject constructor(
|
||||
allowVibration = userPrefs.enableVibrations,
|
||||
formatterSymbols = AllFormatterSymbols.getById(userPrefs.separator),
|
||||
middleZero = userPrefs.middleZero,
|
||||
acButton = userPrefs.acButton,
|
||||
partialHistoryView = userPrefs.partialHistoryView,
|
||||
)
|
||||
}
|
||||
@ -95,6 +98,7 @@ internal class CalculatorViewModel @Inject constructor(
|
||||
)
|
||||
|
||||
fun addTokens(tokens: String) = _input.update { it.addTokens(tokens) }
|
||||
fun addBracket() = _input.update { it.addBracket() }
|
||||
fun deleteTokens() = _input.update { it.deleteTokens() }
|
||||
fun clearInput() = _input.update { TextFieldValue() }
|
||||
fun onCursorChange(selection: TextRange) = _input.update { it.copy(selection = selection) }
|
||||
|
@ -56,12 +56,15 @@ import com.sadellie.unitto.core.ui.common.ColumnWithConstraints
|
||||
import com.sadellie.unitto.core.ui.common.KeyboardButtonAdditional
|
||||
import com.sadellie.unitto.core.ui.common.KeyboardButtonFilled
|
||||
import com.sadellie.unitto.core.ui.common.KeyboardButtonLight
|
||||
import com.sadellie.unitto.core.ui.common.KeyboardButtonTertiary
|
||||
import com.sadellie.unitto.core.ui.common.RowWithConstraints
|
||||
import com.sadellie.unitto.core.ui.common.key.UnittoIcons
|
||||
import com.sadellie.unitto.core.ui.common.key.unittoicons.AcTan
|
||||
import com.sadellie.unitto.core.ui.common.key.unittoicons.ArCos
|
||||
import com.sadellie.unitto.core.ui.common.key.unittoicons.ArSin
|
||||
import com.sadellie.unitto.core.ui.common.key.unittoicons.Backspace
|
||||
import com.sadellie.unitto.core.ui.common.key.unittoicons.Brackets
|
||||
import com.sadellie.unitto.core.ui.common.key.unittoicons.Clear
|
||||
import com.sadellie.unitto.core.ui.common.key.unittoicons.Comma
|
||||
import com.sadellie.unitto.core.ui.common.key.unittoicons.Cos
|
||||
import com.sadellie.unitto.core.ui.common.key.unittoicons.Deg
|
||||
@ -106,7 +109,9 @@ internal fun CalculatorKeyboard(
|
||||
fractional: String,
|
||||
allowVibration: Boolean,
|
||||
middleZero: Boolean,
|
||||
acButton: Boolean,
|
||||
addSymbol: (String) -> Unit,
|
||||
addBracket: () -> Unit,
|
||||
clearSymbols: () -> Unit,
|
||||
deleteSymbol: () -> Unit,
|
||||
toggleAngleMode: () -> Unit,
|
||||
@ -123,7 +128,9 @@ internal fun CalculatorKeyboard(
|
||||
toggleAngleMode = toggleAngleMode,
|
||||
deleteSymbol = deleteSymbol,
|
||||
clearSymbols = clearSymbols,
|
||||
evaluate = evaluate
|
||||
evaluate = evaluate,
|
||||
acButton = acButton,
|
||||
addBracket = addBracket,
|
||||
)
|
||||
} else {
|
||||
LandscapeKeyboard(
|
||||
@ -136,7 +143,9 @@ internal fun CalculatorKeyboard(
|
||||
toggleAngleMode = toggleAngleMode,
|
||||
deleteSymbol = deleteSymbol,
|
||||
clearSymbols = clearSymbols,
|
||||
evaluate = evaluate
|
||||
evaluate = evaluate,
|
||||
acButton = acButton,
|
||||
addBracket = addBracket,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -152,7 +161,9 @@ private fun PortraitKeyboard(
|
||||
toggleAngleMode: () -> Unit,
|
||||
deleteSymbol: () -> Unit,
|
||||
clearSymbols: () -> Unit,
|
||||
evaluate: () -> Unit
|
||||
evaluate: () -> Unit,
|
||||
acButton: Boolean,
|
||||
addBracket: () -> Unit,
|
||||
) {
|
||||
val fractionalIcon = remember { if (fractional == Token.Digit.dot) UnittoIcons.Dot else UnittoIcons.Comma }
|
||||
var showAdditional: Boolean by remember { mutableStateOf(false) }
|
||||
@ -239,8 +250,13 @@ private fun PortraitKeyboard(
|
||||
Spacer(modifier = Modifier.height(spacerHeight))
|
||||
|
||||
Row(weightModifier) {
|
||||
KeyboardButtonFilled(mainButtonModifier, UnittoIcons.LeftBracket, allowVibration) { addSymbol(Token.Operator.leftBracket) }
|
||||
KeyboardButtonFilled(mainButtonModifier, UnittoIcons.RightBracket, allowVibration) { addSymbol(Token.Operator.rightBracket) }
|
||||
if (acButton) {
|
||||
KeyboardButtonTertiary(mainButtonModifier, UnittoIcons.Clear, allowVibration) { clearSymbols() }
|
||||
KeyboardButtonFilled(mainButtonModifier, UnittoIcons.Brackets, allowVibration) { addBracket() }
|
||||
} else {
|
||||
KeyboardButtonFilled(mainButtonModifier, UnittoIcons.LeftBracket, allowVibration) { addSymbol(Token.Operator.leftBracket) }
|
||||
KeyboardButtonFilled(mainButtonModifier, UnittoIcons.RightBracket, allowVibration) { addSymbol(Token.Operator.rightBracket) }
|
||||
}
|
||||
KeyboardButtonFilled(mainButtonModifier, UnittoIcons.Percent, allowVibration) { addSymbol(Token.Operator.percent) }
|
||||
KeyboardButtonFilled(mainButtonModifier, UnittoIcons.Divide, allowVibration) { addSymbol(Token.Operator.divide) }
|
||||
}
|
||||
@ -361,7 +377,9 @@ private fun LandscapeKeyboard(
|
||||
toggleAngleMode: () -> Unit,
|
||||
deleteSymbol: () -> Unit,
|
||||
clearSymbols: () -> Unit,
|
||||
evaluate: () -> Unit
|
||||
evaluate: () -> Unit,
|
||||
acButton: Boolean,
|
||||
addBracket: () -> Unit,
|
||||
) {
|
||||
val fractionalIcon = remember { if (fractional == Token.Digit.dot) UnittoIcons.Dot else UnittoIcons.Comma }
|
||||
var invMode: Boolean by remember { mutableStateOf(false) }
|
||||
@ -426,13 +444,21 @@ private fun LandscapeKeyboard(
|
||||
}
|
||||
|
||||
Column(Modifier.weight(1f)) {
|
||||
KeyboardButtonFilled(buttonModifier, UnittoIcons.LeftBracket, allowVibration) { addSymbol(Token.Operator.leftBracket) }
|
||||
if (acButton) {
|
||||
KeyboardButtonTertiary(buttonModifier, UnittoIcons.Clear, allowVibration) { clearSymbols() }
|
||||
} else {
|
||||
KeyboardButtonFilled(buttonModifier, UnittoIcons.LeftBracket, allowVibration) { addSymbol(Token.Operator.leftBracket) }
|
||||
}
|
||||
KeyboardButtonFilled(buttonModifier, UnittoIcons.Multiply, allowVibration) { addSymbol(Token.Operator.multiply) }
|
||||
KeyboardButtonFilled(buttonModifier, UnittoIcons.Minus, allowVibration) { addSymbol(Token.Operator.minus) }
|
||||
KeyboardButtonFilled(buttonModifier, UnittoIcons.Plus, allowVibration) { addSymbol(Token.Operator.plus) }
|
||||
}
|
||||
Column(Modifier.weight(1f)) {
|
||||
KeyboardButtonFilled(buttonModifier, UnittoIcons.RightBracket, allowVibration) { addSymbol(Token.Operator.rightBracket) }
|
||||
if (acButton) {
|
||||
KeyboardButtonTertiary(buttonModifier, UnittoIcons.Brackets, allowVibration) { addBracket() }
|
||||
} else {
|
||||
KeyboardButtonFilled(buttonModifier, UnittoIcons.RightBracket, allowVibration) { addSymbol(Token.Operator.rightBracket) }
|
||||
}
|
||||
KeyboardButtonFilled(buttonModifier, UnittoIcons.Divide, allowVibration) { addSymbol(Token.Operator.divide) }
|
||||
KeyboardButtonFilled(buttonModifier, UnittoIcons.Percent, allowVibration) { addSymbol(Token.Operator.percent) }
|
||||
KeyboardButtonFilled(buttonModifier, UnittoIcons.Equal, allowVibration) { evaluate() }
|
||||
@ -518,5 +544,7 @@ private fun PreviewCalculatorKeyboard() {
|
||||
evaluate = {},
|
||||
allowVibration = false,
|
||||
middleZero = false,
|
||||
acButton = true,
|
||||
addBracket = {}
|
||||
)
|
||||
}
|
||||
|
@ -110,6 +110,7 @@ internal fun ConverterRoute(
|
||||
clearInput = viewModel::clearInput,
|
||||
onCursorChange = viewModel::onCursorChange,
|
||||
onErrorClick = viewModel::updateCurrencyRates,
|
||||
addBracket = viewModel::addBracket
|
||||
)
|
||||
}
|
||||
|
||||
@ -126,6 +127,7 @@ private fun ConverterScreen(
|
||||
clearInput: () -> Unit,
|
||||
onCursorChange: (TextRange) -> Unit,
|
||||
onErrorClick: (AbstractUnit) -> Unit,
|
||||
addBracket: () -> Unit,
|
||||
) {
|
||||
when (uiState) {
|
||||
UnitConverterUIState.Loading -> UnittoEmptyScreen()
|
||||
@ -164,7 +166,8 @@ private fun ConverterScreen(
|
||||
swapUnits = swapUnits,
|
||||
navigateToRightScreen = navigateToRightScreen,
|
||||
clearInput = clearInput,
|
||||
refreshCurrencyRates = onErrorClick
|
||||
refreshCurrencyRates = onErrorClick,
|
||||
addBracket = addBracket,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -258,6 +261,7 @@ private fun Default(
|
||||
navigateToRightScreen: () -> Unit,
|
||||
clearInput: () -> Unit,
|
||||
refreshCurrencyRates: (AbstractUnit) -> Unit,
|
||||
addBracket: () -> Unit,
|
||||
) {
|
||||
val locale: Locale = LocalLocale.current
|
||||
var calculation by remember(uiState.calculation) {
|
||||
@ -365,7 +369,9 @@ private fun Default(
|
||||
clearInput = clearInput,
|
||||
allowVibration = uiState.enableHaptic,
|
||||
fractional = uiState.formatterSymbols.fractional,
|
||||
middleZero = uiState.middleZero
|
||||
middleZero = uiState.middleZero,
|
||||
acButton = uiState.acButton,
|
||||
addBracket = addBracket
|
||||
)
|
||||
}
|
||||
)
|
||||
@ -522,5 +528,6 @@ private fun PreviewConverterScreen() {
|
||||
clearInput = {},
|
||||
onCursorChange = {},
|
||||
onErrorClick = {},
|
||||
addBracket = {}
|
||||
)
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ internal sealed class UnitConverterUIState {
|
||||
val outputFormat: Int,
|
||||
val formatTime: Boolean,
|
||||
val currencyRateUpdateState: CurrencyRateUpdateState,
|
||||
val acButton: Boolean,
|
||||
) : UnitConverterUIState()
|
||||
|
||||
data class NumberBase(
|
||||
|
@ -25,6 +25,7 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.sadellie.unitto.core.base.Token
|
||||
import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols
|
||||
import com.sadellie.unitto.core.ui.common.textfield.addBracket
|
||||
import com.sadellie.unitto.core.ui.common.textfield.addTokens
|
||||
import com.sadellie.unitto.core.ui.common.textfield.deleteTokens
|
||||
import com.sadellie.unitto.data.common.combine
|
||||
@ -105,7 +106,8 @@ internal class ConverterViewModel @Inject constructor(
|
||||
scale = prefs.precision,
|
||||
outputFormat = prefs.outputFormat,
|
||||
formatTime = prefs.unitConverterFormatTime,
|
||||
currencyRateUpdateState = currenciesState
|
||||
currencyRateUpdateState = currenciesState,
|
||||
acButton = prefs.acButton,
|
||||
)
|
||||
}
|
||||
(unitFrom is NumberBaseUnit) and (unitTo is NumberBaseUnit) -> {
|
||||
@ -256,6 +258,12 @@ internal class ConverterViewModel @Inject constructor(
|
||||
newValue
|
||||
}
|
||||
|
||||
fun addBracket() = _input.update {
|
||||
val newValue = it.addBracket()
|
||||
savedStateHandle[converterInputKey] = newValue.text
|
||||
newValue
|
||||
}
|
||||
|
||||
fun deleteTokens() = _input.update {
|
||||
val newValue = it.deleteTokens()
|
||||
savedStateHandle[converterInputKey] = newValue.text
|
||||
|
@ -31,8 +31,11 @@ import com.sadellie.unitto.core.base.Token
|
||||
import com.sadellie.unitto.core.ui.common.ColumnWithConstraints
|
||||
import com.sadellie.unitto.core.ui.common.KeyboardButtonFilled
|
||||
import com.sadellie.unitto.core.ui.common.KeyboardButtonLight
|
||||
import com.sadellie.unitto.core.ui.common.KeyboardButtonTertiary
|
||||
import com.sadellie.unitto.core.ui.common.key.UnittoIcons
|
||||
import com.sadellie.unitto.core.ui.common.key.unittoicons.Backspace
|
||||
import com.sadellie.unitto.core.ui.common.key.unittoicons.Brackets
|
||||
import com.sadellie.unitto.core.ui.common.key.unittoicons.Clear
|
||||
import com.sadellie.unitto.core.ui.common.key.unittoicons.Comma
|
||||
import com.sadellie.unitto.core.ui.common.key.unittoicons.Divide
|
||||
import com.sadellie.unitto.core.ui.common.key.unittoicons.Dot
|
||||
@ -70,6 +73,8 @@ internal fun DefaultKeyboard(
|
||||
allowVibration: Boolean,
|
||||
fractional: String,
|
||||
middleZero: Boolean,
|
||||
acButton: Boolean,
|
||||
addBracket: () -> Unit,
|
||||
) {
|
||||
ColumnWithConstraints(modifier) {
|
||||
val fractionalIcon = remember { if (fractional == Token.Digit.dot) UnittoIcons.Dot else UnittoIcons.Comma }
|
||||
@ -85,8 +90,13 @@ internal fun DefaultKeyboard(
|
||||
// Column modifier
|
||||
val cModifier = Modifier.weight(1f)
|
||||
Row(cModifier) {
|
||||
KeyboardButtonFilled(bModifier, UnittoIcons.LeftBracket, allowVibration) { addDigit(Token.Operator.leftBracket) }
|
||||
KeyboardButtonFilled(bModifier, UnittoIcons.RightBracket, allowVibration) { addDigit(Token.Operator.rightBracket) }
|
||||
if (acButton) {
|
||||
KeyboardButtonTertiary(bModifier, UnittoIcons.Clear, allowVibration) { clearInput() }
|
||||
KeyboardButtonFilled(bModifier, UnittoIcons.Brackets, allowVibration) { addBracket() }
|
||||
} else {
|
||||
KeyboardButtonFilled(bModifier, UnittoIcons.LeftBracket, allowVibration) { addDigit(Token.Operator.leftBracket) }
|
||||
KeyboardButtonFilled(bModifier, UnittoIcons.RightBracket, allowVibration) { addDigit(Token.Operator.rightBracket) }
|
||||
}
|
||||
KeyboardButtonFilled(bModifier, UnittoIcons.Power, allowVibration) { addDigit(Token.Operator.power) }
|
||||
KeyboardButtonFilled(bModifier, UnittoIcons.Root, allowVibration) { addDigit(Token.Operator.sqrt) }
|
||||
}
|
||||
@ -188,7 +198,9 @@ private fun PreviewConverterKeyboard() {
|
||||
deleteDigit = {},
|
||||
allowVibration = false,
|
||||
fractional = FormatterSymbols.Spaces.fractional,
|
||||
middleZero = false
|
||||
middleZero = false,
|
||||
acButton = true,
|
||||
addBracket = {}
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -88,7 +88,8 @@ private fun PreviewCalculatorSettingsScreen() {
|
||||
middleZero = false,
|
||||
partialHistoryView = true,
|
||||
precision = 3,
|
||||
outputFormat = OutputFormat.PLAIN
|
||||
outputFormat = OutputFormat.PLAIN,
|
||||
acButton = true,
|
||||
),
|
||||
navigateUpAction = {},
|
||||
updatePartialHistoryView = {}
|
||||
|
@ -147,6 +147,7 @@ private fun PreviewConverterSettingsScreen() {
|
||||
enableToolsExperiment = false,
|
||||
latestLeftSideUnit = "kilometer",
|
||||
latestRightSideUnit = "mile",
|
||||
acButton = true,
|
||||
),
|
||||
navigateUpAction = {},
|
||||
navigateToUnitsGroup = {},
|
||||
|
@ -62,6 +62,8 @@ import com.sadellie.unitto.core.ui.common.SegmentedButtonsRow
|
||||
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
||||
import com.sadellie.unitto.core.ui.common.UnittoListItem
|
||||
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
|
||||
import com.sadellie.unitto.core.ui.common.key.UnittoIcons
|
||||
import com.sadellie.unitto.core.ui.common.key.unittoicons.Clear
|
||||
import com.sadellie.unitto.feature.settings.components.ColorSelector
|
||||
import com.sadellie.unitto.feature.settings.components.MonetModeSelector
|
||||
import io.github.sadellie.themmo.MonetMode
|
||||
@ -113,6 +115,8 @@ internal fun DisplayRoute(
|
||||
},
|
||||
systemFont = prefs.systemFont,
|
||||
updateSystemFont = viewModel::updateSystemFont,
|
||||
acButton = prefs.acButton,
|
||||
updateAcButton = viewModel::updateAcButton,
|
||||
middleZero = prefs.middleZero,
|
||||
updateMiddleZero = viewModel::updateMiddleZero,
|
||||
navigateToLanguages = navigateToLanguages
|
||||
@ -136,6 +140,8 @@ private fun DisplayScreen(
|
||||
onMonetModeChange: (MonetMode) -> Unit,
|
||||
systemFont: Boolean,
|
||||
updateSystemFont: (Boolean) -> Unit,
|
||||
acButton: Boolean,
|
||||
updateAcButton: (Boolean) -> Unit,
|
||||
middleZero: Boolean,
|
||||
updateMiddleZero: (Boolean) -> Unit,
|
||||
navigateToLanguages: () -> Unit,
|
||||
@ -266,6 +272,15 @@ private fun DisplayScreen(
|
||||
onSwitchChange = updateSystemFont
|
||||
)
|
||||
|
||||
UnittoListItem(
|
||||
icon = UnittoIcons.Clear,
|
||||
iconDescription = stringResource(R.string.settings_middle_zero),
|
||||
headlineText = stringResource(R.string.settings_ac_button),
|
||||
supportingText = stringResource(R.string.settings_ac_button_support),
|
||||
switchState = acButton,
|
||||
onSwitchChange = updateAcButton
|
||||
)
|
||||
|
||||
UnittoListItem(
|
||||
icon = Icons.Default.ExposureZero,
|
||||
iconDescription = stringResource(R.string.settings_middle_zero),
|
||||
@ -304,6 +319,8 @@ private fun Preview() {
|
||||
onMonetModeChange = themmoController::setMonetMode,
|
||||
systemFont = false,
|
||||
updateSystemFont = {},
|
||||
acButton = false,
|
||||
updateAcButton = {},
|
||||
middleZero = false,
|
||||
updateMiddleZero = {},
|
||||
navigateToLanguages = {}
|
||||
|
@ -37,60 +37,48 @@ class DisplayViewModel @Inject constructor(
|
||||
val prefs = userPrefsRepository.displayPrefs
|
||||
.stateIn(viewModelScope, null)
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateThemingMode
|
||||
*/
|
||||
fun updateThemingMode(themingMode: ThemingMode) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateThemingMode(themingMode)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateDynamicTheme
|
||||
*/
|
||||
fun updateDynamicTheme(enabled: Boolean) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateDynamicTheme(enabled)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateAmoledTheme
|
||||
*/
|
||||
fun updateAmoledTheme(enabled: Boolean) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateAmoledTheme(enabled)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateCustomColor
|
||||
*/
|
||||
fun updateCustomColor(color: Color) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateCustomColor(color)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateMonetMode
|
||||
*/
|
||||
fun updateMonetMode(monetMode: MonetMode) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateMonetMode(monetMode)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateSystemFont
|
||||
*/
|
||||
fun updateSystemFont(enabled: Boolean) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateSystemFont(enabled)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateAcButton(enabled: Boolean) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateAcButton(enabled)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateMiddleZero(enabled: Boolean) = viewModelScope.launch {
|
||||
userPrefsRepository.updateMiddleZero(enabled)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user