Move cursor logic to EpochViewModel.kt

This commit is contained in:
Sad Ellie 2023-02-10 02:08:31 +04:00
parent 55d9ec4327
commit b963cdc644
4 changed files with 52 additions and 49 deletions

View File

@ -20,18 +20,14 @@ package com.sadellie.unitto.feature.epoch
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable 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.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.TextRange
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle 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.PortraitLandscape
import com.sadellie.unitto.core.ui.common.UnittoTopAppBar
import com.sadellie.unitto.feature.epoch.component.EpochKeyboard import com.sadellie.unitto.feature.epoch.component.EpochKeyboard
import com.sadellie.unitto.feature.epoch.component.TopPart import com.sadellie.unitto.feature.epoch.component.TopPart
@ -47,7 +43,8 @@ internal fun EpochRoute(
addSymbol = viewModel::addSymbol, addSymbol = viewModel::addSymbol,
deleteSymbol = viewModel::deleteSymbol, deleteSymbol = viewModel::deleteSymbol,
swap = viewModel::swap, swap = viewModel::swap,
clearSymbols = viewModel::clearSymbols clearSymbols = viewModel::clearSymbols,
onCursorChange = viewModel::onCursorChange
) )
} }
@ -55,17 +52,16 @@ internal fun EpochRoute(
private fun EpochScreen( private fun EpochScreen(
navigateUpAction: () -> Unit, navigateUpAction: () -> Unit,
uiState: EpochUIState, uiState: EpochUIState,
addSymbol: (String, Int) -> Unit, addSymbol: (String) -> Unit,
deleteSymbol: (Int) -> Unit, deleteSymbol: () -> Unit,
clearSymbols: () -> Unit, clearSymbols: () -> Unit,
swap: () -> Unit swap: () -> Unit,
onCursorChange: (IntRange) -> Unit
) { ) {
UnittoTopAppBar( UnittoTopAppBar(
title = stringResource(R.string.epoch_converter), title = stringResource(R.string.epoch_converter),
navigateUpAction = navigateUpAction navigateUpAction = navigateUpAction
) { padding -> ) { padding ->
var selection: TextRange by remember { mutableStateOf(TextRange.Zero) }
PortraitLandscape( PortraitLandscape(
modifier = Modifier.padding(padding), modifier = Modifier.padding(padding),
content1 = { topContentModifier -> content1 = { topContentModifier ->
@ -74,31 +70,17 @@ private fun EpochScreen(
dateToUnix = uiState.dateToUnix, dateToUnix = uiState.dateToUnix,
dateValue = uiState.dateField, dateValue = uiState.dateField,
unixValue = uiState.unixField, unixValue = uiState.unixField,
swap = { swap = swap,
swap() selection = TextRange(uiState.selection.first, uiState.selection.last),
selection = TextRange.Zero onCursorChange = onCursorChange
},
selection = selection,
onCursorChange = { selection = it.selection }
) )
}, },
content2 = { bottomModifier -> content2 = { bottomModifier ->
EpochKeyboard( EpochKeyboard(
modifier = bottomModifier, modifier = bottomModifier,
addSymbol = { addSymbol = addSymbol,
addSymbol(it, selection.start) clearSymbols = clearSymbols,
selection = TextRange(selection.start + 1) deleteSymbol = deleteSymbol
},
clearSymbols = {
clearSymbols()
selection = TextRange.Zero
},
deleteSymbol = {
if (selection.start != 0) {
deleteSymbol(selection.start - 1)
selection = TextRange(selection.start - 1)
}
}
) )
} }
) )

View File

@ -28,13 +28,13 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import java.lang.Integer.min
import javax.inject.Inject import javax.inject.Inject
data class EpochUIState( data class EpochUIState(
val dateField: String = "", val dateField: String = "",
val unixField: String = "", val unixField: String = "",
val dateToUnix: Boolean = true val dateToUnix: Boolean = true,
val selection: IntRange = 0..0
) )
@HiltViewModel @HiltViewModel
@ -42,15 +42,17 @@ class EpochViewModel @Inject constructor() : ViewModel() {
private val _input: MutableStateFlow<String> = MutableStateFlow("") private val _input: MutableStateFlow<String> = MutableStateFlow("")
private val _fromDateToUnix: MutableStateFlow<Boolean> = MutableStateFlow(true) private val _fromDateToUnix: MutableStateFlow<Boolean> = MutableStateFlow(true)
private val _selection: MutableStateFlow<IntRange> = MutableStateFlow(IntRange(0, 0))
val uiState: StateFlow<EpochUIState> = combine( val uiState: StateFlow<EpochUIState> = combine(
_input, _fromDateToUnix _input, _fromDateToUnix, _selection
) { input, fromDateToUnix -> ) { input, fromDateToUnix, selection ->
if (fromDateToUnix) { if (fromDateToUnix) {
EpochUIState( EpochUIState(
dateField = input, dateField = input,
unixField = EpochDateConverter.convertDateToUnix(input), unixField = EpochDateConverter.convertDateToUnix(input),
dateToUnix = fromDateToUnix dateToUnix = fromDateToUnix,
selection = selection
) )
} else { } else {
val date = try { val date = try {
@ -62,29 +64,48 @@ class EpochViewModel @Inject constructor() : ViewModel() {
EpochUIState( EpochUIState(
unixField = input, unixField = input,
dateField = date, dateField = date,
dateToUnix = fromDateToUnix dateToUnix = fromDateToUnix,
selection = selection
) )
} }
}.stateIn( }.stateIn(
viewModelScope, SharingStarted.WhileSubscribed(5000L), EpochUIState() 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 val maxSymbols = if (_fromDateToUnix.value) 14 else 10
if (_input.value.length >= maxSymbols) return if (_input.value.length >= maxSymbols) return
_input.update { it.replaceRange(position, position, symbol) }
}
fun deleteSymbol(position: Int) { _input.update {
_input.update { if (it.isEmpty()) symbol else it.replaceRange(selection.first, selection.last, symbol)
it.removeRange(position, min(position + 1, _input.value.length))
} }
_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() clearSymbols()
!it _fromDateToUnix.update { !it }
}
fun onCursorChange(selectionRange: IntRange) {
_selection.update { selectionRange }
} }
} }

View File

@ -33,7 +33,7 @@ import com.sadellie.unitto.core.ui.theme.NumbersTextStyleDisplayMedium
@Composable @Composable
internal fun DateUnixTextFields( internal fun DateUnixTextFields(
fromTextFieldValue: TextFieldValue, fromTextFieldValue: TextFieldValue,
onCursorChange: (TextFieldValue) -> Unit, onCursorChange: (IntRange) -> Unit,
fromSupportText: String, fromSupportText: String,
toTextValue: String, toTextValue: String,
toSupportText: String, toSupportText: String,
@ -47,7 +47,7 @@ internal fun DateUnixTextFields(
) { ) {
BasicTextField( BasicTextField(
value = fromTextFieldValue, value = fromTextFieldValue,
onValueChange = onCursorChange, onValueChange = { onCursorChange(it.selection.start..it.selection.end) },
textStyle = NumbersTextStyleDisplayMedium.copy( textStyle = NumbersTextStyleDisplayMedium.copy(
textAlign = TextAlign.Start, textAlign = TextAlign.Start,
color = MaterialTheme.colorScheme.onBackground color = MaterialTheme.colorScheme.onBackground

View File

@ -37,7 +37,7 @@ fun TopPart(
dateValue: String, dateValue: String,
unixValue: String, unixValue: String,
selection: TextRange, selection: TextRange,
onCursorChange: (TextFieldValue) -> Unit onCursorChange: (IntRange) -> Unit
) { ) {
Column( Column(
modifier = modifier, modifier = modifier,