Refactor FormatterSymbols

closes #90
This commit is contained in:
Sad Ellie 2024-02-12 22:12:07 +03:00
parent 224ddd8bad
commit 263a1139dc
54 changed files with 323 additions and 332 deletions

View File

@ -1,6 +1,6 @@
/*
* Unitto is a calculator for Android
* Copyright (c) 2022-2024 Elshan Agaev
* Copyright (c) 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
@ -19,10 +19,12 @@
package com.sadellie.unitto.core.base
/**
* Separators mean symbols that separate fractional part
* Formatter symbols. Always use [Token].
*
* @property grouping Symbol fpr thousands separator.
* @property fractional Symbol decimal separator.
*/
object Separator {
const val SPACE = 0
const val PERIOD = 1
const val COMMA = 2
}
data class FormatterSymbols(
val grouping: String,
val fractional: String,
)

View File

@ -20,6 +20,10 @@ package com.sadellie.unitto.core.base
@Suppress("ObjectPropertyName")
object Token {
const val SPACE = " "
const val PERIOD = "."
const val COMMA = ","
object Digit {
const val _1 = "1"
const val _2 = "2"

View File

@ -245,6 +245,7 @@ Alternatively you can use "Export" -->
<string name="settings_currency_rates_note_text">Currency rates are updated daily. There\'s no real-time market monitoring in the app</string>
<string name="settings_currency_rates_note_title">Wrong currency rates?</string>
<string name="settings_dark_mode">Dark</string>
<string name="settings_decimal_separator">Decimal separator</string>
<string name="settings_disable_unit_group_description">Disable unit group</string>
<string name="settings_display">Display</string>
<string name="settings_display_support">App look and feel</string>
@ -301,6 +302,7 @@ Maybe this can be labeled better? Let me know. It should be something that can d
<string name="settings_system_font_support">Use system font for texts in app</string>
<string name="settings_terms_and_conditions">Terms and Conditions</string>
<string name="settings_third_party_licenses">Third party licenses</string>
<string name="settings_thousands_separator">Thousands separator</string>
<string name="settings_title">Settings</string>
<string name="settings_translate_app">Translate this app</string>
<string name="settings_translate_app_support">Join POEditor project to help</string>

View File

@ -1,45 +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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.core.base
import org.junit.Assert
import org.junit.Test
class SeparatorTest {
@Test
fun testExists() {
Assert.assertNotNull(Separator)
}
@Test
fun testSeparatorSpace() {
Assert.assertEquals(0, Separator.SPACE)
}
@Test
fun testSeparatorPeriod() {
Assert.assertEquals(1, Separator.PERIOD)
}
@Test
fun testSeparatorComma() {
Assert.assertEquals(2, Separator.COMMA)
}
}

View File

@ -22,6 +22,14 @@ import org.junit.Assert
import org.junit.Test
class TokenTest {
@Test
fun testFormatterSymbols() {
Assert.assertEquals(" ", Token.SPACE)
Assert.assertEquals(".", Token.PERIOD)
Assert.assertEquals(",", Token.COMMA)
}
@Test
fun testDigit() {
Assert.assertEquals("1234567890", Token.Digit.all.joinToString(""))
@ -126,7 +134,7 @@ class TokenTest {
"e",
).joinToString("")
Assert.assertEquals("1234567890.$operator$func$consts", Token.expressionTokens.joinToString(""))
Assert.assertEquals("1234567890.$operator$func${consts}E", Token.expressionTokens.joinToString(""))
}
@Test

View File

@ -21,6 +21,7 @@ package com.sadellie.unitto.core.ui.common.textfield
import android.content.ClipData
import androidx.compose.ui.platform.ClipboardManager
import androidx.compose.ui.text.AnnotatedString
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.base.Token
/**

View File

@ -22,6 +22,7 @@ import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.input.OffsetMapping
import androidx.compose.ui.text.input.TransformedText
import androidx.compose.ui.text.input.VisualTransformation
import com.sadellie.unitto.core.base.FormatterSymbols
class ExpressionTransformer(private val formatterSymbols: FormatterSymbols) : VisualTransformation {

View File

@ -35,6 +35,7 @@ import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextAlign
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.ui.theme.LocalNumberTypography
@Composable

View File

@ -18,6 +18,7 @@
package com.sadellie.unitto.core.ui.common.textfield
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.base.Token
private val numbersRegex by lazy { Regex("[\\d.]+") }

View File

@ -1,46 +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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.core.ui.common.textfield
import com.sadellie.unitto.core.base.Separator
sealed class FormatterSymbols(val grouping: String, val fractional: String) {
data object Spaces : FormatterSymbols(" ", ".")
data object Period : FormatterSymbols(".", ",")
data object Comma : FormatterSymbols(",", ".")
}
object AllFormatterSymbols {
private val allFormatterSymbols by lazy {
hashMapOf(
Separator.SPACE to FormatterSymbols.Spaces,
Separator.PERIOD to FormatterSymbols.Period,
Separator.COMMA to FormatterSymbols.Comma
)
}
/**
* Defaults to [FormatterSymbols.Spaces] if not found.
*
* @see Separator
*/
fun getById(separator: Int): FormatterSymbols {
return allFormatterSymbols.getOrElse(separator) { FormatterSymbols.Spaces }
}
}

View File

@ -44,6 +44,7 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.TextUnit
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.ui.common.autosize.AutoSizeTextStyleBox
import com.sadellie.unitto.core.ui.theme.LocalNumberTypography

View File

@ -18,40 +18,44 @@
package com.sadellie.unitto.core.ui
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.core.ui.common.textfield.clearAndFilterExpression
import org.junit.Assert.assertEquals
import org.junit.Test
class CleanAndFilterExpression {
private val formatterSymbols = FormatterSymbols(Token.COMMA, Token.PERIOD)
@Test
fun noAdditionalSymbols() {
assertEquals("123", "123".clearAndFilterExpression(FormatterSymbols.Comma))
assertEquals("123.456", "123.456".clearAndFilterExpression(FormatterSymbols.Comma))
assertEquals("123", "123".clearAndFilterExpression(formatterSymbols))
assertEquals("123.456", "123.456".clearAndFilterExpression(formatterSymbols))
}
@Test
fun hasFormatterSymbol() {
assertEquals("123456", "123,456".clearAndFilterExpression(FormatterSymbols.Comma))
assertEquals("123456.789", "123,456.789".clearAndFilterExpression(FormatterSymbols.Comma))
assertEquals("123456", "123,456".clearAndFilterExpression(formatterSymbols))
assertEquals("123456.789", "123,456.789".clearAndFilterExpression(formatterSymbols))
}
@Test
fun hasWrongFormatterSymbol() {
assertEquals("123456", "123 456".clearAndFilterExpression(FormatterSymbols.Comma))
assertEquals("123456.789", "123 456.789".clearAndFilterExpression(FormatterSymbols.Comma))
assertEquals("123456", "123 456".clearAndFilterExpression(formatterSymbols))
assertEquals("123456.789", "123 456.789".clearAndFilterExpression(formatterSymbols))
}
@Test
fun fractionExpression() {
assertEquals("1600+1234÷56789", "1,600 123456789".clearAndFilterExpression(FormatterSymbols.Comma))
assertEquals("123456.789+1234÷56789", "123,456.789 123456789".clearAndFilterExpression(FormatterSymbols.Comma))
assertEquals("1600+1234÷56789", "1,600 123456789".clearAndFilterExpression(formatterSymbols))
assertEquals("123456.789+1234÷56789", "123,456.789 123456789".clearAndFilterExpression(formatterSymbols))
}
@Test
fun garbage() {
// 'e' is a known symbol
assertEquals("eeee123", "pee pee poo poo -123".clearAndFilterExpression(FormatterSymbols.Comma))
assertEquals("eeee123.456", "pee pee poo poo -123.456".clearAndFilterExpression(FormatterSymbols.Comma))
assertEquals("eeee123", "pee pee poo poo -123".clearAndFilterExpression(formatterSymbols))
assertEquals("eeee123.456", "pee pee poo poo -123.456".clearAndFilterExpression(formatterSymbols))
}
}

View File

@ -18,14 +18,15 @@
package com.sadellie.unitto.core.ui
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.core.ui.common.textfield.ExpressionTransformer
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import org.junit.Assert.assertEquals
import org.junit.Test
class ExpressionTransformerTest {
private val expr = ExpressionTransformer(FormatterSymbols.Comma)
private val expr = ExpressionTransformer(FormatterSymbols(Token.COMMA, Token.PERIOD))
// Use "|" for cursor
private fun origToTrans(orig: String, trans: String) {

View File

@ -18,7 +18,8 @@
package com.sadellie.unitto.core.ui
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.core.ui.common.textfield.formatExpression
import org.junit.Assert.assertEquals
import org.junit.Test
@ -40,7 +41,7 @@ class FormatterExpressionTest {
@Test
fun setSeparatorSpaces() {
fun String.format(): String = formatExpression(FormatterSymbols.Spaces)
fun String.format(): String = formatExpression(FormatterSymbols(Token.SPACE, Token.PERIOD))
assertEquals("123E+21", ENG_VALUE.format())
assertEquals("123.3E+21", ENG_VALUE_FRACTIONAL.format())
assertEquals("123E+21+(123 456.789)", ENG_VALUE_EXPRESSION.format())
@ -57,7 +58,7 @@ class FormatterExpressionTest {
@Test
fun setSeparatorComma() {
fun String.format(): String = formatExpression(FormatterSymbols.Comma)
fun String.format(): String = formatExpression(FormatterSymbols(Token.COMMA, Token.PERIOD))
assertEquals("123E+21", ENG_VALUE.format())
assertEquals("123.3E+21", ENG_VALUE_FRACTIONAL.format())
assertEquals("123E+21+(123,456.789)", ENG_VALUE_EXPRESSION.format())
@ -74,7 +75,7 @@ class FormatterExpressionTest {
@Test
fun setSeparatorPeriod() {
fun String.format(): String = formatExpression(FormatterSymbols.Period)
fun String.format(): String = formatExpression(FormatterSymbols(Token.PERIOD, Token.COMMA))
assertEquals("123E+21", ENG_VALUE.format())
assertEquals("123,3E+21", ENG_VALUE_FRACTIONAL.format())
assertEquals("123E+21+(123.456,789)", ENG_VALUE_EXPRESSION.format())

View File

@ -51,7 +51,7 @@ interface UserPreferencesRepository {
suspend fun updateDigitsPrecision(precision: Int)
suspend fun updateSeparator(separator: Int)
suspend fun updateFormatterSymbols(grouping: String, fractional: String)
suspend fun updateOutputFormat(outputFormat: Int)

View File

@ -18,6 +18,8 @@
package com.sadellie.unitto.data.model.userprefs
import com.sadellie.unitto.core.base.FormatterSymbols
interface AddSubtractPreferences{
val separator: Int
val formatterSymbols: FormatterSymbols
}

View File

@ -18,6 +18,8 @@
package com.sadellie.unitto.data.model.userprefs
import com.sadellie.unitto.core.base.FormatterSymbols
interface BodyMassPreferences{
val separator: Int
val formatterSymbols: FormatterSymbols
}

View File

@ -18,9 +18,11 @@
package com.sadellie.unitto.data.model.userprefs
import com.sadellie.unitto.core.base.FormatterSymbols
interface CalculatorPreferences {
val radianMode: Boolean
val separator: Int
val formatterSymbols: FormatterSymbols
val middleZero: Boolean
val acButton: Boolean
val partialHistoryView: Boolean

View File

@ -18,11 +18,12 @@
package com.sadellie.unitto.data.model.userprefs
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.UnitsListSorting
interface ConverterPreferences {
val separator: Int
val formatterSymbols: FormatterSymbols
val middleZero: Boolean
val acButton: Boolean
val precision: Int

View File

@ -18,8 +18,10 @@
package com.sadellie.unitto.data.model.userprefs
import com.sadellie.unitto.core.base.FormatterSymbols
interface FormattingPreferences{
val digitsPrecision: Int
val separator: Int
val formatterSymbols: FormatterSymbols
val outputFormat: Int
}

View File

@ -19,8 +19,9 @@
package com.sadellie.unitto.data.userprefs
import androidx.datastore.preferences.core.Preferences
import com.sadellie.unitto.core.base.FormatterSymbols
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.base.TopLevelDestinations
import com.sadellie.unitto.data.converter.UnitID
import com.sadellie.unitto.data.model.UnitGroup
@ -76,8 +77,21 @@ internal fun Preferences.getRadianMode(): Boolean {
return this[PrefsKeys.RADIAN_MODE] ?: true
}
internal fun Preferences.getSeparator(): Int {
return this[PrefsKeys.SEPARATOR] ?: Separator.SPACE
internal fun Preferences.getFormatterSymbols(): FormatterSymbols {
val grouping = this[PrefsKeys.FORMATTER_GROUPING]
val fractional = this[PrefsKeys.FORMATTER_FRACTIONAL]
// Updating from older version or fresh install
// TODO Remove in the future
if ((grouping == null) or (fractional == null)) {
return when(this[PrefsKeys.SEPARATOR] ?: 0) {
0 -> FormatterSymbols(Token.SPACE, Token.PERIOD)
1 -> FormatterSymbols(Token.PERIOD, Token.COMMA)
else -> FormatterSymbols(Token.COMMA, Token.PERIOD)
}
}
return FormatterSymbols(grouping ?: Token.SPACE, fractional ?: Token.PERIOD)
}
internal fun Preferences.getMiddleZero(): Boolean {

View File

@ -18,6 +18,7 @@
package com.sadellie.unitto.data.userprefs
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.data.model.userprefs.AboutPreferences
@ -53,7 +54,7 @@ data class GeneralPreferencesImpl(
data class CalculatorPreferencesImpl(
override val radianMode: Boolean,
override val separator: Int,
override val formatterSymbols: FormatterSymbols,
override val middleZero: Boolean,
override val acButton: Boolean,
override val partialHistoryView: Boolean,
@ -62,7 +63,7 @@ data class CalculatorPreferencesImpl(
) : CalculatorPreferences
data class ConverterPreferencesImpl(
override val separator: Int,
override val formatterSymbols: FormatterSymbols,
override val middleZero: Boolean,
override val acButton: Boolean,
override val precision: Int,
@ -84,7 +85,7 @@ data class DisplayPreferencesImpl(
data class FormattingPreferencesImpl(
override val digitsPrecision: Int,
override val separator: Int,
override val formatterSymbols: FormatterSymbols,
override val outputFormat: Int,
) : FormattingPreferences
@ -93,11 +94,11 @@ data class UnitGroupsPreferencesImpl(
) : UnitGroupsPreferences
data class AddSubtractPreferencesImpl(
override val separator: Int,
override val formatterSymbols: FormatterSymbols,
) : AddSubtractPreferences
data class BodyMassPreferencesImpl(
override val separator: Int,
override val formatterSymbols: FormatterSymbols,
) : BodyMassPreferences
data class AboutPreferencesImpl(

View File

@ -42,6 +42,8 @@ object PrefsKeys {
// FORMATTER
val DIGITS_PRECISION = intPreferencesKey("DIGITS_PRECISION_PREF_KEY")
val SEPARATOR = intPreferencesKey("SEPARATOR_PREF_KEY")
val FORMATTER_GROUPING = stringPreferencesKey("FORMATTER_GROUPING_PREF_KEY")
val FORMATTER_FRACTIONAL = stringPreferencesKey("FORMATTER_FRACTIONAL_PREF_KEY")
val OUTPUT_FORMAT = intPreferencesKey("OUTPUT_FORMAT_PREF_KEY")
// CALCULATOR

View File

@ -78,7 +78,7 @@ class UserPreferencesRepositoryImpl @Inject constructor(
.map { preferences ->
CalculatorPreferencesImpl(
radianMode = preferences.getRadianMode(),
separator = preferences.getSeparator(),
formatterSymbols = preferences.getFormatterSymbols(),
middleZero = preferences.getMiddleZero(),
partialHistoryView = preferences.getPartialHistoryView(),
precision = preferences.getDigitsPrecision(),
@ -90,7 +90,7 @@ class UserPreferencesRepositoryImpl @Inject constructor(
override val converterPrefs: Flow<ConverterPreferences> = data
.map { preferences ->
ConverterPreferencesImpl(
separator = preferences.getSeparator(),
formatterSymbols = preferences.getFormatterSymbols(),
middleZero = preferences.getMiddleZero(),
precision = preferences.getDigitsPrecision(),
outputFormat = preferences.getOutputFormat(),
@ -118,7 +118,7 @@ class UserPreferencesRepositoryImpl @Inject constructor(
.map { preferences ->
FormattingPreferencesImpl(
digitsPrecision = preferences.getDigitsPrecision(),
separator = preferences.getSeparator(),
formatterSymbols = preferences.getFormatterSymbols(),
outputFormat = preferences.getOutputFormat(),
)
}
@ -133,14 +133,14 @@ class UserPreferencesRepositoryImpl @Inject constructor(
override val addSubtractPrefs: Flow<AddSubtractPreferences> = data
.map { preferences ->
AddSubtractPreferencesImpl(
separator = preferences.getSeparator(),
formatterSymbols = preferences.getFormatterSymbols(),
)
}
override val bodyMassPrefs: Flow<BodyMassPreferences> = data
.map { preferences ->
BodyMassPreferencesImpl(
separator = preferences.getSeparator(),
formatterSymbols = preferences.getFormatterSymbols(),
)
}
@ -164,9 +164,13 @@ class UserPreferencesRepositoryImpl @Inject constructor(
}
}
override suspend fun updateSeparator(separator: Int) {
override suspend fun updateFormatterSymbols(grouping: String, fractional: String) {
// Grouping and fractional symbols are always different
if (grouping == fractional) return
dataStore.edit { preferences ->
preferences[PrefsKeys.SEPARATOR] = separator
preferences[PrefsKeys.FORMATTER_GROUPING] = grouping
preferences[PrefsKeys.FORMATTER_FRACTIONAL] = fractional
}
}

View File

@ -49,14 +49,15 @@ 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.FormatterSymbols
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.core.ui.common.DrawerButton
import com.sadellie.unitto.core.ui.common.EmptyScreen
import com.sadellie.unitto.core.ui.common.ScaffoldWithTopBar
import com.sadellie.unitto.core.ui.common.SegmentedButton
import com.sadellie.unitto.core.ui.common.SegmentedButtonsRow
import com.sadellie.unitto.core.ui.common.textfield.ExpressionTransformer
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.ui.openLink
import com.sadellie.unitto.data.common.isEqualTo
import com.sadellie.unitto.feature.bodymass.components.BodyMassResult
@ -223,7 +224,7 @@ fun PreviewBodyMassScreen() {
weight = TextFieldValue(),
normalWeightRange = BigDecimal(30) to BigDecimal(50),
result = BigDecimal(18.5),
formatterSymbols = FormatterSymbols.Spaces
formatterSymbols = FormatterSymbols(Token.SPACE, Token.PERIOD)
),
updateHeight1 = {},
updateHeight2 = {},

View File

@ -24,7 +24,6 @@ import android.os.Build
import androidx.compose.ui.text.input.TextFieldValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols
import com.sadellie.unitto.data.common.combine
import com.sadellie.unitto.data.common.stateIn
import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
@ -64,7 +63,7 @@ internal class BodyMassViewModel @Inject constructor(
weight = weight,
result = result,
normalWeightRange = normalWeightRange,
formatterSymbols = AllFormatterSymbols.getById(userPrefs.separator)
formatterSymbols = userPrefs.formatterSymbols
)
}
.mapLatest { ui ->

View File

@ -19,7 +19,7 @@
package com.sadellie.unitto.feature.bodymass
import androidx.compose.ui.text.input.TextFieldValue
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.base.FormatterSymbols
import java.math.BigDecimal
internal sealed class UIState {

View File

@ -37,9 +37,10 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.base.OutputFormat
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.core.ui.common.textfield.formatExpression
import com.sadellie.unitto.data.common.format
import java.math.BigDecimal
@ -171,6 +172,6 @@ fun PreviewBodyMassResult() {
value = BigDecimal(18.5),
range = BigDecimal(50) to BigDecimal(80),
rangeSuffix = "kg",
formatterSymbols = FormatterSymbols.Spaces,
formatterSymbols = FormatterSymbols(Token.SPACE, Token.PERIOD),
)
}

View File

@ -26,9 +26,10 @@ import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.test.swipeDown
import androidx.compose.ui.text.input.TextFieldValue
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.base.OutputFormat
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.base.Token
import org.junit.Rule
import org.junit.Test
@ -67,7 +68,7 @@ class CalculatorScreenTest {
radianMode = false,
precision = 3,
outputFormat = OutputFormat.PLAIN,
formatterSymbols = FormatterSymbols.Spaces,
formatterSymbols = FormatterSymbols(Token.SPACE, Token.PERIOD),
history = emptyList(),
middleZero = false,
acButton = true,
@ -100,7 +101,7 @@ class CalculatorScreenTest {
radianMode = false,
precision = 3,
outputFormat = OutputFormat.PLAIN,
formatterSymbols = FormatterSymbols.Spaces,
formatterSymbols = FormatterSymbols(Token.SPACE, Token.PERIOD),
history = emptyList(),
middleZero = false,
acButton = true,

View File

@ -62,14 +62,15 @@ import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.base.OutputFormat
import com.sadellie.unitto.core.base.R
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.DrawerButton
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 com.sadellie.unitto.data.model.HistoryItem
import com.sadellie.unitto.feature.calculator.components.CalculatorKeyboard
import com.sadellie.unitto.feature.calculator.components.HistoryItemHeight
@ -355,7 +356,7 @@ private fun PreviewCalculatorScreen() {
radianMode = false,
precision = 3,
outputFormat = OutputFormat.PLAIN,
formatterSymbols = FormatterSymbols.Spaces,
formatterSymbols = FormatterSymbols(Token.SPACE, Token.PERIOD),
history = historyItems,
middleZero = false,
acButton = true,

View File

@ -20,8 +20,8 @@ package com.sadellie.unitto.feature.calculator
import androidx.annotation.StringRes
import androidx.compose.ui.text.input.TextFieldValue
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.data.model.HistoryItem
internal sealed class CalculatorUIState {

View File

@ -24,7 +24,6 @@ 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.addBracket
import com.sadellie.unitto.core.ui.common.textfield.addTokens
import com.sadellie.unitto.core.ui.common.textfield.deleteTokens
@ -79,7 +78,7 @@ internal class CalculatorViewModel @Inject constructor(
radianMode = prefs.radianMode,
precision = prefs.precision,
outputFormat = prefs.outputFormat,
formatterSymbols = AllFormatterSymbols.getById(prefs.separator),
formatterSymbols = prefs.formatterSymbols,
history = history,
middleZero = prefs.middleZero,
acButton = prefs.acButton,

View File

@ -110,7 +110,6 @@ import com.sadellie.unitto.core.ui.common.icons.iconpack.RightBracket
import com.sadellie.unitto.core.ui.common.icons.iconpack.Root
import com.sadellie.unitto.core.ui.common.icons.iconpack.Sin
import com.sadellie.unitto.core.ui.common.icons.iconpack.Tan
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
@Composable
internal fun CalculatorKeyboard(
@ -182,8 +181,8 @@ private fun PortraitKeyboard(
val angleIcon = remember(radianMode) { if (radianMode) IconPack.Rad else IconPack.Deg }
val angleIconDescription = remember(radianMode) { if (radianMode) R.string.keyboard_radian else R.string.keyboard_degree }
val fractionalIcon = remember(fractional) { if (fractional == Token.Digit.dot) IconPack.Dot else IconPack.Comma }
val fractionalIconDescription = remember(fractional) { if (fractional == Token.Digit.dot) R.string.keyboard_dot else R.string.comma }
val fractionalIcon = remember(fractional) { if (fractional == Token.PERIOD) IconPack.Dot else IconPack.Comma }
val fractionalIconDescription = remember(fractional) { if (fractional == Token.PERIOD) R.string.keyboard_dot else R.string.comma }
var showAdditional: Boolean by remember { mutableStateOf(false) }
val expandRotation: Float by animateFloatAsState(
@ -414,8 +413,8 @@ private fun LandscapeKeyboard(
val angleIcon = remember(radianMode) { if (radianMode) IconPack.Rad else IconPack.Deg }
val angleIconDescription = remember(radianMode) { if (radianMode) R.string.keyboard_radian else R.string.keyboard_degree }
val fractionalIcon = remember(fractional) { if (fractional == Token.Digit.dot) IconPack.Dot else IconPack.Comma }
val fractionalIconDescription = remember(fractional) { if (fractional == Token.Digit.dot) R.string.keyboard_dot else R.string.comma }
val fractionalIcon = remember(fractional) { if (fractional == Token.PERIOD) IconPack.Dot else IconPack.Comma }
val fractionalIconDescription = remember(fractional) { if (fractional == Token.PERIOD) R.string.keyboard_dot else R.string.comma }
Crossfade(
targetState = invMode,
@ -544,7 +543,7 @@ private fun PreviewPortraitKeyboard() {
PortraitKeyboard(
modifier = Modifier.fillMaxHeight(),
radianMode = true,
fractional = FormatterSymbols.Comma.fractional,
fractional = Token.PERIOD,
addSymbol = {},
clearSymbols = {},
deleteSymbol = {},
@ -564,7 +563,7 @@ private fun PreviewLandscapeKeyboard() {
LandscapeKeyboard(
modifier = Modifier.fillMaxHeight(),
radianMode = true,
fractional = FormatterSymbols.Comma.fractional,
fractional = Token.PERIOD,
addSymbol = {},
clearSymbols = {},
deleteSymbol = {},

View File

@ -47,9 +47,10 @@ import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.core.ui.common.textfield.FixedExpressionInputTextField
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.data.model.HistoryItem
import java.text.SimpleDateFormat
import java.util.Locale
@ -225,7 +226,7 @@ private fun PreviewHistoryList() {
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f))
.fillMaxSize(),
historyItems = historyItems,
formatterSymbols = FormatterSymbols.Spaces,
formatterSymbols = FormatterSymbols(Token.SPACE, Token.PERIOD),
addTokens = {},
onDelete = {},
showDeleteButtons = true,

View File

@ -39,10 +39,10 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTag
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.ui.LocalWindowSize
import com.sadellie.unitto.core.ui.WindowHeightSizeClass
import com.sadellie.unitto.core.ui.common.textfield.ExpressionTextField
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.ui.common.textfield.SimpleTextField
import com.sadellie.unitto.feature.calculator.CalculationResult

View File

@ -70,6 +70,7 @@ 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.FormatterSymbols
import com.sadellie.unitto.core.base.OutputFormat
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.base.Token
@ -80,7 +81,6 @@ import com.sadellie.unitto.core.ui.common.EmptyScreen
import com.sadellie.unitto.core.ui.common.PortraitLandscape
import com.sadellie.unitto.core.ui.common.ScaffoldWithTopBar
import com.sadellie.unitto.core.ui.common.textfield.ExpressionTextField
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.ui.common.textfield.NumberBaseTextField
import com.sadellie.unitto.core.ui.common.textfield.SimpleTextField
import com.sadellie.unitto.core.ui.datetime.formatDateWeekDayMonthYear
@ -425,7 +425,7 @@ private fun ConverterResultTextField(
result: ConverterResult,
scale: Int = 0,
outputFormat: Int = OutputFormat.PLAIN,
formatterSymbols: FormatterSymbols = FormatterSymbols.Spaces,
formatterSymbols: FormatterSymbols = FormatterSymbols(Token.SPACE, Token.PERIOD),
onErrorClick: () -> Unit = {},
) {
val mContext = LocalContext.current

View File

@ -20,9 +20,9 @@ package com.sadellie.unitto.feature.converter
import android.content.Context
import androidx.compose.ui.text.input.TextFieldValue
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.ui.common.textfield.formatExpression
import com.sadellie.unitto.data.common.format
import com.sadellie.unitto.data.common.isEqualTo

View File

@ -23,7 +23,6 @@ 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.addBracket
import com.sadellie.unitto.core.ui.common.textfield.addTokens
import com.sadellie.unitto.core.ui.common.textfield.deleteTokens
@ -94,7 +93,7 @@ internal class ConverterViewModel @Inject constructor(
unitFrom = unitFrom as DefaultUnit,
unitTo = unitTo as DefaultUnit,
middleZero = prefs.middleZero,
formatterSymbols = AllFormatterSymbols.getById(prefs.separator),
formatterSymbols = prefs.formatterSymbols,
scale = prefs.precision,
outputFormat = prefs.outputFormat,
formatTime = prefs.unitConverterFormatTime,

View File

@ -19,7 +19,7 @@
package com.sadellie.unitto.feature.converter
import androidx.compose.ui.text.input.TextFieldValue
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.data.model.unit.AbstractUnit

View File

@ -22,7 +22,6 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols
import com.sadellie.unitto.data.common.stateIn
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.repository.UnitsRepository
@ -112,7 +111,7 @@ internal class UnitSelectorViewModel @Inject constructor(
sorting = prefs.unitConverterSorting,
scale = prefs.precision,
outputFormat = prefs.outputFormat,
formatterSymbols = AllFormatterSymbols.getById(prefs.separator),
formatterSymbols = prefs.formatterSymbols,
)
}
.mapLatest { ui ->

View File

@ -28,11 +28,12 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.base.OutputFormat
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.core.ui.common.EmptyScreen
import com.sadellie.unitto.core.ui.common.SearchBar
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.ui.common.textfield.formatExpression
import com.sadellie.unitto.data.common.format
import com.sadellie.unitto.data.converter.UnitID
@ -189,7 +190,7 @@ private fun UnitToSelectorPreview() {
input = "100",
scale = 3,
outputFormat = OutputFormat.PLAIN,
formatterSymbols = FormatterSymbols.Spaces,
formatterSymbols = FormatterSymbols(Token.SPACE, Token.PERIOD),
),
onQueryChange = {},
toggleFavoritesOnly = {},

View File

@ -66,7 +66,6 @@ import com.sadellie.unitto.core.ui.common.icons.iconpack.Plus
import com.sadellie.unitto.core.ui.common.icons.iconpack.Power
import com.sadellie.unitto.core.ui.common.icons.iconpack.RightBracket
import com.sadellie.unitto.core.ui.common.icons.iconpack.Root
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
@Composable
internal fun DefaultKeyboard(
@ -79,8 +78,8 @@ internal fun DefaultKeyboard(
acButton: Boolean,
addBracket: () -> Unit,
) {
val fractionalIcon = remember(fractional) { if (fractional == Token.Digit.dot) IconPack.Dot else IconPack.Comma }
val fractionalIconDescription = remember(fractional) { if (fractional == Token.Digit.dot) R.string.keyboard_dot else R.string.comma }
val fractionalIcon = remember(fractional) { if (fractional == Token.PERIOD) IconPack.Dot else IconPack.Comma }
val fractionalIconDescription = remember(fractional) { if (fractional == Token.PERIOD) R.string.keyboard_dot else R.string.comma }
val contentHeight: Float = if (LocalWindowSize.current.heightSizeClass < WindowHeightSizeClass.Medium) KeyboardButtonContentHeightShort else KeyboardButtonContentHeightTall
KeypadFlow(
@ -178,7 +177,7 @@ private fun PreviewConverterKeyboard() {
addDigit = {},
clearInput = {},
deleteDigit = {},
fractional = FormatterSymbols.Spaces.fractional,
fractional = Token.PERIOD,
middleZero = false,
acButton = true,
addBracket = {}

View File

@ -19,7 +19,8 @@
package com.sadellie.unitto.feature.converter
import android.content.Context
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.base.Token
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
@ -32,7 +33,7 @@ class ConverterUIStateKtTest {
@Test
fun format() {
val formatterSymbols = FormatterSymbols.Spaces
val formatterSymbols = FormatterSymbols(Token.SPACE, Token.PERIOD)
var basicValue = BigDecimal("1")
val mContext: Context = RuntimeEnvironment.getApplication().applicationContext

View File

@ -19,7 +19,8 @@
package com.sadellie.unitto.feature.datecalculator.addsubtract
import androidx.compose.ui.text.input.TextFieldValue
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.feature.datecalculator.ZonedDateTimeUtils
import java.time.ZonedDateTime
@ -32,6 +33,6 @@ internal data class AddSubtractState(
val hours: TextFieldValue = TextFieldValue(),
val minutes: TextFieldValue = TextFieldValue(),
val addition: Boolean = true,
val formatterSymbols: FormatterSymbols = FormatterSymbols.Spaces,
val formatterSymbols: FormatterSymbols = FormatterSymbols(Token.SPACE, Token.PERIOD),
val allowVibration: Boolean = false,
)

View File

@ -22,7 +22,6 @@ import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols
import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
@ -46,7 +45,7 @@ internal class AddSubtractViewModel @Inject constructor(
val uiState: StateFlow<AddSubtractState> = _uiState
.combine(userPreferencesRepository.addSubtractPrefs) { uiState, userPrefs ->
return@combine uiState.copy(
formatterSymbols = AllFormatterSymbols.getById(userPrefs.separator),
formatterSymbols = userPrefs.formatterSymbols,
)
}
.onEach { updateResult() }

View File

@ -40,9 +40,10 @@ 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.FormatterSymbols
import com.sadellie.unitto.core.base.OutputFormat
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.core.ui.common.textfield.formatExpression
import com.sadellie.unitto.data.common.format
import com.sadellie.unitto.feature.datecalculator.ZonedDateTimeUtils
@ -185,7 +186,7 @@ fun DateDifferenceViewPreview() {
),
precision = 3,
outputFormat = OutputFormat.PLAIN,
formatterSymbols = FormatterSymbols.Spaces
formatterSymbols = FormatterSymbols(Token.SPACE, Token.PERIOD)
),
setStartDate = {},
setEndDate = {},

View File

@ -20,7 +20,6 @@ package com.sadellie.unitto.feature.datecalculator.difference
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols
import com.sadellie.unitto.data.common.stateIn
import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import com.sadellie.unitto.feature.datecalculator.ZonedDateTimeUtils
@ -55,7 +54,7 @@ internal class DateDifferenceViewModel @Inject constructor(
result = result,
precision = prefs.digitsPrecision,
outputFormat = prefs.outputFormat,
formatterSymbols = AllFormatterSymbols.getById(prefs.separator)
formatterSymbols = prefs.formatterSymbols
)
}
.mapLatest { ui ->

View File

@ -18,7 +18,7 @@
package com.sadellie.unitto.feature.datecalculator.difference
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.base.FormatterSymbols
import java.time.ZonedDateTime
internal sealed class DifferenceUIState {

View File

@ -54,9 +54,8 @@ import androidx.glance.text.Text
import androidx.glance.text.TextAlign
import androidx.glance.text.TextStyle
import androidx.glance.unit.ColorProvider
import com.sadellie.unitto.core.base.FormatterSymbols
import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.ui.common.textfield.formatExpression
import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import com.sadellie.unitto.data.model.userprefs.CalculatorPreferences
@ -139,7 +138,7 @@ private fun ReadyUI(
val input = glancePrefs[CalculatorWidget.inputPrefKey] ?: ""
val output = glancePrefs[CalculatorWidget.outputPrefKey] ?: ""
val equalClicked = glancePrefs[CalculatorWidget.equalClickedPrefKey] ?: false
val formatterSymbols = AllFormatterSymbols.getById(appPrefs.separator)
val formatterSymbols = appPrefs.formatterSymbols
fun runCalculateAction(
input: String,

View File

@ -28,9 +28,10 @@ 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.FormatterSymbols
import com.sadellie.unitto.core.base.OutputFormat
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.base.Separator
import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.core.ui.common.EmptyScreen
import com.sadellie.unitto.core.ui.common.ListItem
import com.sadellie.unitto.core.ui.common.NavigateUpButton
@ -83,7 +84,7 @@ private fun PreviewCalculatorSettingsScreenStandard() {
CalculatorSettingsScreen(
prefs = CalculatorPreferencesImpl(
radianMode = true,
separator = Separator.SPACE,
formatterSymbols = FormatterSymbols(Token.SPACE, Token.PERIOD),
middleZero = false,
acButton = false,
partialHistoryView = false,

View File

@ -34,9 +34,10 @@ 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.FormatterSymbols
import com.sadellie.unitto.core.base.OutputFormat
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.base.Separator
import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.core.ui.common.EmptyScreen
import com.sadellie.unitto.core.ui.common.ListItem
import com.sadellie.unitto.core.ui.common.NavigateUpButton
@ -133,7 +134,7 @@ private fun ConverterSettingsScreen(
private fun PreviewConverterSettingsScreen() {
ConverterSettingsScreen(
prefs = ConverterPreferencesImpl(
separator = Separator.SPACE,
formatterSymbols = FormatterSymbols(Token.SPACE, Token.PERIOD),
middleZero = false,
precision = 3,
outputFormat = OutputFormat.PLAIN,

View File

@ -18,13 +18,18 @@
package com.sadellie.unitto.feature.settings.formatting
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.icons.Icons
@ -38,6 +43,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
@ -48,10 +54,11 @@ 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.FormatterSymbols
import com.sadellie.unitto.core.base.MAX_PRECISION
import com.sadellie.unitto.core.base.OutputFormat
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.base.Separator
import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.core.ui.common.EmptyScreen
import com.sadellie.unitto.core.ui.common.ListItem
import com.sadellie.unitto.core.ui.common.NavigateUpButton
@ -60,7 +67,6 @@ import com.sadellie.unitto.core.ui.common.ScaffoldWithLargeTopBar
import com.sadellie.unitto.core.ui.common.SegmentedButton
import com.sadellie.unitto.core.ui.common.SegmentedButtonsRow
import com.sadellie.unitto.core.ui.common.Slider
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.ui.common.textfield.formatExpression
import com.sadellie.unitto.core.ui.theme.LocalNumberTypography
import com.sadellie.unitto.data.common.format
@ -79,7 +85,7 @@ fun FormattingRoute(
navigateUpAction = navigateUpAction,
uiState = uiState,
onPrecisionChange = viewModel::updatePrecision,
onSeparatorChange = viewModel::updateSeparator,
updateFormatterSymbols = viewModel::updateFormatterSymbols,
onOutputFormatChange = viewModel::updateOutputFormat,
)
}
@ -91,7 +97,7 @@ fun FormattingScreen(
navigateUpAction: () -> Unit,
uiState: FormattingUIState,
onPrecisionChange: (Int) -> Unit,
onSeparatorChange: (Int) -> Unit,
updateFormatterSymbols: (grouping: String, fractional: String) -> Unit,
onOutputFormatChange: (Int) -> Unit,
precisions: ClosedFloatingPointRange<Float> = 0f..16f, // 16th is a MAX_PRECISION (1000)
) {
@ -114,11 +120,10 @@ fun FormattingScreen(
title = stringResource(R.string.settings_formatting),
navigationIcon = { NavigateUpButton(navigateUpAction) },
) { paddingValues ->
LazyColumn(
Column(
modifier = Modifier
.padding(paddingValues)
) {
item("preview") {
PagedIsland(
modifier = Modifier
.fillMaxWidth()
@ -146,9 +151,7 @@ fun FormattingScreen(
color = MaterialTheme.colorScheme.onSecondaryContainer
)
}
}
item("precision_label") {
ListItem(
leadingContent = {
Icon(
@ -169,28 +172,21 @@ fun FormattingScreen(
Text(stringResource(R.string.settings_precision_support))
}
)
}
item("precision_slider") {
Slider(
modifier = Modifier.padding(start = 56.dp, end = 16.dp),
value = uiState.precision.toFloat(),
valueRange = precisions,
onValueChange = { onPrecisionChange(it.roundToInt()) },
)
}
item("separator_label") {
ListItem(
leadingContent = {
Icon(Icons.Default._123, stringResource(R.string.settings_separator))
Icon(Icons.Default._123, stringResource(R.string.settings_thousands_separator))
},
headlineContent = { Text(stringResource(R.string.settings_separator)) },
supportingContent = { Text(stringResource(R.string.settings_separator_support)) },
headlineContent = { Text(stringResource(R.string.settings_thousands_separator)) },
)
}
item("separator") {
Row(
Modifier
.horizontalScroll(rememberScrollState())
@ -200,24 +196,56 @@ fun FormattingScreen(
SegmentedButtonsRow {
SegmentedButton(
label = stringResource(R.string.settings_space),
onClick = { onSeparatorChange(Separator.SPACE) },
selected = Separator.SPACE == uiState.separator
onClick = { updateFormatterSymbols(Token.SPACE, uiState.formatterSymbols.fractional) },
selected = uiState.formatterSymbols.grouping == Token.SPACE
)
SegmentedButton(
label = stringResource(R.string.settings_period),
onClick = { onSeparatorChange(Separator.PERIOD) },
selected = Separator.PERIOD == uiState.separator
onClick = { updateFormatterSymbols(Token.PERIOD, Token.COMMA) },
selected = uiState.formatterSymbols.grouping == Token.PERIOD,
)
SegmentedButton(
label = stringResource(R.string.comma),
onClick = { onSeparatorChange(Separator.COMMA) },
selected = Separator.COMMA == uiState.separator
onClick = { updateFormatterSymbols(Token.COMMA, Token.PERIOD) },
selected = uiState.formatterSymbols.grouping == Token.COMMA,
)
}
}
AnimatedVisibility(
visible = uiState.formatterSymbols.grouping == Token.SPACE,
enter = expandVertically() + fadeIn(),
exit = shrinkVertically() + fadeOut()
) {
Column(
modifier = Modifier.padding(start = 40.dp)
) {
ListItem(
modifier = Modifier,
headlineContent = { Text(stringResource(R.string.settings_decimal_separator)) },
)
Row(
Modifier
.horizontalScroll(rememberScrollState())
.wrapContentWidth()
.padding(start = 16.dp)
) {
SegmentedButtonsRow {
SegmentedButton(
label = stringResource(R.string.settings_period),
onClick = { updateFormatterSymbols(Token.SPACE, Token.PERIOD) },
selected = uiState.formatterSymbols.fractional == Token.PERIOD,
)
SegmentedButton(
label = stringResource(R.string.comma),
onClick = { updateFormatterSymbols(Token.SPACE, Token.COMMA) },
selected = uiState.formatterSymbols.fractional == Token.COMMA,
)
}
}
}
}
item("output_format_label") {
ListItem(
leadingContent = {
Icon(Icons.Default.EMobiledata, stringResource(R.string.settings_precision))
@ -225,9 +253,7 @@ fun FormattingScreen(
headlineContent = { Text(stringResource(R.string.settings_exponential_notation)) },
supportingContent = { Text(stringResource(R.string.settings_exponential_notation_support)) }
)
}
item("output_format") {
Row(
Modifier
.horizontalScroll(rememberScrollState())
@ -255,24 +281,24 @@ fun FormattingScreen(
}
}
}
}
@Preview
@Composable
private fun PreviewFormattingScreen() {
var currentPrecision by remember { mutableIntStateOf(6) }
var currentSeparator by remember { mutableIntStateOf(Separator.COMMA) }
var currentFormatterSymbols by remember { mutableStateOf(FormatterSymbols(Token.SPACE, Token.PERIOD)) }
var currentOutputFormat by remember { mutableIntStateOf(OutputFormat.PLAIN) }
FormattingScreen(
uiState = FormattingUIState(
precision = 16,
separator = Separator.SPACE,
outputFormat = OutputFormat.PLAIN,
formatterSymbols = FormatterSymbols.Spaces
formatterSymbols = currentFormatterSymbols
),
onPrecisionChange = { currentPrecision = it },
onSeparatorChange = { currentSeparator = it },
updateFormatterSymbols = updateFormatterSymbols@{ grouping, fractional ->
currentFormatterSymbols = FormatterSymbols(grouping, fractional)
},
onOutputFormatChange = { currentOutputFormat = it },
navigateUpAction = {},
)

View File

@ -18,11 +18,10 @@
package com.sadellie.unitto.feature.settings.formatting
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.base.FormatterSymbols
data class FormattingUIState(
val precision: Int,
val separator: Int,
val outputFormat: Int,
val formatterSymbols: FormatterSymbols,
)

View File

@ -21,7 +21,6 @@ package com.sadellie.unitto.feature.settings.formatting
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.core.base.MAX_PRECISION
import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols
import com.sadellie.unitto.data.common.stateIn
import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel
@ -38,9 +37,8 @@ class FormattingViewModel @Inject constructor(
val uiState = _prefs.map { mainPrefs ->
FormattingUIState(
precision = mainPrefs.digitsPrecision,
separator = mainPrefs.separator,
outputFormat = mainPrefs.outputFormat,
formatterSymbols = AllFormatterSymbols.getById(mainPrefs.separator)
formatterSymbols = mainPrefs.formatterSymbols
)
}
.stateIn(viewModelScope, null)
@ -55,10 +53,10 @@ class FormattingViewModel @Inject constructor(
}
/**
* @see UserPreferencesRepository.updateSeparator
* @see UserPreferencesRepository.updateFormatterSymbols
*/
fun updateSeparator(separator: Int) = viewModelScope.launch {
userPreferencesRepository.updateSeparator(separator)
fun updateFormatterSymbols(grouping: String, fractional: String) = viewModelScope.launch {
userPreferencesRepository.updateFormatterSymbols(grouping, fractional)
}
/**