diff --git a/app/src/main/java/com/sadellie/unitto/App.kt b/app/src/main/java/com/sadellie/unitto/App.kt index c6762e63..3b8cf1b0 100644 --- a/app/src/main/java/com/sadellie/unitto/App.kt +++ b/app/src/main/java/com/sadellie/unitto/App.kt @@ -112,7 +112,6 @@ internal fun ComponentActivity.App(prefs: AppPreferences?) { navController = navController, themmoController = it, startDestination = prefs.startingScreen, - rpnMode = prefs.rpnMode, openDrawer = { drawerScope.launch { drawerState.open() } } ) } diff --git a/app/src/main/java/com/sadellie/unitto/UnittoNavigation.kt b/app/src/main/java/com/sadellie/unitto/UnittoNavigation.kt index a6bae2ec..43be9a39 100644 --- a/app/src/main/java/com/sadellie/unitto/UnittoNavigation.kt +++ b/app/src/main/java/com/sadellie/unitto/UnittoNavigation.kt @@ -42,7 +42,6 @@ internal fun UnittoNavigation( themmoController: ThemmoController, startDestination: String, openDrawer: () -> Unit, - rpnMode: Boolean, ) { NavHost( navController = navController, @@ -65,7 +64,6 @@ internal fun UnittoNavigation( calculatorGraph( openDrawer = openDrawer, - rpnMode = rpnMode, navigateToSettings = navController::navigateToSettings ) diff --git a/data/evaluatto/src/main/java/io/github/sadellie/evaluatto/RPNCalculation.kt b/data/evaluatto/src/main/java/io/github/sadellie/evaluatto/RPNCalculation.kt deleted file mode 100644 index ea6603cc..00000000 --- a/data/evaluatto/src/main/java/io/github/sadellie/evaluatto/RPNCalculation.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Unitto is a calculator for Android - * Copyright (c) 2023-2024 Elshan Agaev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package io.github.sadellie.evaluatto - -sealed class RPNCalculation { - data object Negate : RPNCalculation() - - data object Clear : RPNCalculation() - data object Enter : RPNCalculation() - data object RotateUp : RPNCalculation() - data object RotateDown : RPNCalculation() - data object Swap : RPNCalculation() - data object Pop : RPNCalculation() - - data object Plus : RPNCalculation() - data object Minus : RPNCalculation() - data object Multiply : RPNCalculation() - data object Divide : RPNCalculation() - data object Percent : RPNCalculation() - data object Power : RPNCalculation() // unused -} diff --git a/data/evaluatto/src/main/java/io/github/sadellie/evaluatto/RPNEngine.kt b/data/evaluatto/src/main/java/io/github/sadellie/evaluatto/RPNEngine.kt deleted file mode 100644 index 40f531eb..00000000 --- a/data/evaluatto/src/main/java/io/github/sadellie/evaluatto/RPNEngine.kt +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Unitto is a calculator for Android - * Copyright (c) 2023-2024 Elshan Agaev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package io.github.sadellie.evaluatto - -import com.sadellie.unitto.core.base.MAX_PRECISION -import java.math.BigDecimal -import java.math.RoundingMode - -sealed class RPNResult { - - /** - * Both input and stack were changed. - * - * @property input New input. Empty when `null`. - * @property stack New stack. - */ - data class Result( - val input: BigDecimal?, - val stack: List, - ) : RPNResult() - - /** - * Only input has been changed. - * - * @property input New input. - */ - data class NewInput( - val input: BigDecimal, - ) : RPNResult() - - /** - * Only stack has been changed. - * - * @property stack New stack. - */ - data class NewStack( - val stack: List, - ) : RPNResult() - - /** - * Something is wrong. Input/stack is empty or there ane not enough stack objects. - */ - data object BadInput : RPNResult() - - /** - * Dividing by zero, duh - */ - data object DivideByZero : RPNResult() -} - -// vroom vroom mfs -// overdose on early returns -fun RPNCalculation.perform( - input: String, - stack: List, -): RPNResult { - when (this) { - RPNCalculation.Clear -> { - return RPNResult.Result(null, emptyList()) - } - - RPNCalculation.Enter -> { - val inputBD = input.toBigDecimalOrNull() ?: return RPNResult.BadInput - return RPNResult.Result(null, stack + inputBD) - } - - RPNCalculation.Negate -> { - val inputBD = input.toBigDecimalOrNull() ?: return RPNResult.BadInput - val result = inputBD.negate() - return RPNResult.NewInput(result) - } - - RPNCalculation.RotateUp -> { - if (stack.size < 2) return RPNResult.BadInput - return RPNResult.NewStack(stack.rotateUp()) - } - - RPNCalculation.RotateDown -> { - if (stack.size < 2) return RPNResult.BadInput - return RPNResult.NewStack(stack.rotateDown()) - } - - RPNCalculation.Swap -> { - if (stack.isEmpty()) return RPNResult.BadInput - if (input.isEmpty()) { - // Swap last 2 in stack - if (stack.size < 2) return RPNResult.BadInput - return RPNResult.NewStack(stack.swapLastTwo()) - } - - // Swap last and input - val (lastFromStack, inputBD) = operands(stack, input) ?: return RPNResult.BadInput - return RPNResult.Result(lastFromStack, stack.dropLast(1) + inputBD) - } - - RPNCalculation.Pop -> { - val lastStacked = stack.lastOrNull() ?: return RPNResult.BadInput - return RPNResult.Result(lastStacked, stack.dropLast(1)) - } - - RPNCalculation.Plus -> { - val (lastFromStack, inputBD) = operands(stack, input) ?: return RPNResult.BadInput - val result = lastFromStack.plus(inputBD) - return RPNResult.Result(result, stack.dropLast(1)) - } - - RPNCalculation.Minus -> { - val (lastFromStack, inputBD) = operands(stack, input) ?: return RPNResult.BadInput - val result = lastFromStack.minus(inputBD) - return RPNResult.Result(result, stack.dropLast(1)) - } - - RPNCalculation.Multiply -> { - val (lastFromStack, inputBD) = operands(stack, input) ?: return RPNResult.BadInput - val result = lastFromStack.multiply(inputBD) - return RPNResult.Result(result, stack.dropLast(1)) - } - - RPNCalculation.Divide -> { - val (lastFromStack, inputBD) = operands(stack, input) ?: return RPNResult.BadInput - if (inputBD.compareTo(BigDecimal.ZERO) == 0) return RPNResult.DivideByZero - - val result = lastFromStack.divide(inputBD, MAX_PRECISION, RoundingMode.HALF_EVEN) - return RPNResult.Result(result, stack.dropLast(1)) - } - - RPNCalculation.Percent -> { - val (lastFromStack, inputBD) = operands(stack, input) ?: return RPNResult.BadInput - // 100 * 24 / 100 = - val result = lastFromStack - .multiply(inputBD) - .divide(bigDecimalHundred, MAX_PRECISION, RoundingMode.HALF_EVEN) - return RPNResult.Result(result, stack.dropLast(1)) - } - - RPNCalculation.Power -> { - val (lastFromStack, inputBD) = operands(stack, input) ?: return RPNResult.BadInput - val result = lastFromStack.pow(inputBD) - return RPNResult.Result(result, stack.dropLast(1)) - } - } -} - -private val bigDecimalHundred by lazy { BigDecimal("100") } - -private fun operands( - stack: List, - input: String, -): Pair? { - val first = stack.lastOrNull() ?: return null - val second = input.toBigDecimalOrNull() ?: return null - - return first to second -} - -private fun List.swapLastTwo(): List { - if (size < 2) return this - return this - .dropLast(2) - .plus(get(lastIndex)) - .plus(get(lastIndex - 1)) -} - -private fun List.rotateUp(): List { - if (size < 2) return this - return this - .drop(1) - .plus(first()) -} - -private fun List.rotateDown(): List { - if (size < 2) return this - return listOf(last()) - .plus(this.dropLast(1)) -} diff --git a/data/evaluatto/src/test/java/io/github/sadellie/evaluatto/RPNEngineKtTest.kt b/data/evaluatto/src/test/java/io/github/sadellie/evaluatto/RPNEngineKtTest.kt deleted file mode 100644 index 7d3a2e60..00000000 --- a/data/evaluatto/src/test/java/io/github/sadellie/evaluatto/RPNEngineKtTest.kt +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Unitto is a calculator for Android - * Copyright (c) 2023-2024 Elshan Agaev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package io.github.sadellie.evaluatto - -import com.sadellie.unitto.core.base.MAX_PRECISION -import org.junit.Assert.assertEquals -import org.junit.Test -import java.math.BigDecimal - -class RPNEngineKtTest { - - @Test - fun testBadOperands() { - // no funny business if input and/or stack is empty - val actual = RPNCalculation.Divide.perform( - input = "", - stack = emptyList() - ) - - assertEquals(RPNResult.BadInput, actual) - } - - @Test - fun testDivide() { - val actual = RPNCalculation.Divide.perform( - input = "2", - stack = listOf(BigDecimal("5")) - ) - - if (actual !is RPNResult.Result) throw Exception("Wrong return") - - assertEquals(BigDecimal("2.5").setScale(MAX_PRECISION), actual.input) - assertEquals(emptyList(), actual.stack) - } - - @Test - fun testDivideByZero() { - val actual = RPNCalculation.Divide.perform( - input = "0", - stack = listOf(BigDecimal("5")) - ) - - assertEquals(RPNResult.DivideByZero, actual) - } - - @Test - fun testMinus() { - val actual = RPNCalculation.Minus.perform( - input = "2", - stack = listOf(BigDecimal("5")) - ) - - if (actual !is RPNResult.Result) throw Exception("Wrong return") - - assertEquals(BigDecimal("3"), actual.input) - assertEquals(emptyList(), actual.stack) - } - - @Test - fun testMultiply() { - val actual = RPNCalculation.Multiply.perform( - input = "2", - stack = listOf(BigDecimal("5")) - ) - - if (actual !is RPNResult.Result) throw Exception("Wrong return") - - assertEquals(BigDecimal("10"), actual.input) - assertEquals(emptyList(), actual.stack) - } - - @Test - fun testNegate() { - val actual = RPNCalculation.Negate.perform( - input = "2", - stack = listOf(BigDecimal("5")) - ) - - if (actual !is RPNResult.NewInput) throw Exception("Wrong return") - - assertEquals(BigDecimal("-2"), actual.input) - } - - @Test - fun testPercent() { - val actual = RPNCalculation.Percent.perform( - input = "150", - stack = listOf(BigDecimal("69")) - ) - - if (actual !is RPNResult.Result) throw Exception("Wrong return") - - assertEquals(BigDecimal("103.5").setScale(MAX_PRECISION), actual.input) - assertEquals(emptyList(), actual.stack) - } - - @Test - fun testPlus() { - val actual = RPNCalculation.Plus.perform( - input = "150", - stack = listOf(BigDecimal("69")) - ) - - if (actual !is RPNResult.Result) throw Exception("Wrong return") - - assertEquals(BigDecimal("219"), actual.input) - assertEquals(emptyList(), actual.stack) - } - - @Test - fun testPower() { - val actual = RPNCalculation.Power.perform( - input = "3", - stack = listOf(BigDecimal("2")) - ) - - if (actual !is RPNResult.Result) throw Exception("Wrong return") - - assertEquals(BigDecimal("8"), actual.input) - assertEquals(emptyList(), actual.stack) - } - - @Test - fun testRotateUp() { - val actual = RPNCalculation.RotateUp.perform( - input = "", - stack = listOf(BigDecimal("1"), BigDecimal("2"), BigDecimal("3")) - ) - - if (actual !is RPNResult.NewStack) throw Exception("Wrong return") - - assertEquals(listOf(BigDecimal("2"), BigDecimal("3"), BigDecimal("1")), actual.stack) - } - - @Test - fun testRotateDown() { - val actual = RPNCalculation.RotateDown.perform( - input = "", - stack = listOf(BigDecimal("1"), BigDecimal("2"), BigDecimal("3")) - ) - - if (actual !is RPNResult.NewStack) throw Exception("Wrong return") - - assertEquals(listOf(BigDecimal("3"), BigDecimal("1"), BigDecimal("2")), actual.stack) - } - - @Test - fun testPop() { - val actual = RPNCalculation.Pop.perform( - input = "", - stack = listOf(BigDecimal("1"), BigDecimal("2"), BigDecimal("3")) - ) - - if (actual !is RPNResult.Result) throw Exception("Wrong return") - - assertEquals(BigDecimal("3"), actual.input) - assertEquals(listOf(BigDecimal("1"), BigDecimal("2")), actual.stack) - } - - @Test - fun testClear() { - val actual = RPNCalculation.Clear.perform( - input = "3", - stack = listOf(BigDecimal("2")) - ) - - if (actual !is RPNResult.Result) throw Exception("Wrong return") - - assertEquals(null, actual.input) - assertEquals(emptyList(), actual.stack) - } - - @Test - fun testEnter() { - val actual = RPNCalculation.Enter.perform( - input = "3", - stack = listOf(BigDecimal("2")) - ) - - if (actual !is RPNResult.Result) throw Exception("Wrong return") - - assertEquals(null, actual.input) - assertEquals(listOf(BigDecimal("2"), BigDecimal("3")), actual.stack) - } - - @Test - fun testSwap() { - val actual = RPNCalculation.Swap.perform( - input = "3", - stack = listOf(BigDecimal("2")) - ) - - if (actual !is RPNResult.Result) throw Exception("Wrong return") - - assertEquals(BigDecimal("2"), actual.input) - assertEquals(listOf(BigDecimal("3")), actual.stack) - } - - @Test - fun testSwapEmptyInput() { - val actual = RPNCalculation.Swap.perform( - input = "", - stack = listOf(BigDecimal("1"), BigDecimal("2")) - ) - - if (actual !is RPNResult.NewStack) throw Exception("Wrong return") - - assertEquals(listOf(BigDecimal("2"), BigDecimal("1")), actual.stack) - } - - @Test - fun testSwapEmptyInputNotEnoughInStack() { - val actual = RPNCalculation.Swap.perform( - input = "", - stack = listOf(BigDecimal("1")) - ) - - assertEquals(RPNResult.BadInput, actual) - } - - @Test - fun testSwapEmptyStack() { - val actual = RPNCalculation.Swap.perform( - input = "123", - stack = emptyList() - ) - - assertEquals(RPNResult.BadInput, actual) - } - - @Test - fun testSwapEmptyBoth() { - val actual = RPNCalculation.Swap.perform( - input = "", - stack = emptyList() - ) - - assertEquals(RPNResult.BadInput, actual) - } -} diff --git a/data/model/src/main/java/com/sadellie/unitto/data/model/repository/UserPreferencesRepository.kt b/data/model/src/main/java/com/sadellie/unitto/data/model/repository/UserPreferencesRepository.kt index 36c65d62..b8d3d74b 100644 --- a/data/model/src/main/java/com/sadellie/unitto/data/model/repository/UserPreferencesRepository.kt +++ b/data/model/src/main/java/com/sadellie/unitto/data/model/repository/UserPreferencesRepository.kt @@ -92,6 +92,4 @@ interface UserPreferencesRepository { suspend fun updatePartialHistoryView(enabled: Boolean) suspend fun updateAcButton(enabled: Boolean) - - suspend fun updateRpnMode(enabled: Boolean) } diff --git a/data/model/src/main/java/com/sadellie/unitto/data/model/userprefs/AppPreferences.kt b/data/model/src/main/java/com/sadellie/unitto/data/model/userprefs/AppPreferences.kt index 7de30184..00004d5b 100644 --- a/data/model/src/main/java/com/sadellie/unitto/data/model/userprefs/AppPreferences.kt +++ b/data/model/src/main/java/com/sadellie/unitto/data/model/userprefs/AppPreferences.kt @@ -30,6 +30,5 @@ interface AppPreferences { val startingScreen: String val enableToolsExperiment: Boolean val systemFont: Boolean - val rpnMode: Boolean val enableVibrations: Boolean } diff --git a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/PreferenceExt.kt b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/PreferenceExt.kt index c0e6336a..cb394150 100644 --- a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/PreferenceExt.kt +++ b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/PreferenceExt.kt @@ -134,10 +134,6 @@ fun Preferences.getAcButton(): Boolean { return this[PrefsKeys.AC_BUTTON] ?: true } -fun Preferences.getRpnMode(): Boolean { - return this[PrefsKeys.RPN_MODE] ?: false -} - private inline fun T.letTryOrNull(block: (T) -> R): R? = try { this?.let(block) } catch (e: Exception) { diff --git a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/PreferenceModels.kt b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/PreferenceModels.kt index 2a60d1d9..d9b09e13 100644 --- a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/PreferenceModels.kt +++ b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/PreferenceModels.kt @@ -44,7 +44,6 @@ data class AppPreferencesImpl( override val startingScreen: String, override val enableToolsExperiment: Boolean, override val systemFont: Boolean, - override val rpnMode: Boolean, override val enableVibrations: Boolean, ) : AppPreferences diff --git a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/PrefsKeys.kt b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/PrefsKeys.kt index c3c23cb1..0c65ccce 100644 --- a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/PrefsKeys.kt +++ b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/PrefsKeys.kt @@ -37,7 +37,7 @@ object PrefsKeys { val ENABLE_VIBRATIONS = booleanPreferencesKey("ENABLE_VIBRATIONS_PREF_KEY") val MIDDLE_ZERO = booleanPreferencesKey("MIDDLE_ZERO_PREF_KEY") val AC_BUTTON = booleanPreferencesKey("AC_BUTTON_PREF_KEY") - val RPN_MODE = booleanPreferencesKey("RPN_MODE_PREF_KEY") + // val RPN_MODE = booleanPreferencesKey("RPN_MODE_PREF_KEY") // FORMATTER val DIGITS_PRECISION = intPreferencesKey("DIGITS_PRECISION_PREF_KEY") diff --git a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt index 57d3e616..92213e0e 100644 --- a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt +++ b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt @@ -62,7 +62,6 @@ class UserPreferencesRepositoryImpl @Inject constructor( startingScreen = preferences.getStartingScreen(), enableToolsExperiment = preferences.getEnableToolsExperiment(), systemFont = preferences.getSystemFont(), - rpnMode = preferences.getRpnMode(), enableVibrations = preferences.getEnableVibrations(), ) } @@ -291,10 +290,4 @@ class UserPreferencesRepositoryImpl @Inject constructor( preferences[PrefsKeys.AC_BUTTON] = enabled } } - - override suspend fun updateRpnMode(enabled: Boolean) { - dataStore.edit { preferences -> - preferences[PrefsKeys.RPN_MODE] = enabled - } - } } diff --git a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/InputBox.kt b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/InputBox.kt deleted file mode 100644 index a8b84558..00000000 --- a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/InputBox.kt +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Unitto is a calculator for Android - * Copyright (c) 2023-2024 Elshan Agaev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sadellie.unitto.feature.calculator - -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.MaterialTheme -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.text.TextRange -import androidx.compose.ui.text.input.TextFieldValue -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.sadellie.unitto.core.base.OutputFormat -import com.sadellie.unitto.core.ui.common.textfield.ExpressionTextField -import com.sadellie.unitto.core.ui.common.textfield.FixedInputTextField -import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols -import com.sadellie.unitto.data.common.format -import java.math.BigDecimal - -@Composable -internal fun InputBox( - modifier: Modifier, - input: TextFieldValue, - onCursorChange: (TextRange) -> Unit, - stack: List, - formatterSymbols: FormatterSymbols, - precision: Int, - outputFormat: Int, -) { - val listState = rememberLazyListState() - - LaunchedEffect(stack) { - listState.animateScrollToItem(stack.lastIndex.coerceAtLeast(0)) - } - - Column( - modifier = modifier - .clip(RoundedCornerShape(24.dp)) - .fillMaxWidth() - .background(MaterialTheme.colorScheme.surfaceVariant) - .padding(start = 12.dp, end = 12.dp, bottom = 12.dp), - verticalArrangement = Arrangement.Bottom - ) { - LazyColumn( - modifier = Modifier.weight(1f), - state = listState, - verticalArrangement = Arrangement.Bottom, - ) { - items(stack) { - FixedInputTextField( - modifier = Modifier.fillMaxWidth(), - value = it.format(precision, outputFormat), - formatterSymbols = formatterSymbols, - textColor = MaterialTheme.colorScheme.onSurfaceVariant, - onClick = {} - ) - } - } - - ExpressionTextField( - modifier = Modifier - .fillMaxWidth() - .fillMaxHeight(0.25f), - value = input, - minRatio = 0.6f, - onCursorChange = onCursorChange, - formatterSymbols = formatterSymbols, - textColor = MaterialTheme.colorScheme.onSurfaceVariant - ) - } -} - -@Preview(device = "spec:width=1080px,height=2160px,dpi=440") -@Composable -fun PreviewInputBox() { - InputBox( - modifier = Modifier.fillMaxSize(), - input = TextFieldValue("123456.789"), - onCursorChange = {}, - stack = listOf( - BigDecimal("123456.7890"), - BigDecimal("123456.7890"), - BigDecimal("123456.7890"), - BigDecimal("123456.7890"), - BigDecimal("123456.7890"), - BigDecimal("123456.7890"), - ), - formatterSymbols = FormatterSymbols.Spaces, - precision = 3, - outputFormat = OutputFormat.PLAIN - ) -} diff --git a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/RPNCalculatorKeyboard.kt b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/RPNCalculatorKeyboard.kt deleted file mode 100644 index f38788ab..00000000 --- a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/RPNCalculatorKeyboard.kt +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Unitto is a calculator for Android - * Copyright (c) 2023-2024 Elshan Agaev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sadellie.unitto.feature.calculator - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.tooling.preview.Preview -import com.sadellie.unitto.core.base.Token -import com.sadellie.unitto.core.ui.LocalWindowSize -import com.sadellie.unitto.core.ui.WindowHeightSizeClass -import com.sadellie.unitto.core.ui.common.KeyboardButtonAdditional -import com.sadellie.unitto.core.ui.common.KeyboardButtonContentHeightShort -import com.sadellie.unitto.core.ui.common.KeyboardButtonContentHeightTall -import com.sadellie.unitto.core.ui.common.KeyboardButtonContentHeightTallAdditional -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.KeypadFlow -import com.sadellie.unitto.core.ui.common.icons.IconPack -import com.sadellie.unitto.core.ui.common.icons.iconpack.Backspace -import com.sadellie.unitto.core.ui.common.icons.iconpack.Clear -import com.sadellie.unitto.core.ui.common.icons.iconpack.Comma -import com.sadellie.unitto.core.ui.common.icons.iconpack.Divide -import com.sadellie.unitto.core.ui.common.icons.iconpack.Dot -import com.sadellie.unitto.core.ui.common.icons.iconpack.Down -import com.sadellie.unitto.core.ui.common.icons.iconpack.Enter -import com.sadellie.unitto.core.ui.common.icons.iconpack.Key0 -import com.sadellie.unitto.core.ui.common.icons.iconpack.Key1 -import com.sadellie.unitto.core.ui.common.icons.iconpack.Key2 -import com.sadellie.unitto.core.ui.common.icons.iconpack.Key3 -import com.sadellie.unitto.core.ui.common.icons.iconpack.Key4 -import com.sadellie.unitto.core.ui.common.icons.iconpack.Key5 -import com.sadellie.unitto.core.ui.common.icons.iconpack.Key6 -import com.sadellie.unitto.core.ui.common.icons.iconpack.Key7 -import com.sadellie.unitto.core.ui.common.icons.iconpack.Key8 -import com.sadellie.unitto.core.ui.common.icons.iconpack.Key9 -import com.sadellie.unitto.core.ui.common.icons.iconpack.Minus -import com.sadellie.unitto.core.ui.common.icons.iconpack.Multiply -import com.sadellie.unitto.core.ui.common.icons.iconpack.Percent -import com.sadellie.unitto.core.ui.common.icons.iconpack.Plus -import com.sadellie.unitto.core.ui.common.icons.iconpack.Pop -import com.sadellie.unitto.core.ui.common.icons.iconpack.Swap -import com.sadellie.unitto.core.ui.common.icons.iconpack.Unary -import com.sadellie.unitto.core.ui.common.icons.iconpack.Up -import io.github.sadellie.evaluatto.RPNCalculation - -@Composable -internal fun RPNCalculatorKeyboard( - modifier: Modifier, - fractional: String, - middleZero: Boolean, - onCalculationClick: (RPNCalculation) -> Unit, - onInputEditClick: (RPNInputEdit) -> Unit, -) { - val fractionalIcon = remember(fractional) { if (fractional == Token.Digit.dot) IconPack.Dot else IconPack.Comma } - - if (LocalWindowSize.current.heightSizeClass < WindowHeightSizeClass.Medium) { - RPNCalculatorKeyboardLandscape( - modifier = modifier, - fractionalIcon = fractionalIcon, - middleZero = middleZero, - onCalculationClick = onCalculationClick, - onInputEditClick = onInputEditClick - ) - } else { - RPNCalculatorKeyboardPortrait( - modifier = modifier, - fractionalIcon = fractionalIcon, - middleZero = middleZero, - onCalculationClick = onCalculationClick, - onInputEditClick = onInputEditClick - ) - } -} - -@Composable -private fun RPNCalculatorKeyboardPortrait( - modifier: Modifier, - fractionalIcon: ImageVector, - middleZero: Boolean, - onCalculationClick: (RPNCalculation) -> Unit, - onInputEditClick: (RPNInputEdit) -> Unit, -) { - Column( - modifier = modifier - ) { - KeypadFlow( - modifier = Modifier.fillMaxHeight(0.1f).fillMaxWidth(), - rows = 1, - columns = 4 - ) { width, height -> - val aModifier = Modifier - .fillMaxWidth(width) - .fillMaxHeight(height) - - KeyboardButtonAdditional(aModifier, IconPack.Swap, null, KeyboardButtonContentHeightTallAdditional) { onCalculationClick(RPNCalculation.Swap) } - KeyboardButtonAdditional(aModifier, IconPack.Up, null, KeyboardButtonContentHeightTallAdditional) { onCalculationClick(RPNCalculation.RotateUp) } - KeyboardButtonAdditional(aModifier, IconPack.Down, null, KeyboardButtonContentHeightTallAdditional) { onCalculationClick(RPNCalculation.RotateDown) } - KeyboardButtonAdditional(aModifier, IconPack.Pop, null, KeyboardButtonContentHeightTallAdditional) { onCalculationClick(RPNCalculation.Pop) } - } - - KeypadFlow( - modifier = Modifier.weight(1f).fillMaxSize(), - rows = 5, - columns = 4 - ) { width, height -> - val bModifier = Modifier - .fillMaxWidth(width) - .fillMaxHeight(height) - - KeyboardButtonTertiary(bModifier, IconPack.Clear, null, KeyboardButtonContentHeightTall) { onCalculationClick(RPNCalculation.Clear) } - KeyboardButtonFilled(bModifier, IconPack.Unary, null, KeyboardButtonContentHeightTall) { onCalculationClick(RPNCalculation.Negate) } - KeyboardButtonFilled(bModifier, IconPack.Percent, null, KeyboardButtonContentHeightTall) { onCalculationClick(RPNCalculation.Percent) } - KeyboardButtonFilled(bModifier, IconPack.Divide, null, KeyboardButtonContentHeightTall) { onCalculationClick(RPNCalculation.Divide) } - - KeyboardButtonLight(bModifier, IconPack.Key7, null, KeyboardButtonContentHeightTall) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._7)) } - KeyboardButtonLight(bModifier, IconPack.Key8, null, KeyboardButtonContentHeightTall) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._8)) } - KeyboardButtonLight(bModifier, IconPack.Key9, null, KeyboardButtonContentHeightTall) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._9)) } - KeyboardButtonFilled(bModifier, IconPack.Multiply, null, KeyboardButtonContentHeightTall) { onCalculationClick(RPNCalculation.Multiply) } - - KeyboardButtonLight(bModifier, IconPack.Key4, null, KeyboardButtonContentHeightTall) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._4)) } - KeyboardButtonLight(bModifier, IconPack.Key5, null, KeyboardButtonContentHeightTall) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._5)) } - KeyboardButtonLight(bModifier, IconPack.Key6, null, KeyboardButtonContentHeightTall) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._6)) } - KeyboardButtonFilled(bModifier, IconPack.Minus, null, KeyboardButtonContentHeightTall) { onCalculationClick(RPNCalculation.Minus) } - - KeyboardButtonLight(bModifier, IconPack.Key1, null, KeyboardButtonContentHeightTall) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._1)) } - KeyboardButtonLight(bModifier, IconPack.Key2, null, KeyboardButtonContentHeightTall) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._2)) } - KeyboardButtonLight(bModifier, IconPack.Key3, null, KeyboardButtonContentHeightTall) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._3)) } - KeyboardButtonFilled(bModifier, IconPack.Plus, null, KeyboardButtonContentHeightTall) { onCalculationClick(RPNCalculation.Plus) } - - if (middleZero) { - KeyboardButtonLight(bModifier, fractionalIcon, null, KeyboardButtonContentHeightTall) { onInputEditClick(RPNInputEdit.Dot) } - KeyboardButtonLight(bModifier, IconPack.Key0, null, KeyboardButtonContentHeightTall) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._0)) } - } else { - KeyboardButtonLight(bModifier, IconPack.Key0, null, KeyboardButtonContentHeightTall) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._0)) } - KeyboardButtonLight(bModifier, fractionalIcon, null, KeyboardButtonContentHeightTall) { onInputEditClick(RPNInputEdit.Dot) } - } - KeyboardButtonLight(bModifier, IconPack.Backspace, null, KeyboardButtonContentHeightTall) { onInputEditClick(RPNInputEdit.Delete) } - KeyboardButtonFilled(bModifier, IconPack.Enter, null, KeyboardButtonContentHeightTall) { onCalculationClick(RPNCalculation.Enter) } - } - } -} - -@Composable -private fun RPNCalculatorKeyboardLandscape( - modifier: Modifier, - fractionalIcon: ImageVector, - middleZero: Boolean, - onCalculationClick: (RPNCalculation) -> Unit, - onInputEditClick: (RPNInputEdit) -> Unit, -) { - KeypadFlow( - modifier = modifier, - rows = 4, - columns = 6 - ) { width, height -> - val bModifier = Modifier - .fillMaxHeight(height) - .fillMaxWidth(width) - - KeyboardButtonAdditional(bModifier, IconPack.Swap, null, KeyboardButtonContentHeightTallAdditional) { onCalculationClick(RPNCalculation.Swap) } - KeyboardButtonLight(bModifier, IconPack.Key7, null, KeyboardButtonContentHeightShort) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._7)) } - KeyboardButtonLight(bModifier, IconPack.Key8, null, KeyboardButtonContentHeightShort) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._8)) } - KeyboardButtonLight(bModifier, IconPack.Key9, null, KeyboardButtonContentHeightShort) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._9)) } - KeyboardButtonTertiary(bModifier, IconPack.Clear, null, KeyboardButtonContentHeightTall) { onCalculationClick(RPNCalculation.Clear) } - KeyboardButtonFilled(bModifier, IconPack.Unary, null, KeyboardButtonContentHeightShort) { onCalculationClick(RPNCalculation.Negate) } - - KeyboardButtonAdditional(bModifier, IconPack.Up, null, KeyboardButtonContentHeightTallAdditional) { onCalculationClick(RPNCalculation.RotateUp) } - KeyboardButtonLight(bModifier, IconPack.Key4, null, KeyboardButtonContentHeightShort) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._4)) } - KeyboardButtonLight(bModifier, IconPack.Key5, null, KeyboardButtonContentHeightShort) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._5)) } - KeyboardButtonLight(bModifier, IconPack.Key6, null, KeyboardButtonContentHeightShort) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._6)) } - KeyboardButtonFilled(bModifier, IconPack.Multiply, null, KeyboardButtonContentHeightShort) { onCalculationClick(RPNCalculation.Multiply) } - KeyboardButtonFilled(bModifier, IconPack.Divide, null, KeyboardButtonContentHeightShort) { onCalculationClick(RPNCalculation.Divide) } - - KeyboardButtonAdditional(bModifier, IconPack.Down, null, KeyboardButtonContentHeightTallAdditional) { onCalculationClick(RPNCalculation.RotateDown) } - KeyboardButtonLight(bModifier, IconPack.Key1, null, KeyboardButtonContentHeightShort) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._1)) } - KeyboardButtonLight(bModifier, IconPack.Key2, null, KeyboardButtonContentHeightShort) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._2)) } - KeyboardButtonLight(bModifier, IconPack.Key3, null, KeyboardButtonContentHeightShort) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._3)) } - KeyboardButtonFilled(bModifier, IconPack.Plus, null, KeyboardButtonContentHeightShort) { onCalculationClick(RPNCalculation.Plus) } - KeyboardButtonFilled(bModifier, IconPack.Minus, null, KeyboardButtonContentHeightShort) { onCalculationClick(RPNCalculation.Minus) } - - KeyboardButtonAdditional(bModifier, IconPack.Pop, null, KeyboardButtonContentHeightTallAdditional) { onCalculationClick(RPNCalculation.Pop) } - if (middleZero) { - KeyboardButtonLight(bModifier, fractionalIcon, null, KeyboardButtonContentHeightShort) { onInputEditClick(RPNInputEdit.Dot) } - KeyboardButtonLight(bModifier, IconPack.Key0, null, KeyboardButtonContentHeightShort) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._0)) } - } else { - KeyboardButtonLight(bModifier, IconPack.Key0, null, KeyboardButtonContentHeightShort) { onInputEditClick(RPNInputEdit.Digit(Token.Digit._0)) } - KeyboardButtonLight(bModifier, fractionalIcon, null, KeyboardButtonContentHeightShort) { onInputEditClick(RPNInputEdit.Dot) } - } - KeyboardButtonLight(bModifier, IconPack.Backspace, null, KeyboardButtonContentHeightShort) { onInputEditClick(RPNInputEdit.Delete) } - KeyboardButtonFilled(bModifier, IconPack.Percent, null, KeyboardButtonContentHeightShort) { onCalculationClick(RPNCalculation.Percent) } - KeyboardButtonFilled(bModifier, IconPack.Enter, null, KeyboardButtonContentHeightShort) { onCalculationClick(RPNCalculation.Enter) } - } -} - -@Preview(device = "spec:parent=pixel_5,orientation=portrait") -@Preview(device = "spec:parent=pixel_5,orientation=landscape") -@Composable -private fun PreviewKeyboard() { - RPNCalculatorKeyboard( - modifier = Modifier.fillMaxSize(), - fractional = Token.Digit.dot, - middleZero = false, - onCalculationClick = {}, - onInputEditClick = {} - ) -} diff --git a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/RPNCalculatorScreen.kt b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/RPNCalculatorScreen.kt deleted file mode 100644 index 7028b939..00000000 --- a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/RPNCalculatorScreen.kt +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Unitto is a calculator for Android - * Copyright (c) 2023-2024 Elshan Agaev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sadellie.unitto.feature.calculator - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Text -import com.sadellie.unitto.core.ui.WindowHeightSizeClass -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.TextRange -import androidx.compose.ui.text.input.TextFieldValue -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.sadellie.unitto.core.base.OutputFormat -import com.sadellie.unitto.core.base.R -import com.sadellie.unitto.core.ui.LocalWindowSize -import com.sadellie.unitto.core.ui.common.MenuButton -import com.sadellie.unitto.core.ui.common.SettingsButton -import com.sadellie.unitto.core.ui.common.EmptyScreen -import com.sadellie.unitto.core.ui.common.ScaffoldWithTopBar -import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols -import io.github.sadellie.evaluatto.RPNCalculation -import java.math.BigDecimal - -@Composable -internal fun RPNCalculatorRoute( - openDrawer: () -> Unit, - navigateToSettings: () -> Unit, - viewModel: RPNCalculatorViewModel = hiltViewModel(), -) { - when (val uiState = viewModel.uiState.collectAsStateWithLifecycle().value) { - RPNCalculatorUIState.Loading -> EmptyScreen() - is RPNCalculatorUIState.Ready -> RPNCalculatorScreen( - uiState = uiState, - openDrawer = openDrawer, - navigateToSettings = navigateToSettings, - onCursorChange = viewModel::onCursorChange, - onCalculationClick = viewModel::onCalculationClick, - onInputEditClick = viewModel::onInputEdit - ) - } -} - -@Composable -internal fun RPNCalculatorScreen( - uiState: RPNCalculatorUIState.Ready, - openDrawer: () -> Unit, - navigateToSettings: () -> Unit, - onCursorChange: (TextRange) -> Unit, - onCalculationClick: (RPNCalculation) -> Unit, - onInputEditClick: (RPNInputEdit) -> Unit, -) { - ScaffoldWithTopBar( - title = { Text(stringResource(id = R.string.calculator_title)) }, - navigationIcon = { MenuButton(openDrawer) }, - actions = { SettingsButton(navigateToSettings) } - ) { paddingValues -> - Column( - Modifier.padding(paddingValues) - ) { - InputBox( - modifier = Modifier - .padding(8.dp) - .fillMaxHeight(if (LocalWindowSize.current.heightSizeClass > WindowHeightSizeClass.Compact) 0.3f else 0.5f), - input = uiState.input, - stack = uiState.stack, - formatterSymbols = uiState.formatterSymbols, - precision = uiState.precision, - outputFormat = uiState.outputFormat, - onCursorChange = onCursorChange - ) - RPNCalculatorKeyboard( - modifier = Modifier - .padding(horizontal = 4.dp) - .fillMaxSize(), - fractional = uiState.formatterSymbols.fractional, - middleZero = uiState.middleZero, - onCalculationClick = onCalculationClick, - onInputEditClick = onInputEditClick - ) - } - } -} - -@Preview(widthDp = 432, heightDp = 1008, device = "spec:parent=pixel_5,orientation=portrait") -@Preview(widthDp = 432, heightDp = 864, device = "spec:parent=pixel_5,orientation=portrait") -@Preview(widthDp = 597, heightDp = 1393, device = "spec:parent=pixel_5,orientation=portrait") -@Composable -private fun RPNCalculatorScreenPreview() { - RPNCalculatorScreen( - uiState = RPNCalculatorUIState.Ready( - input = TextFieldValue("test"), - stack = listOf( - BigDecimal("123456.7890"), - BigDecimal("123456.7890"), - BigDecimal("123456.7890"), - BigDecimal("123456.7890"), - BigDecimal("123456.7890"), - BigDecimal("123456.7890"), - ), - precision = 3, - outputFormat = OutputFormat.PLAIN, - formatterSymbols = FormatterSymbols.Spaces, - middleZero = true, - ), - openDrawer = {}, - navigateToSettings = {}, - onCalculationClick = {}, - onInputEditClick = {}, - onCursorChange = {} - ) -} diff --git a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/RPNCalculatorUIState.kt b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/RPNCalculatorUIState.kt deleted file mode 100644 index 4db3230d..00000000 --- a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/RPNCalculatorUIState.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Unitto is a calculator for Android - * Copyright (c) 2023-2024 Elshan Agaev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sadellie.unitto.feature.calculator - -import androidx.compose.ui.text.input.TextFieldValue -import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols -import java.math.BigDecimal - -internal sealed class RPNCalculatorUIState { - data object Loading : RPNCalculatorUIState() - - data class Ready( - val input: TextFieldValue, - val stack: List, - val precision: Int, - val outputFormat: Int, - val formatterSymbols: FormatterSymbols, - val middleZero: Boolean, - ) : RPNCalculatorUIState() -} diff --git a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/RPNCalculatorViewModel.kt b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/RPNCalculatorViewModel.kt deleted file mode 100644 index 2de873d3..00000000 --- a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/RPNCalculatorViewModel.kt +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Unitto is a calculator for Android - * Copyright (c) 2023-2024 Elshan Agaev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sadellie.unitto.feature.calculator - -import androidx.compose.ui.text.TextRange -import androidx.compose.ui.text.input.TextFieldValue -import androidx.lifecycle.SavedStateHandle -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.addTokens -import com.sadellie.unitto.core.ui.common.textfield.deleteTokens -import com.sadellie.unitto.core.ui.common.textfield.getTextField -import com.sadellie.unitto.data.common.format -import com.sadellie.unitto.data.common.stateIn -import com.sadellie.unitto.data.model.repository.UserPreferencesRepository -import dagger.hilt.android.lifecycle.HiltViewModel -import io.github.sadellie.evaluatto.RPNCalculation -import io.github.sadellie.evaluatto.RPNResult -import io.github.sadellie.evaluatto.perform -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import java.math.BigDecimal -import javax.inject.Inject - -@HiltViewModel -internal class RPNCalculatorViewModel @Inject constructor( - userPrefsRepository: UserPreferencesRepository, - private val savedStateHandle: SavedStateHandle, -) : ViewModel() { - - private val _inputKey = "RPN_CALCULATOR_INPUT" - private val _input = MutableStateFlow(savedStateHandle.getTextField(_inputKey)) - private val _stack = MutableStateFlow(emptyList()) - private val _prefs = userPrefsRepository.calculatorPrefs.stateIn(viewModelScope, null) - - val uiState = combine( - _prefs, - _input, - _stack - ) { prefs, input, stack -> - prefs ?: return@combine RPNCalculatorUIState.Loading - - return@combine RPNCalculatorUIState.Ready( - input = input, - stack = stack, - precision = prefs.precision, - outputFormat = prefs.outputFormat, - formatterSymbols = AllFormatterSymbols.getById(prefs.separator), - middleZero = prefs.middleZero - ) - } - .stateIn(viewModelScope, RPNCalculatorUIState.Loading) - - fun onInputEdit(action: RPNInputEdit) { - val input = _input.value - val newInput = when (action) { - is RPNInputEdit.Digit -> input.addTokens(action.value) - RPNInputEdit.Dot -> { - if (_input.value.text.contains(Token.Digit.dot)) return - input.addTokens(Token.Digit.dot) - } - RPNInputEdit.Delete -> input.deleteTokens() - } - - _input.update { newInput } - savedStateHandle[_inputKey] = newInput.text - } - - fun onCalculationClick(action: RPNCalculation) = viewModelScope.launch { - val prefs = _prefs.value ?: return@launch - - val newResult = withContext(Dispatchers.Default) { - action.perform(_input.value.text, _stack.value) - } - - when (newResult) { - is RPNResult.Result -> { - val newInput = newResult.input?.format(prefs.precision, prefs.outputFormat) ?: "" - _input.update { TextFieldValue(newInput, TextRange(newInput.length)) } - _stack.update { newResult.stack } - } - - is RPNResult.NewStack -> { - _stack.update { newResult.stack } - } - - is RPNResult.NewInput -> { - val newInput = newResult.input.format(prefs.precision, prefs.outputFormat) - _input.update { TextFieldValue(newInput, TextRange(newInput.length)) } - } - RPNResult.BadInput, RPNResult.DivideByZero -> Unit - } - } - - fun onCursorChange(selection: TextRange) = _input.update { it.copy(selection = selection) } -} diff --git a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/RPNInputEdit.kt b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/RPNInputEdit.kt deleted file mode 100644 index 28a391d9..00000000 --- a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/RPNInputEdit.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Unitto is a calculator for Android - * Copyright (c) 2023-2024 Elshan Agaev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sadellie.unitto.feature.calculator - -sealed class RPNInputEdit { - data class Digit(val value: String) : RPNInputEdit() - data object Delete : RPNInputEdit() - data object Dot : RPNInputEdit() -} diff --git a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/navigation/CalculatorNavigation.kt b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/navigation/CalculatorNavigation.kt index d6f6f262..b3d62764 100644 --- a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/navigation/CalculatorNavigation.kt +++ b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/navigation/CalculatorNavigation.kt @@ -24,13 +24,11 @@ import com.sadellie.unitto.core.ui.model.DrawerItem import com.sadellie.unitto.core.ui.unittoComposable import com.sadellie.unitto.core.ui.unittoNavigation import com.sadellie.unitto.feature.calculator.CalculatorRoute -import com.sadellie.unitto.feature.calculator.RPNCalculatorRoute private val graph = DrawerItem.Calculator.graph private val start = DrawerItem.Calculator.start fun NavGraphBuilder.calculatorGraph( - rpnMode: Boolean, openDrawer: () -> Unit, navigateToSettings: () -> Unit ) { @@ -42,17 +40,10 @@ fun NavGraphBuilder.calculatorGraph( ) ) { unittoComposable(start) { - if (rpnMode) { - RPNCalculatorRoute( - openDrawer = openDrawer, - navigateToSettings = navigateToSettings - ) - } else { - CalculatorRoute( - navigateToMenu = openDrawer, - navigateToSettings = navigateToSettings - ) - } + CalculatorRoute( + navigateToMenu = openDrawer, + navigateToSettings = navigateToSettings + ) } } } diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/calculator/CalculatorSettingsScreen.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/calculator/CalculatorSettingsScreen.kt index ee25cc90..480edaaa 100644 --- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/calculator/CalculatorSettingsScreen.kt +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/calculator/CalculatorSettingsScreen.kt @@ -18,7 +18,6 @@ package com.sadellie.unitto.feature.settings.calculator -import androidx.compose.animation.Crossfade import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons @@ -29,84 +28,51 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.sadellie.unitto.core.base.OutputFormat import com.sadellie.unitto.core.base.R -import com.sadellie.unitto.core.ui.common.NavigateUpButton +import com.sadellie.unitto.core.base.Separator import com.sadellie.unitto.core.ui.common.EmptyScreen import com.sadellie.unitto.core.ui.common.ListItem +import com.sadellie.unitto.core.ui.common.NavigateUpButton import com.sadellie.unitto.core.ui.common.ScaffoldWithLargeTopBar +import com.sadellie.unitto.data.model.userprefs.CalculatorPreferences +import com.sadellie.unitto.data.userprefs.CalculatorPreferencesImpl @Composable internal fun CalculatorSettingsRoute( viewModel: CalculatorSettingsViewModel = hiltViewModel(), navigateUpAction: () -> Unit, ) { - when (val prefs = viewModel.uiState.collectAsStateWithLifecycle().value) { - CalculatorSettingsUIState.Loading -> EmptyScreen() + when (val prefs = viewModel.prefs.collectAsStateWithLifecycle().value) { + null -> EmptyScreen() else -> { CalculatorSettingsScreen( - uiState = prefs, + prefs = prefs, navigateUpAction = navigateUpAction, updatePartialHistoryView = viewModel::updatePartialHistoryView, - updateRpnMode = viewModel::updateRpnMode, ) } } } -// TODO Translate @Composable private fun CalculatorSettingsScreen( - uiState: CalculatorSettingsUIState, + prefs: CalculatorPreferences, navigateUpAction: () -> Unit, updatePartialHistoryView: (Boolean) -> Unit, - updateRpnMode: (Boolean) -> Unit, ) { ScaffoldWithLargeTopBar( title = stringResource(R.string.calculator_title), navigationIcon = { NavigateUpButton(navigateUpAction) } ) { padding -> Column(Modifier.padding(padding)) { -// SingleChoiceSegmentedButtonRow( -// modifier = Modifier -// .fillMaxWidth() -// .padding(16.dp) -// ) { -// SegmentedButton( -// selected = uiState is CalculatorSettingsUIState.Standard, -// onClick = { updateRpnMode(false) }, -// shape = SegmentedButtonDefaults.itemShape(index = 0, count = 2), -// ) { -// Text("Standard") -// } -// SegmentedButton( -// selected = uiState == CalculatorSettingsUIState.RPN, -// onClick = { updateRpnMode(true) }, -// shape = SegmentedButtonDefaults.itemShape(index = 1, count = 2), -// ) { -// Text("RPN") -// } -// } - - Crossfade( - targetState = uiState, - label = "Mode switch" - ) { state -> - when (state) { - is CalculatorSettingsUIState.Standard -> { - Column { - ListItem( - headlineText = stringResource(R.string.settings_partial_history_view), - icon = Icons.Default.Timer, - supportingText = stringResource(R.string.settings_partial_history_view_support), - switchState = state.partialHistoryView, - onSwitchChange = updatePartialHistoryView - ) - } - } - - else -> Unit - } - } + ListItem( + headlineText = stringResource(R.string.settings_partial_history_view), + icon = Icons.Default.Timer, + supportingText = stringResource(R.string.settings_partial_history_view_support), + switchState = prefs.partialHistoryView, + onSwitchChange = updatePartialHistoryView + ) } } } @@ -115,22 +81,16 @@ private fun CalculatorSettingsScreen( @Composable private fun PreviewCalculatorSettingsScreenStandard() { CalculatorSettingsScreen( - uiState = CalculatorSettingsUIState.Standard( - partialHistoryView = true, + prefs = CalculatorPreferencesImpl( + radianMode = true, + separator = Separator.SPACE, + middleZero = false, + acButton = false, + partialHistoryView = false, + precision = 3, + outputFormat = OutputFormat.PLAIN ), navigateUpAction = {}, updatePartialHistoryView = {}, - updateRpnMode = {} - ) -} - -@Preview -@Composable -private fun PreviewCalculatorSettingsScreenRPN() { - CalculatorSettingsScreen( - uiState = CalculatorSettingsUIState.RPN, - navigateUpAction = {}, - updatePartialHistoryView = {}, - updateRpnMode = {} ) } diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/calculator/CalculatorSettingsUIState.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/calculator/CalculatorSettingsUIState.kt deleted file mode 100644 index 899cb51e..00000000 --- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/calculator/CalculatorSettingsUIState.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Unitto is a calculator for Android - * Copyright (c) 2023-2024 Elshan Agaev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sadellie.unitto.feature.settings.calculator - -internal sealed class CalculatorSettingsUIState { - data object Loading : CalculatorSettingsUIState() - - data object RPN : CalculatorSettingsUIState() - - data class Standard( - val partialHistoryView: Boolean, - ) : CalculatorSettingsUIState() -} diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/calculator/CalculatorSettingsViewModel.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/calculator/CalculatorSettingsViewModel.kt index 41b4c69a..eb4e3ff5 100644 --- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/calculator/CalculatorSettingsViewModel.kt +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/calculator/CalculatorSettingsViewModel.kt @@ -23,7 +23,6 @@ import androidx.lifecycle.viewModelScope import com.sadellie.unitto.data.common.stateIn import com.sadellie.unitto.data.model.repository.UserPreferencesRepository import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch import javax.inject.Inject @@ -31,25 +30,10 @@ import javax.inject.Inject internal class CalculatorSettingsViewModel @Inject constructor( private val userPrefsRepository: UserPreferencesRepository, ) : ViewModel() { - val uiState = combine( - userPrefsRepository.appPrefs, - userPrefsRepository.calculatorPrefs, - ) { app, calc -> - if (app.rpnMode) { - CalculatorSettingsUIState.RPN - } else { - CalculatorSettingsUIState.Standard( - partialHistoryView = calc.partialHistoryView, - ) - } - } - .stateIn(viewModelScope, CalculatorSettingsUIState.Loading) + val prefs = userPrefsRepository.calculatorPrefs + .stateIn(viewModelScope, null) fun updatePartialHistoryView(enabled: Boolean) = viewModelScope.launch { userPrefsRepository.updatePartialHistoryView(enabled) } - - fun updateRpnMode(enabled: Boolean) = viewModelScope.launch { - userPrefsRepository.updateRpnMode(enabled) - } }