mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-18 16:25:27 +02:00
Refactor unit selector screens
decrease duplicate logic in ConverterViewModel
This commit is contained in:
parent
9d76c168ec
commit
7cbbb846af
@ -154,5 +154,45 @@ fun <T1, T2, T3, T4, T5, T6, T7, T8, T9, R> combine(
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST", "UNUSED")
|
||||
fun <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R> combine(
|
||||
flow: Flow<T1>,
|
||||
flow2: Flow<T2>,
|
||||
flow3: Flow<T3>,
|
||||
flow4: Flow<T4>,
|
||||
flow5: Flow<T5>,
|
||||
flow6: Flow<T6>,
|
||||
flow7: Flow<T7>,
|
||||
flow8: Flow<T8>,
|
||||
flow9: Flow<T9>,
|
||||
flow10: Flow<T10>,
|
||||
transform: suspend (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) -> R,
|
||||
): Flow<R> =
|
||||
kotlinx.coroutines.flow.combine(
|
||||
flow,
|
||||
flow2,
|
||||
flow3,
|
||||
flow4,
|
||||
flow5,
|
||||
flow6,
|
||||
flow7,
|
||||
flow8,
|
||||
flow9,
|
||||
flow10
|
||||
) { args: Array<*> ->
|
||||
transform(
|
||||
args[0] as T1,
|
||||
args[1] as T2,
|
||||
args[2] as T3,
|
||||
args[3] as T4,
|
||||
args[4] as T5,
|
||||
args[5] as T6,
|
||||
args[6] as T7,
|
||||
args[7] as T8,
|
||||
args[8] as T9,
|
||||
args[9] as T10,
|
||||
)
|
||||
}
|
||||
|
||||
fun <T> Flow<T>.stateIn(scope: CoroutineScope, initialValue: T): StateFlow<T> =
|
||||
stateIn(scope, SharingStarted.WhileSubscribed(5000L), initialValue)
|
||||
|
@ -97,8 +97,8 @@ import java.util.Locale
|
||||
@Composable
|
||||
internal fun ConverterRoute(
|
||||
viewModel: ConverterViewModel = hiltViewModel(),
|
||||
navigateToLeftScreen: () -> Unit,
|
||||
navigateToRightScreen: () -> Unit,
|
||||
navigateToLeftScreen: (uiState: UnitConverterUIState) -> Unit,
|
||||
navigateToRightScreen: (uiState: UnitConverterUIState) -> Unit,
|
||||
navigateToMenu: () -> Unit,
|
||||
navigateToSettings: () -> Unit,
|
||||
) {
|
||||
@ -124,8 +124,8 @@ internal fun ConverterRoute(
|
||||
@Composable
|
||||
private fun ConverterScreen(
|
||||
uiState: UnitConverterUIState,
|
||||
navigateToLeftScreen: () -> Unit,
|
||||
navigateToRightScreen: () -> Unit,
|
||||
navigateToLeftScreen: (uiState: UnitConverterUIState) -> Unit,
|
||||
navigateToRightScreen: (uiState: UnitConverterUIState) -> Unit,
|
||||
navigateToSettings: () -> Unit,
|
||||
navigateToMenu: () -> Unit,
|
||||
swapUnits: () -> Unit,
|
||||
@ -207,9 +207,9 @@ private fun NumberBase(
|
||||
onValueChange: (TextFieldValue) -> Unit,
|
||||
processInput: (String) -> Unit,
|
||||
deleteDigit: () -> Unit,
|
||||
navigateToLeftScreen: () -> Unit,
|
||||
navigateToLeftScreen: (uiState: UnitConverterUIState) -> Unit,
|
||||
swapUnits: () -> Unit,
|
||||
navigateToRightScreen: () -> Unit,
|
||||
navigateToRightScreen: (uiState: UnitConverterUIState) -> Unit,
|
||||
clearInput: () -> Unit,
|
||||
) {
|
||||
PortraitLandscape(
|
||||
@ -239,8 +239,8 @@ private fun NumberBase(
|
||||
unitFromLabel = stringResource(uiState.unitFrom.displayName),
|
||||
unitToLabel = stringResource(uiState.unitTo.displayName),
|
||||
swapUnits = swapUnits,
|
||||
navigateToLeftScreen = navigateToLeftScreen,
|
||||
navigateToRightScreen = navigateToRightScreen
|
||||
navigateToLeftScreen = { navigateToLeftScreen(uiState) },
|
||||
navigateToRightScreen = { navigateToRightScreen(uiState) }
|
||||
)
|
||||
}
|
||||
},
|
||||
@ -263,9 +263,9 @@ private fun Default(
|
||||
onFocusOnInput2: (Boolean) -> Unit,
|
||||
processInput: (String) -> Unit,
|
||||
deleteDigit: () -> Unit,
|
||||
navigateToLeftScreen: () -> Unit,
|
||||
navigateToLeftScreen: (uiState: UnitConverterUIState) -> Unit,
|
||||
swapUnits: () -> Unit,
|
||||
navigateToRightScreen: () -> Unit,
|
||||
navigateToRightScreen: (uiState: UnitConverterUIState) -> Unit,
|
||||
clearInput: () -> Unit,
|
||||
refreshCurrencyRates: (AbstractUnit) -> Unit,
|
||||
addBracket: () -> Unit,
|
||||
@ -327,7 +327,9 @@ private fun Default(
|
||||
.weight(1f)
|
||||
) {
|
||||
ExpressionTextField(
|
||||
modifier = Modifier.fillMaxWidth().weight(1f),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f),
|
||||
value = uiState.input1,
|
||||
minRatio = 0.7f,
|
||||
onValueChange = onValueChange,
|
||||
@ -345,7 +347,9 @@ private fun Default(
|
||||
.weight(1f)
|
||||
) {
|
||||
ExpressionTextField(
|
||||
modifier = Modifier.fillMaxWidth().weight(1f)
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
.onFocusEvent { state -> onFocusOnInput2(state.hasFocus) },
|
||||
value = uiState.input2,
|
||||
minRatio = 0.7f,
|
||||
@ -405,8 +409,8 @@ private fun Default(
|
||||
unitFromLabel = stringResource(uiState.unitFrom.displayName),
|
||||
unitToLabel = stringResource(uiState.unitTo.displayName),
|
||||
swapUnits = swapUnits,
|
||||
navigateToLeftScreen = navigateToLeftScreen,
|
||||
navigateToRightScreen = navigateToRightScreen
|
||||
navigateToLeftScreen = { navigateToLeftScreen(uiState) },
|
||||
navigateToRightScreen = { navigateToRightScreen(uiState) }
|
||||
)
|
||||
}
|
||||
},
|
||||
|
@ -33,7 +33,6 @@ import com.sadellie.unitto.data.common.isExpression
|
||||
import com.sadellie.unitto.data.common.stateIn
|
||||
import com.sadellie.unitto.data.converter.UnitID
|
||||
import com.sadellie.unitto.data.model.UnitGroup
|
||||
import com.sadellie.unitto.data.model.UnitsListSorting
|
||||
import com.sadellie.unitto.data.model.repository.UnitsRepository
|
||||
import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
|
||||
import com.sadellie.unitto.data.model.unit.AbstractUnit
|
||||
@ -45,12 +44,10 @@ import io.github.sadellie.evaluatto.ExpressionException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.getAndUpdate
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -74,13 +71,6 @@ internal class ConverterViewModel @Inject constructor(
|
||||
private val _unitFrom = MutableStateFlow<AbstractUnit?>(null)
|
||||
private val _unitTo = MutableStateFlow<AbstractUnit?>(null)
|
||||
|
||||
private val _leftQuery = MutableStateFlow(TextFieldValue())
|
||||
private val _leftUnits = MutableStateFlow<Map<UnitGroup, List<AbstractUnit>>>(emptyMap())
|
||||
private val _leftUnitGroup = MutableStateFlow<UnitGroup?>(null)
|
||||
|
||||
private val _rightQuery = MutableStateFlow(TextFieldValue())
|
||||
private val _rightUnits = MutableStateFlow<Map<UnitGroup, List<AbstractUnit>>>(emptyMap())
|
||||
|
||||
private val _currenciesState = MutableStateFlow<CurrencyRateUpdateState>(CurrencyRateUpdateState.Nothing)
|
||||
private var _loadCurrenciesJob: Job? = null
|
||||
|
||||
@ -160,81 +150,6 @@ internal class ConverterViewModel @Inject constructor(
|
||||
}
|
||||
.stateIn(viewModelScope, UnitConverterUIState.Loading)
|
||||
|
||||
val leftSideUIState = combine(
|
||||
_unitFrom,
|
||||
_leftQuery,
|
||||
_leftUnits,
|
||||
_leftUnitGroup,
|
||||
userPrefsRepository.converterPrefs,
|
||||
unitsRepo.units
|
||||
) { unitFrom, query, units, unitGroup, prefs, _ ->
|
||||
unitFrom ?: return@combine LeftSideUIState.Loading
|
||||
|
||||
return@combine LeftSideUIState.Ready(
|
||||
unitFrom = unitFrom,
|
||||
sorting = prefs.unitConverterSorting,
|
||||
shownUnitGroups = prefs.shownUnitGroups,
|
||||
favorites = prefs.unitConverterFavoritesOnly,
|
||||
query = query,
|
||||
units = units,
|
||||
unitGroup = unitGroup
|
||||
)
|
||||
}
|
||||
.mapLatest {
|
||||
if (it !is LeftSideUIState.Ready) return@mapLatest it
|
||||
|
||||
filterUnitsLeft(
|
||||
query = it.query,
|
||||
unitGroup = it.unitGroup,
|
||||
favoritesOnly = it.favorites,
|
||||
sorting = it.sorting,
|
||||
shownUnitGroups = it.shownUnitGroups,
|
||||
)
|
||||
it
|
||||
}
|
||||
.stateIn(viewModelScope, SharingStarted.Lazily, LeftSideUIState.Loading)
|
||||
|
||||
val rightSideUIState = combine(
|
||||
_unitFrom,
|
||||
_unitTo,
|
||||
_input1,
|
||||
_calculation,
|
||||
_rightQuery,
|
||||
_rightUnits,
|
||||
userPrefsRepository.converterPrefs,
|
||||
_currenciesState,
|
||||
unitsRepo.units,
|
||||
) { unitFrom, unitTo, input, calculation, query, units, prefs, currenciesState, _ ->
|
||||
unitFrom ?: return@combine RightSideUIState.Loading
|
||||
unitTo ?: return@combine RightSideUIState.Loading
|
||||
|
||||
return@combine RightSideUIState.Ready(
|
||||
unitFrom = unitFrom,
|
||||
unitTo = unitTo,
|
||||
sorting = prefs.unitConverterSorting,
|
||||
favorites = prefs.unitConverterFavoritesOnly,
|
||||
input = (calculation?.toPlainString() ?: input.text).replace(Token.Operator.minus, "-"),
|
||||
scale = prefs.precision,
|
||||
outputFormat = prefs.outputFormat,
|
||||
formatterSymbols = AllFormatterSymbols.getById(prefs.separator),
|
||||
currencyRateUpdateState = currenciesState,
|
||||
query = query,
|
||||
units = units,
|
||||
)
|
||||
}
|
||||
.mapLatest {
|
||||
if (it !is RightSideUIState.Ready) return@mapLatest it
|
||||
|
||||
filterUnitsRight(
|
||||
query = it.query,
|
||||
unitGroup = it.unitFrom.group,
|
||||
favoritesOnly = it.favorites,
|
||||
sorting = it.sorting,
|
||||
)
|
||||
it
|
||||
}
|
||||
.stateIn(viewModelScope, SharingStarted.Lazily, RightSideUIState.Loading)
|
||||
|
||||
fun swapUnits() {
|
||||
_unitFrom
|
||||
.getAndUpdate { _unitTo.value }
|
||||
@ -380,56 +295,6 @@ internal class ConverterViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun queryChangeLeft(query: TextFieldValue) = _leftQuery.update { query }
|
||||
|
||||
fun queryChangeRight(query: TextFieldValue) = _rightQuery.update { query }
|
||||
|
||||
fun favoritesOnlyChange(enabled: Boolean) = viewModelScope.launch {
|
||||
userPrefsRepository.updateUnitConverterFavoritesOnly(enabled)
|
||||
}
|
||||
|
||||
fun updateUnitGroupLeft(unitGroup: UnitGroup?) = _leftUnitGroup.update { unitGroup }
|
||||
|
||||
fun favoriteUnit(unit: AbstractUnit) = viewModelScope.launch {
|
||||
unitsRepo.favorite(unit)
|
||||
}
|
||||
|
||||
private fun filterUnitsLeft(
|
||||
query: TextFieldValue,
|
||||
unitGroup: UnitGroup?,
|
||||
favoritesOnly: Boolean,
|
||||
sorting: UnitsListSorting,
|
||||
shownUnitGroups: List<UnitGroup>,
|
||||
) = viewModelScope.launch(Dispatchers.Default) {
|
||||
_leftUnits.update {
|
||||
unitsRepo.filterUnits(
|
||||
query = query.text,
|
||||
unitGroup = unitGroup,
|
||||
favoritesOnly = favoritesOnly,
|
||||
hideBrokenUnits = false,
|
||||
sorting = sorting,
|
||||
shownUnitGroups = shownUnitGroups
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun filterUnitsRight(
|
||||
query: TextFieldValue,
|
||||
unitGroup: UnitGroup?,
|
||||
favoritesOnly: Boolean,
|
||||
sorting: UnitsListSorting,
|
||||
) = viewModelScope.launch(Dispatchers.Default) {
|
||||
_rightUnits.update {
|
||||
unitsRepo.filterUnits(
|
||||
query = query.text,
|
||||
unitGroup = unitGroup,
|
||||
favoritesOnly = favoritesOnly,
|
||||
hideBrokenUnits = true,
|
||||
sorting = sorting,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertDefault(
|
||||
unitFrom: DefaultUnit,
|
||||
unitTo: DefaultUnit,
|
||||
|
@ -1,38 +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.feature.converter
|
||||
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import com.sadellie.unitto.data.model.UnitGroup
|
||||
import com.sadellie.unitto.data.model.UnitsListSorting
|
||||
import com.sadellie.unitto.data.model.unit.AbstractUnit
|
||||
|
||||
internal sealed class LeftSideUIState {
|
||||
data object Loading : LeftSideUIState()
|
||||
|
||||
data class Ready(
|
||||
val unitFrom: AbstractUnit,
|
||||
val query: TextFieldValue,
|
||||
val units: Map<UnitGroup, List<AbstractUnit>> = emptyMap(),
|
||||
val favorites: Boolean,
|
||||
val shownUnitGroups: List<UnitGroup>,
|
||||
val unitGroup: UnitGroup?,
|
||||
val sorting: UnitsListSorting,
|
||||
) : LeftSideUIState()
|
||||
}
|
@ -49,31 +49,32 @@ import com.sadellie.unitto.feature.converter.components.UnitsList
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Composable
|
||||
internal fun LeftSideRoute(
|
||||
viewModel: ConverterViewModel,
|
||||
internal fun UnitFromSelectorRoute(
|
||||
unitSelectorViewModel: UnitSelectorViewModel,
|
||||
converterViewModel: ConverterViewModel,
|
||||
navigateUp: () -> Unit,
|
||||
navigateToUnitGroups: () -> Unit,
|
||||
) {
|
||||
when (
|
||||
val uiState = viewModel.leftSideUIState.collectAsStateWithLifecycle().value
|
||||
val uiState = unitSelectorViewModel.unitFromUIState.collectAsStateWithLifecycle().value
|
||||
) {
|
||||
is LeftSideUIState.Loading -> EmptyScreen()
|
||||
is LeftSideUIState.Ready -> LeftSideScreen(
|
||||
is UnitSelectorUIState.UnitFrom -> UnitFromSelectorScreen(
|
||||
uiState = uiState,
|
||||
onQueryChange = viewModel::queryChangeLeft,
|
||||
toggleFavoritesOnly = viewModel::favoritesOnlyChange,
|
||||
updateUnitFrom = viewModel::updateUnitFrom,
|
||||
updateUnitGroup = viewModel::updateUnitGroupLeft,
|
||||
favoriteUnit = viewModel::favoriteUnit,
|
||||
onQueryChange = unitSelectorViewModel::updateSelectorQuery,
|
||||
toggleFavoritesOnly = unitSelectorViewModel::updateShowFavoritesOnly,
|
||||
updateUnitFrom = converterViewModel::updateUnitFrom,
|
||||
updateUnitGroup = unitSelectorViewModel::updateSelectedUnitGroup,
|
||||
favoriteUnit = unitSelectorViewModel::favoriteUnit,
|
||||
navigateUp = navigateUp,
|
||||
navigateToUnitGroups = navigateToUnitGroups,
|
||||
)
|
||||
else -> EmptyScreen()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LeftSideScreen(
|
||||
uiState: LeftSideUIState.Ready,
|
||||
private fun UnitFromSelectorScreen(
|
||||
uiState: UnitSelectorUIState.UnitFrom,
|
||||
onQueryChange: (TextFieldValue) -> Unit,
|
||||
toggleFavoritesOnly: (Boolean) -> Unit,
|
||||
updateUnitFrom: (AbstractUnit) -> Unit,
|
||||
@ -87,8 +88,6 @@ private fun LeftSideScreen(
|
||||
val chipsRowLazyListState = rememberLazyListState()
|
||||
|
||||
LaunchedEffect(uiState.unitFrom, uiState.shownUnitGroups) {
|
||||
updateUnitGroup(uiState.unitFrom.group)
|
||||
|
||||
kotlin.runCatching {
|
||||
val groupToSelect = uiState.shownUnitGroups.indexOf(uiState.unitFrom.group)
|
||||
if (groupToSelect > -1) {
|
||||
@ -108,8 +107,8 @@ private fun LeftSideScreen(
|
||||
onQueryChange = onQueryChange,
|
||||
navigateUp = navigateUp,
|
||||
trailingIcon = {
|
||||
FavoritesButton(uiState.favorites) {
|
||||
toggleFavoritesOnly(!uiState.favorites)
|
||||
FavoritesButton(uiState.showFavoritesOnly) {
|
||||
toggleFavoritesOnly(!uiState.showFavoritesOnly)
|
||||
}
|
||||
},
|
||||
scrollBehavior = scrollBehavior
|
||||
@ -119,7 +118,7 @@ private fun LeftSideScreen(
|
||||
modifier = Modifier
|
||||
.padding(start = 8.dp, end = 8.dp, bottom = 4.dp)
|
||||
.fillMaxWidth(),
|
||||
chosenUnitGroup = uiState.unitGroup,
|
||||
chosenUnitGroup = uiState.selectedUnitGroup,
|
||||
items = uiState.shownUnitGroups,
|
||||
selectAction = updateUnitGroup,
|
||||
navigateToSettingsAction = navigateToUnitGroups
|
||||
@ -130,7 +129,7 @@ private fun LeftSideScreen(
|
||||
val resources = LocalContext.current.resources
|
||||
UnitsList(
|
||||
modifier = Modifier.padding(paddingValues),
|
||||
groupedUnits = uiState.units,
|
||||
searchResult = uiState.units,
|
||||
navigateToUnitGroups = navigateToUnitGroups,
|
||||
currentUnitId = uiState.unitFrom.id,
|
||||
supportLabel = { resources.getString(it.shortName) },
|
||||
@ -146,7 +145,7 @@ private fun LeftSideScreen(
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun LeftSideScreenPreview() {
|
||||
private fun UnitFromSelectorScreenPreview() {
|
||||
val units: Map<UnitGroup, List<AbstractUnit>> = mapOf(
|
||||
UnitGroup.LENGTH to listOf(
|
||||
NormalUnit(UnitID.meter, BigDecimal.valueOf(1.0E+18), UnitGroup.LENGTH, R.string.unit_meter, R.string.unit_meter_short),
|
||||
@ -159,14 +158,14 @@ private fun LeftSideScreenPreview() {
|
||||
)
|
||||
)
|
||||
|
||||
LeftSideScreen(
|
||||
uiState = LeftSideUIState.Ready(
|
||||
UnitFromSelectorScreen(
|
||||
uiState = UnitSelectorUIState.UnitFrom(
|
||||
unitFrom = units.values.first().first(),
|
||||
units = units,
|
||||
query = TextFieldValue("test"),
|
||||
favorites = false,
|
||||
units = UnitSearchResult.Success(units),
|
||||
selectedUnitGroup = UnitGroup.SPEED,
|
||||
shownUnitGroups = UnitGroup.entries,
|
||||
unitGroup = units.keys.toList().first(),
|
||||
showFavoritesOnly = false,
|
||||
sorting = UnitsListSorting.USAGE,
|
||||
),
|
||||
onQueryChange = {},
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Unitto is a calculator for Android
|
||||
* Copyright (c) 2023-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
|
||||
@ -24,20 +24,39 @@ import com.sadellie.unitto.data.model.UnitGroup
|
||||
import com.sadellie.unitto.data.model.UnitsListSorting
|
||||
import com.sadellie.unitto.data.model.unit.AbstractUnit
|
||||
|
||||
internal sealed class RightSideUIState {
|
||||
data object Loading : RightSideUIState()
|
||||
internal sealed class UnitSelectorUIState {
|
||||
data object Loading : UnitSelectorUIState()
|
||||
|
||||
data class Ready(
|
||||
data class UnitFrom(
|
||||
val query: TextFieldValue,
|
||||
val unitFrom: AbstractUnit,
|
||||
val shownUnitGroups: List<UnitGroup>,
|
||||
val showFavoritesOnly: Boolean,
|
||||
val units: UnitSearchResult,
|
||||
val selectedUnitGroup: UnitGroup?,
|
||||
val sorting: UnitsListSorting,
|
||||
) : UnitSelectorUIState()
|
||||
|
||||
data class UnitTo(
|
||||
val query: TextFieldValue,
|
||||
val unitFrom: AbstractUnit,
|
||||
val unitTo: AbstractUnit,
|
||||
val query: TextFieldValue,
|
||||
val units: Map<UnitGroup, List<AbstractUnit>>,
|
||||
val favorites: Boolean,
|
||||
val showFavoritesOnly: Boolean,
|
||||
val units: UnitSearchResult,
|
||||
val input: String?,
|
||||
val sorting: UnitsListSorting,
|
||||
val input: String,
|
||||
val scale: Int,
|
||||
val outputFormat: Int,
|
||||
val formatterSymbols: FormatterSymbols,
|
||||
val currencyRateUpdateState: CurrencyRateUpdateState,
|
||||
) : RightSideUIState()
|
||||
) : UnitSelectorUIState()
|
||||
}
|
||||
|
||||
internal sealed class UnitSearchResult {
|
||||
data object Empty : UnitSearchResult()
|
||||
|
||||
data object Loading : UnitSearchResult()
|
||||
|
||||
data class Success(
|
||||
val units: Map<UnitGroup, List<AbstractUnit>>
|
||||
) : UnitSearchResult()
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Unitto is a calculator for Android
|
||||
* 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
|
||||
* 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.feature.converter
|
||||
|
||||
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
|
||||
import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
|
||||
import com.sadellie.unitto.data.model.unit.AbstractUnit
|
||||
import com.sadellie.unitto.feature.converter.navigation.inputArg
|
||||
import com.sadellie.unitto.feature.converter.navigation.unitFromIdArg
|
||||
import com.sadellie.unitto.feature.converter.navigation.unitGroupArg
|
||||
import com.sadellie.unitto.feature.converter.navigation.unitToIdArg
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
internal class UnitSelectorViewModel @Inject constructor(
|
||||
private val userPrefsRepository: UserPreferencesRepository,
|
||||
private val unitsRepo: UnitsRepository,
|
||||
savedStateHandle: SavedStateHandle
|
||||
) : ViewModel() {
|
||||
private val _query = MutableStateFlow(TextFieldValue())
|
||||
private val _searchResults = MutableStateFlow<UnitSearchResult>(UnitSearchResult.Loading)
|
||||
private val _selectedUnitGroup = MutableStateFlow(savedStateHandle.get<UnitGroup>(unitGroupArg))
|
||||
private val _unitFromId = savedStateHandle.get<String>(unitFromIdArg)
|
||||
private val _unitToId = savedStateHandle.get<String>(unitToIdArg)
|
||||
private val _input = savedStateHandle.get<String>(inputArg)
|
||||
|
||||
val unitFromUIState: StateFlow<UnitSelectorUIState> = combine(
|
||||
_query,
|
||||
_searchResults,
|
||||
_selectedUnitGroup,
|
||||
userPrefsRepository.converterPrefs,
|
||||
) { query, searchResults, selectedUnitGroup, prefs ->
|
||||
if (_unitFromId.isNullOrEmpty()) return@combine UnitSelectorUIState.Loading
|
||||
|
||||
return@combine UnitSelectorUIState.UnitFrom(
|
||||
query = query,
|
||||
unitFrom = unitsRepo.getById(_unitFromId),
|
||||
shownUnitGroups = prefs.shownUnitGroups,
|
||||
showFavoritesOnly = prefs.unitConverterFavoritesOnly,
|
||||
units = searchResults,
|
||||
selectedUnitGroup = selectedUnitGroup,
|
||||
sorting = prefs.unitConverterSorting,
|
||||
)
|
||||
}
|
||||
.mapLatest { ui ->
|
||||
if (ui is UnitSelectorUIState.UnitFrom) {
|
||||
_searchResults.update {
|
||||
val result = unitsRepo.filterUnits(
|
||||
query = ui.query.text,
|
||||
unitGroup = ui.selectedUnitGroup,
|
||||
favoritesOnly = ui.showFavoritesOnly,
|
||||
hideBrokenUnits = false,
|
||||
sorting = ui.sorting,
|
||||
shownUnitGroups = ui.shownUnitGroups
|
||||
)
|
||||
|
||||
if (result.isEmpty()) UnitSearchResult.Empty else UnitSearchResult.Success(result)
|
||||
}
|
||||
}
|
||||
|
||||
ui
|
||||
}
|
||||
.stateIn(viewModelScope, UnitSelectorUIState.Loading)
|
||||
|
||||
val unitToUIState: StateFlow<UnitSelectorUIState> = combine(
|
||||
_query,
|
||||
_searchResults,
|
||||
userPrefsRepository.converterPrefs,
|
||||
unitsRepo.units,
|
||||
) { query, searchResults, prefs, _ ->
|
||||
if (_unitFromId.isNullOrEmpty()) return@combine UnitSelectorUIState.Loading
|
||||
if (_unitToId.isNullOrEmpty()) return@combine UnitSelectorUIState.Loading
|
||||
|
||||
UnitSelectorUIState.UnitTo(
|
||||
query = query,
|
||||
unitFrom = unitsRepo.getById(_unitFromId),
|
||||
unitTo = unitsRepo.getById(_unitToId),
|
||||
showFavoritesOnly = prefs.unitConverterFavoritesOnly,
|
||||
units = searchResults,
|
||||
input = _input,
|
||||
sorting = prefs.unitConverterSorting,
|
||||
scale = prefs.precision,
|
||||
outputFormat = prefs.outputFormat,
|
||||
formatterSymbols = AllFormatterSymbols.getById(prefs.separator),
|
||||
)
|
||||
}
|
||||
.mapLatest { ui ->
|
||||
if (ui is UnitSelectorUIState.UnitTo) {
|
||||
_searchResults.update {
|
||||
if (ui.unitFrom.group == UnitGroup.CURRENCY) unitsRepo.updateRates(ui.unitFrom)
|
||||
|
||||
val result = unitsRepo.filterUnits(
|
||||
query = ui.query.text,
|
||||
unitGroup = ui.unitFrom.group,
|
||||
favoritesOnly = ui.showFavoritesOnly,
|
||||
hideBrokenUnits = true,
|
||||
sorting = ui.sorting,
|
||||
)
|
||||
|
||||
if (result.isEmpty()) UnitSearchResult.Empty else UnitSearchResult.Success(result)
|
||||
}
|
||||
}
|
||||
ui
|
||||
}
|
||||
.stateIn(viewModelScope, UnitSelectorUIState.Loading)
|
||||
|
||||
fun updateSelectorQuery(value: TextFieldValue) = _query.update { value }
|
||||
|
||||
fun updateShowFavoritesOnly(value: Boolean) = viewModelScope.launch {
|
||||
userPrefsRepository.updateUnitConverterFavoritesOnly(value)
|
||||
}
|
||||
|
||||
fun updateSelectedUnitGroup(value: UnitGroup?) = _selectedUnitGroup.update { value }
|
||||
|
||||
fun favoriteUnit(unit: AbstractUnit) = viewModelScope.launch(Dispatchers.IO) {
|
||||
unitsRepo.favorite(unit)
|
||||
}
|
||||
}
|
@ -47,31 +47,31 @@ import com.sadellie.unitto.feature.converter.components.UnitsList
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Composable
|
||||
internal fun RightSideRoute(
|
||||
viewModel: ConverterViewModel,
|
||||
internal fun UnitToSelectorRoute(
|
||||
unitSelectorViewModel: UnitSelectorViewModel,
|
||||
converterViewModel: ConverterViewModel,
|
||||
navigateUp: () -> Unit,
|
||||
navigateToUnitGroups: () -> Unit,
|
||||
) {
|
||||
when (
|
||||
val uiState = viewModel.rightSideUIState.collectAsStateWithLifecycle().value
|
||||
val uiState = unitSelectorViewModel.unitToUIState.collectAsStateWithLifecycle().value
|
||||
) {
|
||||
is RightSideUIState.Loading -> EmptyScreen()
|
||||
is RightSideUIState.Ready ->
|
||||
RightSideScreen(
|
||||
uiState = uiState,
|
||||
onQueryChange = viewModel::queryChangeRight,
|
||||
toggleFavoritesOnly = viewModel::favoritesOnlyChange,
|
||||
updateUnitTo = viewModel::updateUnitTo,
|
||||
favoriteUnit = viewModel::favoriteUnit,
|
||||
navigateUp = navigateUp,
|
||||
navigateToUnitGroups = navigateToUnitGroups,
|
||||
)
|
||||
is UnitSelectorUIState.UnitTo -> UnitToSelectorScreen(
|
||||
uiState = uiState,
|
||||
onQueryChange = unitSelectorViewModel::updateSelectorQuery,
|
||||
toggleFavoritesOnly = unitSelectorViewModel::updateShowFavoritesOnly,
|
||||
updateUnitTo = converterViewModel::updateUnitTo,
|
||||
favoriteUnit = unitSelectorViewModel::favoriteUnit,
|
||||
navigateUp = navigateUp,
|
||||
navigateToUnitGroups = navigateToUnitGroups,
|
||||
)
|
||||
else -> EmptyScreen()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RightSideScreen(
|
||||
uiState: RightSideUIState.Ready,
|
||||
private fun UnitToSelectorScreen(
|
||||
uiState: UnitSelectorUIState.UnitTo,
|
||||
onQueryChange: (TextFieldValue) -> Unit,
|
||||
toggleFavoritesOnly: (Boolean) -> Unit,
|
||||
updateUnitTo: (AbstractUnit) -> Unit,
|
||||
@ -89,8 +89,8 @@ private fun RightSideScreen(
|
||||
onQueryChange = onQueryChange,
|
||||
navigateUp = navigateUp,
|
||||
trailingIcon = {
|
||||
FavoritesButton(uiState.favorites) {
|
||||
toggleFavoritesOnly(!uiState.favorites)
|
||||
FavoritesButton(uiState.showFavoritesOnly) {
|
||||
toggleFavoritesOnly(!uiState.showFavoritesOnly)
|
||||
}
|
||||
},
|
||||
scrollBehavior = scrollBehavior
|
||||
@ -100,7 +100,7 @@ private fun RightSideScreen(
|
||||
val resources = LocalContext.current.resources
|
||||
UnitsList(
|
||||
modifier = Modifier.padding(paddingValues),
|
||||
groupedUnits = uiState.units,
|
||||
searchResult = uiState.units,
|
||||
navigateToUnitGroups = navigateToUnitGroups,
|
||||
currentUnitId = uiState.unitTo.id,
|
||||
supportLabel = {
|
||||
@ -112,7 +112,6 @@ private fun RightSideScreen(
|
||||
scale = uiState.scale,
|
||||
outputFormat = uiState.outputFormat,
|
||||
formatterSymbols = uiState.formatterSymbols,
|
||||
readyCurrencies = uiState.currencyRateUpdateState is CurrencyRateUpdateState.Ready,
|
||||
)
|
||||
},
|
||||
onClick = {
|
||||
@ -128,15 +127,13 @@ private fun RightSideScreen(
|
||||
private fun formatUnitToSupportLabel(
|
||||
unitFrom: AbstractUnit?,
|
||||
unitTo: AbstractUnit?,
|
||||
input: String,
|
||||
input: String?,
|
||||
shortName: String,
|
||||
scale: Int,
|
||||
outputFormat: Int,
|
||||
formatterSymbols: FormatterSymbols,
|
||||
readyCurrencies: Boolean,
|
||||
): String {
|
||||
if ((unitFrom?.group == UnitGroup.CURRENCY) and !readyCurrencies) return shortName
|
||||
if (input.isEmpty()) return shortName
|
||||
if (input.isNullOrEmpty()) return shortName
|
||||
|
||||
try {
|
||||
if ((unitFrom is DefaultUnit) and (unitTo is DefaultUnit)) {
|
||||
@ -168,7 +165,7 @@ private fun formatUnitToSupportLabel(
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun RightSideScreenPreview() {
|
||||
private fun UnitToSelectorPreview() {
|
||||
val units: Map<UnitGroup, List<AbstractUnit>> = mapOf(
|
||||
UnitGroup.LENGTH to listOf(
|
||||
NormalUnit(UnitID.meter, BigDecimal.valueOf(1.0E+18), UnitGroup.LENGTH, R.string.unit_meter, R.string.unit_meter_short),
|
||||
@ -181,19 +178,18 @@ private fun RightSideScreenPreview() {
|
||||
)
|
||||
)
|
||||
|
||||
RightSideScreen(
|
||||
uiState = RightSideUIState.Ready(
|
||||
UnitToSelectorScreen(
|
||||
uiState = UnitSelectorUIState.UnitTo(
|
||||
unitFrom = units.values.first().first(),
|
||||
units = units,
|
||||
query = TextFieldValue(),
|
||||
favorites = false,
|
||||
unitTo = units.values.first().first(),
|
||||
query = TextFieldValue("test"),
|
||||
units = UnitSearchResult.Success(units),
|
||||
showFavoritesOnly = false,
|
||||
sorting = UnitsListSorting.USAGE,
|
||||
unitTo = units.values.first()[1],
|
||||
input = "100",
|
||||
scale = 3,
|
||||
outputFormat = OutputFormat.PLAIN,
|
||||
formatterSymbols = FormatterSymbols.Spaces,
|
||||
currencyRateUpdateState = CurrencyRateUpdateState.Nothing
|
||||
),
|
||||
onQueryChange = {},
|
||||
toggleFavoritesOnly = {},
|
@ -33,12 +33,13 @@ import com.sadellie.unitto.data.converter.UnitID
|
||||
import com.sadellie.unitto.data.model.UnitGroup
|
||||
import com.sadellie.unitto.data.model.unit.AbstractUnit
|
||||
import com.sadellie.unitto.data.model.unit.NormalUnit
|
||||
import com.sadellie.unitto.feature.converter.UnitSearchResult
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Composable
|
||||
internal fun UnitsList(
|
||||
modifier: Modifier,
|
||||
groupedUnits: Map<UnitGroup, List<AbstractUnit>>,
|
||||
searchResult: UnitSearchResult,
|
||||
navigateToUnitGroups: () -> Unit,
|
||||
currentUnitId: String,
|
||||
supportLabel: (AbstractUnit) -> String,
|
||||
@ -47,14 +48,14 @@ internal fun UnitsList(
|
||||
) {
|
||||
Crossfade(
|
||||
modifier = modifier,
|
||||
targetState = groupedUnits.isNotEmpty(),
|
||||
targetState = searchResult,
|
||||
label = "Units list"
|
||||
) { hasUnits ->
|
||||
when (hasUnits) {
|
||||
true -> LazyColumn(
|
||||
) { result ->
|
||||
when (result) {
|
||||
is UnitSearchResult.Success -> LazyColumn(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
groupedUnits.forEach { (group, units) ->
|
||||
result.units.forEach { (group, units) ->
|
||||
item(group.name) {
|
||||
UnitGroupHeader(Modifier.animateItemPlacement(), group)
|
||||
}
|
||||
@ -73,11 +74,13 @@ internal fun UnitsList(
|
||||
}
|
||||
}
|
||||
|
||||
false -> SearchPlaceholder(
|
||||
UnitSearchResult.Empty -> SearchPlaceholder(
|
||||
onButtonClick = navigateToUnitGroups,
|
||||
supportText = stringResource(R.string.converter_no_results_support),
|
||||
buttonLabel = stringResource(R.string.open_settings_label)
|
||||
)
|
||||
|
||||
UnitSearchResult.Loading -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -100,7 +103,7 @@ private fun PreviewUnitsList() {
|
||||
|
||||
UnitsList(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
groupedUnits = groupedUnits,
|
||||
searchResult = UnitSearchResult.Success(units = groupedUnits),
|
||||
navigateToUnitGroups = {},
|
||||
currentUnitId = UnitID.mile,
|
||||
supportLabel = { resources.getString(it.shortName) },
|
||||
|
@ -22,19 +22,42 @@ import androidx.compose.runtime.remember
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.navArgument
|
||||
import androidx.navigation.navDeepLink
|
||||
import com.sadellie.unitto.core.ui.model.DrawerItem
|
||||
import com.sadellie.unitto.core.ui.unittoComposable
|
||||
import com.sadellie.unitto.core.ui.unittoNavigation
|
||||
import com.sadellie.unitto.data.model.UnitGroup
|
||||
import com.sadellie.unitto.feature.converter.ConverterRoute
|
||||
import com.sadellie.unitto.feature.converter.ConverterViewModel
|
||||
import com.sadellie.unitto.feature.converter.LeftSideRoute
|
||||
import com.sadellie.unitto.feature.converter.RightSideRoute
|
||||
import com.sadellie.unitto.feature.converter.CurrencyRateUpdateState
|
||||
import com.sadellie.unitto.feature.converter.UnitConverterUIState
|
||||
import com.sadellie.unitto.feature.converter.UnitFromSelectorRoute
|
||||
import com.sadellie.unitto.feature.converter.UnitToSelectorRoute
|
||||
|
||||
private val graph = DrawerItem.Converter.graph
|
||||
private val start = DrawerItem.Converter.start
|
||||
private const val LEFT = "left"
|
||||
private const val RIGHT = "right"
|
||||
|
||||
private const val UNIT_FROM = "unitFromSelector"
|
||||
private const val UNIT_TO = "unitToSelector"
|
||||
internal const val unitGroupArg = "unitGroupArg"
|
||||
internal const val unitFromIdArg = "unitFromId"
|
||||
internal const val unitToIdArg = "unitToIdArg"
|
||||
internal const val inputArg = "inputArg"
|
||||
|
||||
private const val UNIT_FROM_ROUTE = "$UNIT_FROM/{$unitFromIdArg}/{$unitGroupArg}"
|
||||
private const val UNIT_TO_ROUTE = "$UNIT_TO/{$unitFromIdArg}/{$unitToIdArg}/{$inputArg}"
|
||||
private fun NavHostController.navigateLeft(
|
||||
unitFromId: String,
|
||||
unitGroup: UnitGroup,
|
||||
) = navigate("$UNIT_FROM/$unitFromId/$unitGroup")
|
||||
|
||||
private fun NavHostController.navigateRight(
|
||||
unitFromId: String,
|
||||
unitToId: String,
|
||||
input: String?,
|
||||
) = navigate("$UNIT_TO/$unitFromId/$unitToId/$input")
|
||||
|
||||
fun NavGraphBuilder.converterGraph(
|
||||
openDrawer: () -> Unit,
|
||||
@ -58,36 +81,107 @@ fun NavGraphBuilder.converterGraph(
|
||||
|
||||
ConverterRoute(
|
||||
viewModel = parentViewModel,
|
||||
navigateToLeftScreen = { navController.navigate(LEFT) },
|
||||
navigateToRightScreen = { navController.navigate(RIGHT) },
|
||||
// Navigation logic is here, but should actually be in ConverterScreen
|
||||
navigateToLeftScreen = { uiState: UnitConverterUIState ->
|
||||
when (uiState) {
|
||||
is UnitConverterUIState.Default -> navController
|
||||
.navigateLeft(uiState.unitFrom.id, uiState.unitFrom.group)
|
||||
|
||||
is UnitConverterUIState.NumberBase -> navController
|
||||
.navigateLeft(uiState.unitFrom.id, uiState.unitFrom.group)
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
},
|
||||
navigateToRightScreen = { uiState: UnitConverterUIState ->
|
||||
when (uiState) {
|
||||
is UnitConverterUIState.Default -> {
|
||||
// Don't allow converting if still loading currencies
|
||||
val convertingCurrencies = uiState.unitFrom.group == UnitGroup.CURRENCY
|
||||
val currenciesReady =
|
||||
uiState.currencyRateUpdateState is CurrencyRateUpdateState.Ready
|
||||
|
||||
val input: String? = if (convertingCurrencies and !currenciesReady) {
|
||||
null
|
||||
} else {
|
||||
(uiState.calculation?.toPlainString() ?: uiState.input1.text)
|
||||
.ifEmpty { null }
|
||||
}
|
||||
|
||||
navController.navigateRight(
|
||||
uiState.unitFrom.id,
|
||||
uiState.unitTo.id,
|
||||
input
|
||||
)
|
||||
}
|
||||
|
||||
is UnitConverterUIState.NumberBase -> {
|
||||
val input = uiState.input.text.ifEmpty { null }
|
||||
navController.navigateRight(
|
||||
uiState.unitFrom.id,
|
||||
uiState.unitTo.id,
|
||||
input
|
||||
)
|
||||
}
|
||||
|
||||
UnitConverterUIState.Loading -> Unit
|
||||
}
|
||||
},
|
||||
navigateToSettings = navigateToSettings,
|
||||
navigateToMenu = openDrawer
|
||||
)
|
||||
}
|
||||
|
||||
unittoComposable(LEFT) { backStackEntry ->
|
||||
unittoComposable(
|
||||
route = UNIT_FROM_ROUTE,
|
||||
arguments = listOf(
|
||||
navArgument(unitFromIdArg) {
|
||||
type = NavType.StringType
|
||||
},
|
||||
navArgument(unitGroupArg) {
|
||||
type = NavType.EnumType(UnitGroup::class.java)
|
||||
},
|
||||
)
|
||||
) { backStackEntry ->
|
||||
val parentEntry = remember(backStackEntry) {
|
||||
navController.getBackStackEntry(graph)
|
||||
}
|
||||
|
||||
val parentViewModel = hiltViewModel<ConverterViewModel>(parentEntry)
|
||||
|
||||
LeftSideRoute(
|
||||
viewModel = parentViewModel,
|
||||
UnitFromSelectorRoute(
|
||||
unitSelectorViewModel = hiltViewModel(),
|
||||
converterViewModel = parentViewModel,
|
||||
navigateUp = navController::navigateUp,
|
||||
navigateToUnitGroups = navigateToUnitGroups
|
||||
)
|
||||
}
|
||||
|
||||
unittoComposable(RIGHT) { backStackEntry ->
|
||||
unittoComposable(
|
||||
route = UNIT_TO_ROUTE,
|
||||
arguments = listOf(
|
||||
navArgument(unitFromIdArg) {
|
||||
type = NavType.StringType
|
||||
},
|
||||
navArgument(unitToIdArg) {
|
||||
type = NavType.StringType
|
||||
},
|
||||
navArgument(inputArg) {
|
||||
type = NavType.StringType
|
||||
nullable = true
|
||||
defaultValue = null
|
||||
},
|
||||
)
|
||||
) { backStackEntry ->
|
||||
val parentEntry = remember(backStackEntry) {
|
||||
navController.getBackStackEntry(graph)
|
||||
}
|
||||
|
||||
val parentViewModel = hiltViewModel<ConverterViewModel>(parentEntry)
|
||||
|
||||
RightSideRoute(
|
||||
viewModel = parentViewModel,
|
||||
UnitToSelectorRoute(
|
||||
unitSelectorViewModel = hiltViewModel(),
|
||||
converterViewModel = parentViewModel,
|
||||
navigateUp = navController::navigateUp,
|
||||
navigateToUnitGroups = navigateToUnitGroups
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user