Prepare for text2

Enabled physical keyboard support (#148), but not tested
This commit is contained in:
Sad Ellie 2024-02-05 23:30:20 +03:00
parent bf9bf37812
commit 5c81a1c675
8 changed files with 148 additions and 189 deletions

View File

@ -18,37 +18,46 @@
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 androidx.compose.ui.text.input.TextFieldValue
import com.sadellie.unitto.core.base.Token
/**
* Copy value to clipboard with fractional symbols.
* Unformatted values are expected. Basically what BigDecimal and Expression parser use.
*
* Example:
* "123456.789" will be copied as "123456,789"
*
* @param value Internal [TextFieldValue] without formatting with [Token.Digit.dot] as fractional.
* @property formatterSymbols Current [FormatterSymbols].
* @property clipboardManager [android.content.ClipboardManager] provided by system.
*/
internal fun ClipboardManager.copyWithFractional(
value: TextFieldValue,
formatterSymbols: FormatterSymbols
) = this.setText(
AnnotatedString(
value.annotatedString
.subSequence(value.selection)
internal class ExpressionClipboardManager(
private val formatterSymbols: FormatterSymbols,
private val clipboardManager: android.content.ClipboardManager
): ClipboardManager {
override fun setText(annotatedString: AnnotatedString) = clipboardManager.setPrimaryClip(
ClipData.newPlainText(
PLAIN_TEXT_LABEL,
annotatedString
.text
.replace(Token.Digit.dot, formatterSymbols.fractional)
)
)
internal fun ClipboardManager.copy(value: TextFieldValue) = this.setText(
AnnotatedString(
value.annotatedString
.subSequence(value.selection)
.text
)
)
override fun getText(): AnnotatedString? = clipboardManager.primaryClip?.let { primaryClip ->
if (primaryClip.itemCount > 0) {
val clipText = primaryClip.getItemAt(0)?.text ?:return@let null
clipText
.toString()
.toAnnotatedString()
} else {
null
}
}
override fun hasText() =
clipboardManager.primaryClipDescription?.hasMimeType("text/*") ?: false
}
internal const val PLAIN_TEXT_LABEL = "plain text"
private fun CharSequence.toAnnotatedString(): AnnotatedString = AnnotatedString(this.toString())

View File

@ -18,7 +18,7 @@
package com.sadellie.unitto.core.ui.common.textfield
import androidx.compose.foundation.clickable
import android.content.Context
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.text.BasicTextField
@ -32,27 +32,19 @@ import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalTextInputService
import androidx.compose.ui.platform.LocalTextToolbar
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.platform.TextToolbar
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.TextStyle
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.ui.common.autosize.AutoSizeTextStyleBox
import com.sadellie.unitto.core.ui.common.textfield.texttoolbar.UnittoTextToolbar
import com.sadellie.unitto.core.ui.theme.LocalNumberTypography
@Composable
@ -60,105 +52,86 @@ fun ExpressionTextField(
modifier: Modifier,
value: TextFieldValue,
minRatio: Float = 1f,
cutCallback: () -> Unit = {},
pasteCallback: (String) -> Unit = {},
onCursorChange: (TextRange) -> Unit,
onValueChange: (TextFieldValue) -> Unit,
textColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
formatterSymbols: FormatterSymbols,
readOnly: Boolean = false,
placeholder: String = "",
) {
val localView = LocalView.current
val clipboardManager = LocalClipboardManager.current
val expressionTransformer = remember(formatterSymbols) { ExpressionTransformer(formatterSymbols) }
fun copyCallback() {
clipboardManager.copyWithFractional(value, formatterSymbols)
onCursorChange(TextRange(value.selection.end))
}
val textToolbar: UnittoTextToolbar = if (readOnly) {
UnittoTextToolbar(
view = localView,
copyCallback = ::copyCallback,
)
} else {
UnittoTextToolbar(
view = localView,
copyCallback = ::copyCallback,
pasteCallback = {
pasteCallback(clipboardManager.getText()?.text?.clearAndFilterExpression(formatterSymbols) ?: "")
},
cutCallback = {
clipboardManager.copyWithFractional(value, formatterSymbols)
cutCallback()
}
val context = LocalContext.current
val clipboardManager = remember(formatterSymbols) {
ExpressionClipboardManager(
formatterSymbols = formatterSymbols,
clipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE)
as android.content.ClipboardManager
)
}
val expressionTransformer = remember(formatterSymbols) {
ExpressionTransformer(formatterSymbols)
}
CompositionLocalProvider(
LocalClipboardManager provides clipboardManager
) {
AutoSizeTextField(
modifier = modifier,
value = value,
onValueChange = { onCursorChange(it.selection) },
onValueChange = {
onValueChange(it.copy(text = it.text.clearAndFilterExpression(formatterSymbols)))
},
placeholder = placeholder,
textToolbar = textToolbar,
readOnly = readOnly,
textStyle = LocalNumberTypography.current.displayLarge.copy(textColor),
visualTransformation = expressionTransformer,
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurfaceVariant),
minRatio = minRatio
)
}
}
@Composable
fun UnformattedTextField(
fun NumberBaseTextField(
modifier: Modifier,
value: TextFieldValue,
minRatio: Float = 1f,
cutCallback: () -> Unit = {},
pasteCallback: (String) -> Unit = {},
onCursorChange: (TextRange) -> Unit,
onValueChange: (TextFieldValue) -> Unit,
textColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
readOnly: Boolean = false,
placeholder: String = "",
) {
val localView = LocalView.current
val clipboardManager = LocalClipboardManager.current
fun copyCallback() {
clipboardManager.copy(value)
onCursorChange(TextRange(value.selection.end))
}
val textToolbar: UnittoTextToolbar = remember(readOnly) {
if (readOnly) {
UnittoTextToolbar(
view = localView,
copyCallback = ::copyCallback,
)
} else {
UnittoTextToolbar(
view = localView,
copyCallback = ::copyCallback,
pasteCallback = {
pasteCallback(clipboardManager.getText()?.text?.clearAndFilterNumberBase() ?: "")
},
cutCallback = {
clipboardManager.copy(value)
cutCallback()
}
)
}
}
AutoSizeTextField(
modifier = modifier,
value = value,
onValueChange = { onCursorChange(it.selection) },
onValueChange = {
onValueChange(it.copy(text = it.text.clearAndFilterNumberBase()))
},
placeholder = placeholder,
textToolbar = textToolbar,
readOnly = readOnly,
textStyle = LocalNumberTypography.current.displayLarge.copy(color = textColor),
minRatio = minRatio,
textStyle = LocalNumberTypography.current.displayLarge.copy(textColor),
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurfaceVariant),
minRatio = minRatio
)
}
@Composable
fun SimpleTextField(
modifier: Modifier,
value: TextFieldValue,
minRatio: Float = 1f,
onValueChange: (TextFieldValue) -> Unit,
textColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
readOnly: Boolean = false,
placeholder: String = "",
) {
AutoSizeTextField(
modifier = modifier,
value = value,
onValueChange = onValueChange,
placeholder = placeholder,
readOnly = readOnly,
textStyle = LocalNumberTypography.current.displayLarge.copy(textColor),
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurfaceVariant),
minRatio = minRatio
)
}
@ -166,7 +139,6 @@ fun UnformattedTextField(
* Based on: https://gist.github.com/inidamleader/b594d35362ebcf3cedf81055df519300
*
* @param placeholder Placeholder text, shown when [value] is empty.
* @param textToolbar [TextToolbar] with modified actions in menu.
* @param alignment The alignment of the text within its container.
* @see [BasicTextField]
* @see [AutoSizeTextStyleBox]
@ -177,7 +149,6 @@ private fun AutoSizeTextField(
value: TextFieldValue,
onValueChange: (TextFieldValue) -> Unit,
placeholder: String? = null,
textToolbar: TextToolbar = LocalTextToolbar.current,
enabled: Boolean = true,
readOnly: Boolean = false,
textStyle: TextStyle = TextStyle.Default,
@ -206,28 +177,14 @@ private fun AutoSizeTextField(
) {
CompositionLocalProvider(
LocalTextInputService provides null,
LocalTextToolbar provides textToolbar
) {
val currentTextToolbar = LocalTextToolbar.current
val style = LocalTextStyle.current
val focusRequester = remember { FocusRequester() }
BasicTextField(
value = value,
onValueChange = onValueChange,
modifier = Modifier
.fillMaxWidth()
.focusRequester(focusRequester)
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
onClick = {
currentTextToolbar.hide()
focusRequester.requestFocus()
onValueChange(value.copy(selection = TextRange.Zero))
currentTextToolbar.showMenu(Rect(Offset.Zero, 0f))
}
),
.fillMaxWidth(),
enabled = enabled,
readOnly = readOnly,
textStyle = style,

View File

@ -46,11 +46,12 @@ class CalculatorScreenTest {
addTokens = {},
clearInput = {},
deleteTokens = {},
onCursorChange = {},
onValueChange = {},
toggleCalculatorMode = {},
equal = {},
clearHistory = {},
addBracket = {}
addBracket = {},
onDelete = {},
)
}
@ -69,7 +70,6 @@ class CalculatorScreenTest {
outputFormat = OutputFormat.PLAIN,
formatterSymbols = FormatterSymbols.Spaces,
history = emptyList(),
allowVibration = false,
middleZero = false,
acButton = true,
partialHistoryView = true
@ -79,11 +79,12 @@ class CalculatorScreenTest {
addTokens = {},
clearInput = {},
deleteTokens = {},
onCursorChange = {},
onValueChange = {},
toggleCalculatorMode = {},
equal = {},
clearHistory = {},
addBracket = {}
addBracket = {},
onDelete = {},
)
}
@ -103,7 +104,6 @@ class CalculatorScreenTest {
outputFormat = OutputFormat.PLAIN,
formatterSymbols = FormatterSymbols.Spaces,
history = emptyList(),
allowVibration = false,
middleZero = false,
acButton = true,
partialHistoryView = true
@ -113,11 +113,12 @@ class CalculatorScreenTest {
addTokens = {},
clearInput = {},
deleteTokens = {},
onCursorChange = {},
onValueChange = {},
toggleCalculatorMode = {},
equal = {},
clearHistory = {},
addBracket = {}
addBracket = {},
onDelete = {},
)
}

View File

@ -56,7 +56,6 @@ import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTag
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.IntOffset
@ -97,7 +96,7 @@ internal fun CalculatorRoute(
addTokens = viewModel::addTokens,
clearInput = viewModel::clearInput,
deleteTokens = viewModel::deleteTokens,
onCursorChange = viewModel::onCursorChange,
onValueChange = viewModel::updateInput,
toggleCalculatorMode = viewModel::updateRadianMode,
equal = viewModel::equal,
clearHistory = viewModel::clearHistory,
@ -115,7 +114,7 @@ internal fun CalculatorScreen(
addBracket: () -> Unit,
clearInput: () -> Unit,
deleteTokens: () -> Unit,
onCursorChange: (TextRange) -> Unit,
onValueChange: (TextFieldValue) -> Unit,
toggleCalculatorMode: (Boolean) -> Unit,
equal: () -> Unit,
clearHistory: () -> Unit,
@ -130,7 +129,7 @@ internal fun CalculatorScreen(
addSymbol = addTokens,
clearSymbols = clearInput,
deleteSymbol = deleteTokens,
onCursorChange = onCursorChange,
onValueChange = onValueChange,
toggleAngleMode = { toggleCalculatorMode(!uiState.radianMode) },
equal = equal,
clearHistory = clearHistory,
@ -149,7 +148,7 @@ private fun Ready(
addBracket: () -> Unit,
clearSymbols: () -> Unit,
deleteSymbol: () -> Unit,
onCursorChange: (TextRange) -> Unit,
onValueChange: (TextFieldValue) -> Unit,
toggleAngleMode: () -> Unit,
equal: () -> Unit,
clearHistory: () -> Unit,
@ -266,9 +265,7 @@ private fun Ready(
),
formatterSymbols = uiState.formatterSymbols,
input = uiState.input,
deleteSymbol = deleteSymbol,
addSymbol = addSymbol,
onCursorChange = onCursorChange,
onValueChange = onValueChange,
output = uiState.output
)
@ -379,7 +376,7 @@ private fun PreviewCalculatorScreen() {
addTokens = {},
clearInput = {},
deleteTokens = {},
onCursorChange = {},
onValueChange = {},
toggleCalculatorMode = {},
equal = {},
clearHistory = {},

View File

@ -166,11 +166,11 @@ internal class CalculatorViewModel @Inject constructor(
TextFieldValue()
}
fun onCursorChange(selection: TextRange) = _input.update {
fun updateInput(value: TextFieldValue) = _input.update {
// Without this line: will place token (even in the middle of the input) and place cursor at
// the end. This line also removes fractional output once user touches input text field
_equalClicked.update { false }
it.copy(selection = selection)
value
}
fun updateRadianMode(newValue: Boolean) = viewModelScope.launch {

View File

@ -37,14 +37,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTag
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
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.UnformattedTextField
import com.sadellie.unitto.core.ui.common.textfield.SimpleTextField
import com.sadellie.unitto.feature.calculator.CalculationResult
@Composable
@ -52,9 +51,7 @@ fun TextBox(
modifier: Modifier,
formatterSymbols: FormatterSymbols,
input: TextFieldValue,
deleteSymbol: () -> Unit,
addSymbol: (String) -> Unit,
onCursorChange: (TextRange) -> Unit,
onValueChange: (TextFieldValue) -> Unit,
output: CalculationResult,
) {
Column(
@ -77,9 +74,7 @@ fun TextBox(
.padding(horizontal = 8.dp),
value = input,
minRatio = 0.5f,
cutCallback = deleteSymbol,
pasteCallback = addSymbol,
onCursorChange = onCursorChange,
onValueChange = onValueChange,
formatterSymbols = formatterSymbols
)
if (LocalWindowSize.current.heightSizeClass > WindowHeightSizeClass.Compact) {
@ -105,9 +100,9 @@ fun TextBox(
.padding(horizontal = 8.dp),
value = outputTF,
minRatio = 0.8f,
onCursorChange = { outputTF = outputTF.copy(selection = it) },
formatterSymbols = formatterSymbols,
onValueChange = { outputTF = it },
textColor = MaterialTheme.colorScheme.onSurfaceVariant.copy(0.6f),
formatterSymbols = formatterSymbols,
readOnly = true,
)
}
@ -123,36 +118,36 @@ fun TextBox(
.padding(horizontal = 8.dp),
value = outputTF,
minRatio = 0.8f,
onCursorChange = { outputTF = outputTF.copy(selection = it) },
formatterSymbols = formatterSymbols,
onValueChange = { outputTF = it },
textColor = MaterialTheme.colorScheme.onSurfaceVariant.copy(0.6f),
formatterSymbols = formatterSymbols,
readOnly = true,
)
}
is CalculationResult.DivideByZeroError -> {
UnformattedTextField(
SimpleTextField(
modifier = Modifier
.weight(2f)
.fillMaxWidth()
.padding(horizontal = 8.dp),
value = TextFieldValue(stringResource(output.label)),
minRatio = 0.8f,
onCursorChange = {},
onValueChange = {},
textColor = MaterialTheme.colorScheme.error,
readOnly = true,
)
}
is CalculationResult.Error -> {
UnformattedTextField(
SimpleTextField(
modifier = Modifier
.weight(2f)
.fillMaxWidth()
.padding(horizontal = 8.dp),
value = TextFieldValue(stringResource(output.label)),
minRatio = 0.8f,
onCursorChange = {},
onValueChange = {},
textColor = MaterialTheme.colorScheme.error,
readOnly = true,
)

View File

@ -64,7 +64,6 @@ import androidx.compose.ui.focus.onFocusEvent
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@ -83,7 +82,8 @@ import com.sadellie.unitto.core.ui.common.ScaffoldWithTopBar
import com.sadellie.unitto.core.ui.common.SettingsButton
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.UnformattedTextField
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
import com.sadellie.unitto.data.common.format
import com.sadellie.unitto.data.converter.UnitID
@ -114,7 +114,7 @@ internal fun ConverterRoute(
processInput = viewModel::addTokens,
deleteDigit = viewModel::deleteTokens,
clearInput = viewModel::clearInput,
onCursorChange = viewModel::onCursorChange,
onValueChange = viewModel::updateInput,
onFocusOnInput2 = viewModel::updateFocused,
onErrorClick = viewModel::updateCurrencyRates,
addBracket = viewModel::addBracket
@ -132,7 +132,7 @@ private fun ConverterScreen(
processInput: (String) -> Unit,
deleteDigit: () -> Unit,
clearInput: () -> Unit,
onCursorChange: (TextRange) -> Unit,
onValueChange: (TextFieldValue) -> Unit,
onFocusOnInput2: (Boolean) -> Unit,
onErrorClick: (AbstractUnit) -> Unit,
addBracket: () -> Unit,
@ -148,7 +148,7 @@ private fun ConverterScreen(
NumberBase(
modifier = Modifier.padding(it),
uiState = uiState,
onCursorChange = onCursorChange,
onValueChange = onValueChange,
processInput = processInput,
deleteDigit = deleteDigit,
navigateToLeftScreen = navigateToLeftScreen,
@ -167,7 +167,7 @@ private fun ConverterScreen(
Default(
modifier = Modifier.padding(it),
uiState = uiState,
onCursorChange = onCursorChange,
onValueChange = onValueChange,
onFocusOnInput2 = onFocusOnInput2,
processInput = processInput,
deleteDigit = deleteDigit,
@ -204,7 +204,7 @@ private fun UnitConverterTopBar(
private fun NumberBase(
modifier: Modifier,
uiState: UnitConverterUIState.NumberBase,
onCursorChange: (TextRange) -> Unit,
onValueChange: (TextFieldValue) -> Unit,
processInput: (String) -> Unit,
deleteDigit: () -> Unit,
navigateToLeftScreen: () -> Unit,
@ -218,14 +218,12 @@ private fun NumberBase(
ColumnWithConstraints(modifier = contentModifier) {
val textFieldModifier = Modifier.weight(2f)
UnformattedTextField(
NumberBaseTextField(
modifier = textFieldModifier,
minRatio = 0.7f,
placeholder = Token.Digit._0,
value = uiState.input,
onCursorChange = onCursorChange,
pasteCallback = processInput,
cutCallback = deleteDigit,
onValueChange = onValueChange,
)
AnimatedUnitShortName(stringResource(uiState.unitFrom.shortName))
@ -261,7 +259,7 @@ private fun NumberBase(
private fun Default(
modifier: Modifier,
uiState: UnitConverterUIState.Default,
onCursorChange: (TextRange) -> Unit,
onValueChange: (TextFieldValue) -> Unit,
onFocusOnInput2: (Boolean) -> Unit,
processInput: (String) -> Unit,
deleteDigit: () -> Unit,
@ -330,13 +328,11 @@ private fun Default(
) {
ExpressionTextField(
modifier = Modifier.fillMaxWidth().weight(1f),
minRatio = 0.7f,
placeholder = Token.Digit._0,
value = uiState.input1,
onCursorChange = onCursorChange,
pasteCallback = processInput,
cutCallback = deleteDigit,
minRatio = 0.7f,
onValueChange = onValueChange,
formatterSymbols = uiState.formatterSymbols,
placeholder = Token.Digit._0,
)
AnimatedUnitShortName(stringResource(uiState.unitFrom.shortName))
}
@ -351,13 +347,11 @@ private fun Default(
ExpressionTextField(
modifier = Modifier.fillMaxWidth().weight(1f)
.onFocusEvent { state -> onFocusOnInput2(state.hasFocus) },
minRatio = 0.7f,
placeholder = Token.Digit._0,
value = uiState.input2,
onCursorChange = onCursorChange,
pasteCallback = processInput,
cutCallback = deleteDigit,
minRatio = 0.7f,
onValueChange = onValueChange,
formatterSymbols = uiState.formatterSymbols,
placeholder = Token.Digit._0,
)
AnimatedUnitShortName(stringResource(R.string.unit_inch_short))
}
@ -365,13 +359,11 @@ private fun Default(
} else {
ExpressionTextField(
modifier = textFieldModifier,
minRatio = 0.7f,
placeholder = Token.Digit._0,
value = uiState.input1,
onCursorChange = onCursorChange,
pasteCallback = processInput,
cutCallback = deleteDigit,
minRatio = 0.7f,
onValueChange = onValueChange,
formatterSymbols = uiState.formatterSymbols,
placeholder = Token.Digit._0,
)
AnimatedVisibility(
visible = calculation.text.isNotEmpty(),
@ -382,10 +374,10 @@ private fun Default(
ExpressionTextField(
modifier = Modifier,
value = calculation,
onCursorChange = { calculation = calculation.copy(selection = it) },
formatterSymbols = uiState.formatterSymbols,
minRatio = 0.7f,
onValueChange = { calculation = it },
textColor = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
formatterSymbols = uiState.formatterSymbols,
readOnly = true
)
}
@ -456,20 +448,20 @@ private fun ConverterResultTextField(
when (result) {
is ConverterResult.Loading -> {
UnformattedTextField(
SimpleTextField(
modifier = modifier,
value = TextFieldValue(stringResource(R.string.loading_label)),
onCursorChange = {},
onValueChange = {},
minRatio = 0.7f,
readOnly = true
)
}
is ConverterResult.Error -> {
UnformattedTextField(
SimpleTextField(
modifier = modifier,
value = TextFieldValue(stringResource(R.string.error_label)),
onCursorChange = { onErrorClick() },
onValueChange = { onErrorClick() },
minRatio = 0.7f,
readOnly = true,
textColor = MaterialTheme.colorScheme.error,
@ -480,20 +472,29 @@ private fun ConverterResultTextField(
ExpressionTextField(
modifier = modifier,
value = resultTextField,
onCursorChange = { resultTextField = resultTextField.copy(selection = it) },
minRatio = 0.7f,
onValueChange = { resultTextField = it },
formatterSymbols = formatterSymbols,
readOnly = true
)
}
is ConverterResult.NumberBase -> {
NumberBaseTextField(
modifier = modifier,
value = resultTextField,
onValueChange = { resultTextField = it },
minRatio = 0.7f,
readOnly = true
)
}
is ConverterResult.NumberBase,
is ConverterResult.Time,
is ConverterResult.FootInch -> {
UnformattedTextField(
SimpleTextField(
modifier = modifier,
value = resultTextField,
onCursorChange = { resultTextField = resultTextField.copy(selection = it) },
onValueChange = { resultTextField = it },
minRatio = 0.7f,
readOnly = true
)
@ -585,7 +586,7 @@ private fun PreviewConverterScreen() {
processInput = {},
deleteDigit = {},
clearInput = {},
onCursorChange = {},
onValueChange = {},
onFocusOnInput2 = {},
onErrorClick = {},
addBracket = {}

View File

@ -18,7 +18,6 @@
package com.sadellie.unitto.feature.converter
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
@ -321,7 +320,7 @@ internal class ConverterViewModel @Inject constructor(
}
}
fun onCursorChange(selection: TextRange) = _input1.update { it.copy(selection = selection) }
fun updateInput(value: TextFieldValue) = _input1.update { value }
fun updateCurrencyRates(unit: AbstractUnit) {
_loadCurrenciesJob = viewModelScope.launch(Dispatchers.IO) {