diff --git a/feature/epoch/src/main/java/com/sadellie/unitto/feature/epoch/EpochScreen.kt b/feature/epoch/src/main/java/com/sadellie/unitto/feature/epoch/EpochScreen.kt index 65b1cf1c..b9a287e6 100644 --- a/feature/epoch/src/main/java/com/sadellie/unitto/feature/epoch/EpochScreen.kt +++ b/feature/epoch/src/main/java/com/sadellie/unitto/feature/epoch/EpochScreen.kt @@ -20,18 +20,14 @@ package com.sadellie.unitto.feature.epoch import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextRange import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.sadellie.unitto.core.ui.common.UnittoTopAppBar import com.sadellie.unitto.core.ui.common.PortraitLandscape +import com.sadellie.unitto.core.ui.common.UnittoTopAppBar import com.sadellie.unitto.feature.epoch.component.EpochKeyboard import com.sadellie.unitto.feature.epoch.component.TopPart @@ -47,7 +43,8 @@ internal fun EpochRoute( addSymbol = viewModel::addSymbol, deleteSymbol = viewModel::deleteSymbol, swap = viewModel::swap, - clearSymbols = viewModel::clearSymbols + clearSymbols = viewModel::clearSymbols, + onCursorChange = viewModel::onCursorChange ) } @@ -55,17 +52,16 @@ internal fun EpochRoute( private fun EpochScreen( navigateUpAction: () -> Unit, uiState: EpochUIState, - addSymbol: (String, Int) -> Unit, - deleteSymbol: (Int) -> Unit, + addSymbol: (String) -> Unit, + deleteSymbol: () -> Unit, clearSymbols: () -> Unit, - swap: () -> Unit + swap: () -> Unit, + onCursorChange: (IntRange) -> Unit ) { UnittoTopAppBar( title = stringResource(R.string.epoch_converter), navigateUpAction = navigateUpAction ) { padding -> - var selection: TextRange by remember { mutableStateOf(TextRange.Zero) } - PortraitLandscape( modifier = Modifier.padding(padding), content1 = { topContentModifier -> @@ -74,31 +70,17 @@ private fun EpochScreen( dateToUnix = uiState.dateToUnix, dateValue = uiState.dateField, unixValue = uiState.unixField, - swap = { - swap() - selection = TextRange.Zero - }, - selection = selection, - onCursorChange = { selection = it.selection } + swap = swap, + selection = TextRange(uiState.selection.first, uiState.selection.last), + onCursorChange = onCursorChange ) }, content2 = { bottomModifier -> EpochKeyboard( modifier = bottomModifier, - addSymbol = { - addSymbol(it, selection.start) - selection = TextRange(selection.start + 1) - }, - clearSymbols = { - clearSymbols() - selection = TextRange.Zero - }, - deleteSymbol = { - if (selection.start != 0) { - deleteSymbol(selection.start - 1) - selection = TextRange(selection.start - 1) - } - } + addSymbol = addSymbol, + clearSymbols = clearSymbols, + deleteSymbol = deleteSymbol ) } ) diff --git a/feature/epoch/src/main/java/com/sadellie/unitto/feature/epoch/EpochViewModel.kt b/feature/epoch/src/main/java/com/sadellie/unitto/feature/epoch/EpochViewModel.kt index e86e4118..9c4bdf36 100644 --- a/feature/epoch/src/main/java/com/sadellie/unitto/feature/epoch/EpochViewModel.kt +++ b/feature/epoch/src/main/java/com/sadellie/unitto/feature/epoch/EpochViewModel.kt @@ -28,13 +28,13 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update -import java.lang.Integer.min import javax.inject.Inject data class EpochUIState( val dateField: String = "", val unixField: String = "", - val dateToUnix: Boolean = true + val dateToUnix: Boolean = true, + val selection: IntRange = 0..0 ) @HiltViewModel @@ -42,15 +42,17 @@ class EpochViewModel @Inject constructor() : ViewModel() { private val _input: MutableStateFlow = MutableStateFlow("") private val _fromDateToUnix: MutableStateFlow = MutableStateFlow(true) + private val _selection: MutableStateFlow = MutableStateFlow(IntRange(0, 0)) val uiState: StateFlow = combine( - _input, _fromDateToUnix - ) { input, fromDateToUnix -> + _input, _fromDateToUnix, _selection + ) { input, fromDateToUnix, selection -> if (fromDateToUnix) { EpochUIState( dateField = input, unixField = EpochDateConverter.convertDateToUnix(input), - dateToUnix = fromDateToUnix + dateToUnix = fromDateToUnix, + selection = selection ) } else { val date = try { @@ -62,29 +64,48 @@ class EpochViewModel @Inject constructor() : ViewModel() { EpochUIState( unixField = input, dateField = date, - dateToUnix = fromDateToUnix + dateToUnix = fromDateToUnix, + selection = selection ) } }.stateIn( viewModelScope, SharingStarted.WhileSubscribed(5000L), EpochUIState() ) - fun addSymbol(symbol: String, position: Int) { + fun addSymbol(symbol: String) { + val selection = _selection.value val maxSymbols = if (_fromDateToUnix.value) 14 else 10 if (_input.value.length >= maxSymbols) return - _input.update { it.replaceRange(position, position, symbol) } - } - fun deleteSymbol(position: Int) { - _input.update { - it.removeRange(position, min(position + 1, _input.value.length)) + _input.update { + if (it.isEmpty()) symbol else it.replaceRange(selection.first, selection.last, symbol) } + _selection.update { it.first + 1..it.first + 1 } } - fun clearSymbols() = _input.update { "" } + fun deleteSymbol() { + val selection = _selection.value + val newSelectionStart = when (selection.last) { + 0 -> return + selection.first -> _selection.value.first - 1 + else -> _selection.value.first + } - fun swap() = _fromDateToUnix.update { + _selection.update { newSelectionStart..newSelectionStart } + _input.update { it.removeRange(newSelectionStart, selection.last) } + } + + fun clearSymbols() { + _selection.update { 0..0 } + _input.update { "" } + } + + fun swap() { clearSymbols() - !it + _fromDateToUnix.update { !it } + } + + fun onCursorChange(selectionRange: IntRange) { + _selection.update { selectionRange } } } diff --git a/feature/epoch/src/main/java/com/sadellie/unitto/feature/epoch/component/DateUnixTextFields.kt b/feature/epoch/src/main/java/com/sadellie/unitto/feature/epoch/component/DateUnixTextFields.kt index b89dc02b..736b6077 100644 --- a/feature/epoch/src/main/java/com/sadellie/unitto/feature/epoch/component/DateUnixTextFields.kt +++ b/feature/epoch/src/main/java/com/sadellie/unitto/feature/epoch/component/DateUnixTextFields.kt @@ -33,7 +33,7 @@ import com.sadellie.unitto.core.ui.theme.NumbersTextStyleDisplayMedium @Composable internal fun DateUnixTextFields( fromTextFieldValue: TextFieldValue, - onCursorChange: (TextFieldValue) -> Unit, + onCursorChange: (IntRange) -> Unit, fromSupportText: String, toTextValue: String, toSupportText: String, @@ -47,7 +47,7 @@ internal fun DateUnixTextFields( ) { BasicTextField( value = fromTextFieldValue, - onValueChange = onCursorChange, + onValueChange = { onCursorChange(it.selection.start..it.selection.end) }, textStyle = NumbersTextStyleDisplayMedium.copy( textAlign = TextAlign.Start, color = MaterialTheme.colorScheme.onBackground diff --git a/feature/epoch/src/main/java/com/sadellie/unitto/feature/epoch/component/TopPart.kt b/feature/epoch/src/main/java/com/sadellie/unitto/feature/epoch/component/TopPart.kt index b1190789..d43d1ef2 100644 --- a/feature/epoch/src/main/java/com/sadellie/unitto/feature/epoch/component/TopPart.kt +++ b/feature/epoch/src/main/java/com/sadellie/unitto/feature/epoch/component/TopPart.kt @@ -37,7 +37,7 @@ fun TopPart( dateValue: String, unixValue: String, selection: TextRange, - onCursorChange: (TextFieldValue) -> Unit + onCursorChange: (IntRange) -> Unit ) { Column( modifier = modifier,