mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-19 00:35:26 +02:00
Better (?) MutableStateFlows approach
This commit is contained in:
parent
0ffec5e15a
commit
66227f4ed7
@ -26,6 +26,7 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
@ -41,8 +42,8 @@ import com.sadellie.unitto.data.NavRoutes.SETTINGS_GRAPH
|
||||
import com.sadellie.unitto.data.NavRoutes.SETTINGS_SCREEN
|
||||
import com.sadellie.unitto.data.NavRoutes.THEMES_SCREEN
|
||||
import com.sadellie.unitto.data.NavRoutes.UNIT_GROUPS_SCREEN
|
||||
import com.sadellie.unitto.screens.main.MainViewModel
|
||||
import com.sadellie.unitto.screens.main.MainScreen
|
||||
import com.sadellie.unitto.screens.main.MainViewModel
|
||||
import com.sadellie.unitto.screens.second.LeftSideScreen
|
||||
import com.sadellie.unitto.screens.second.RightSideScreen
|
||||
import com.sadellie.unitto.screens.second.SecondViewModel
|
||||
@ -67,15 +68,15 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
setContent {
|
||||
val settingsViewModel: SettingsViewModel = hiltViewModel()
|
||||
val userPrefs = settingsViewModel.userPrefs
|
||||
val userPrefs = settingsViewModel.userPrefs.collectAsStateWithLifecycle()
|
||||
|
||||
val themmoController = rememberThemmoController(
|
||||
lightColorScheme = LightThemeColors,
|
||||
darkColorScheme = DarkThemeColors,
|
||||
// Anything below will not called if theming mode is still loading from DataStore
|
||||
themingMode = userPrefs.themingMode ?: return@setContent,
|
||||
dynamicThemeEnabled = userPrefs.enableDynamicTheme,
|
||||
amoledThemeEnabled = userPrefs.enableAmoledTheme
|
||||
themingMode = userPrefs.value.themingMode ?: return@setContent,
|
||||
dynamicThemeEnabled = userPrefs.value.enableDynamicTheme,
|
||||
amoledThemeEnabled = userPrefs.value.enableAmoledTheme
|
||||
)
|
||||
val navController = rememberNavController()
|
||||
val sysUiController = rememberSystemUiController()
|
||||
|
@ -28,6 +28,8 @@ import com.sadellie.unitto.data.KEY_DOT
|
||||
import com.sadellie.unitto.data.KEY_E
|
||||
import com.sadellie.unitto.data.preferences.Separator
|
||||
import com.sadellie.unitto.data.units.AbstractUnit
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
import java.text.NumberFormat
|
||||
@ -222,3 +224,27 @@ fun Sequence<AbstractUnit>.sortByLev(stringA: String): Sequence<AbstractUnit> {
|
||||
.map { it.first }
|
||||
.asSequence()
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T1, T2, T3, T4, T5, T6, T7, T8, 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>,
|
||||
transform: suspend (T1, T2, T3, T4, T5, T6, T7, T8) -> R
|
||||
): Flow<R> = combine(flow, flow2, flow3, flow4, flow5, flow6, flow7, flow8) { 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
|
||||
)
|
||||
}
|
@ -19,7 +19,6 @@
|
||||
package com.sadellie.unitto.screens.main
|
||||
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
@ -40,12 +39,13 @@ import com.sadellie.unitto.data.units.database.MyBasedUnit
|
||||
import com.sadellie.unitto.data.units.database.MyBasedUnitsRepository
|
||||
import com.sadellie.unitto.data.units.remote.CurrencyApi
|
||||
import com.sadellie.unitto.data.units.remote.CurrencyUnitResponse
|
||||
import com.sadellie.unitto.screens.combine
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
@ -58,12 +58,39 @@ class MainViewModel @Inject constructor(
|
||||
private val application: Application,
|
||||
private val allUnitsRepository: AllUnitsRepository
|
||||
) : ViewModel() {
|
||||
private var userPrefs = UserPreferences()
|
||||
|
||||
/**
|
||||
* UI state
|
||||
*/
|
||||
private val _mainUIState = MutableStateFlow(MainScreenUIState())
|
||||
private val _inputValue: MutableStateFlow<String> = MutableStateFlow(KEY_0)
|
||||
private val _deleteButtonEnabled: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||
private val _dotButtonEnabled: MutableStateFlow<Boolean> = MutableStateFlow(true)
|
||||
private val _negateButtonEnabled: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||
private val _isLoadingDatabase: MutableStateFlow<Boolean> = MutableStateFlow(true)
|
||||
private val _isLoadingNetwork: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||
private val _showError: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||
private val _userPrefs = userPrefsRepository.userPreferencesFlow
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), UserPreferences())
|
||||
|
||||
val mainFlow = combine(
|
||||
_inputValue,
|
||||
_deleteButtonEnabled,
|
||||
_dotButtonEnabled,
|
||||
_negateButtonEnabled,
|
||||
_isLoadingDatabase,
|
||||
_isLoadingNetwork,
|
||||
_showError,
|
||||
_userPrefs
|
||||
) { inputValue, deleteButtonEnabled, dotButtonEnabled, negateButtonEnabled, isLoadingDatabase, isLoadingNetwork, showError, _ ->
|
||||
return@combine MainScreenUIState(
|
||||
inputValue = inputValue,
|
||||
resultValue = convertValue(),
|
||||
deleteButtonEnabled = deleteButtonEnabled,
|
||||
dotButtonEnabled = dotButtonEnabled,
|
||||
negateButtonEnabled = negateButtonEnabled,
|
||||
isLoadingDatabase = isLoadingDatabase,
|
||||
isLoadingNetwork = isLoadingNetwork,
|
||||
showError = showError
|
||||
)
|
||||
}
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), MainScreenUIState())
|
||||
|
||||
/**
|
||||
* Unit we converting from (left side)
|
||||
@ -77,27 +104,16 @@ class MainViewModel @Inject constructor(
|
||||
var unitTo: AbstractUnit by mutableStateOf(allUnitsRepository.getById(MyUnitIDS.mile))
|
||||
private set
|
||||
|
||||
val mainFlow = combine(_mainUIState, userPrefsRepository.userPreferencesFlow) { UIState, prefs ->
|
||||
userPrefs = prefs
|
||||
convertValue()
|
||||
return@combine UIState
|
||||
}
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5000),
|
||||
initialValue = MainScreenUIState()
|
||||
)
|
||||
|
||||
/**
|
||||
* This function takes local variables, converts values and then causes the UI to update
|
||||
*/
|
||||
private fun convertValue() {
|
||||
private fun convertValue(): String {
|
||||
// Converting value using a specified precision
|
||||
val convertedValue: BigDecimal =
|
||||
unitFrom.convert(
|
||||
unitTo,
|
||||
_mainUIState.value.inputValue.toBigDecimal(),
|
||||
userPrefs.digitsPrecision
|
||||
_inputValue.value.toBigDecimal(),
|
||||
_userPrefs.value.digitsPrecision
|
||||
)
|
||||
|
||||
/**
|
||||
@ -107,20 +123,20 @@ class MainViewModel @Inject constructor(
|
||||
*/
|
||||
val resultValue =
|
||||
if (convertedValue == BigDecimal.ZERO.setScale(
|
||||
userPrefs.digitsPrecision,
|
||||
_userPrefs.value.digitsPrecision,
|
||||
RoundingMode.HALF_EVEN
|
||||
)
|
||||
) {
|
||||
KEY_0
|
||||
} else {
|
||||
// Setting result value using a specified OutputFormat
|
||||
when (userPrefs.outputFormat) {
|
||||
when (_userPrefs.value.outputFormat) {
|
||||
OutputFormat.ALLOW_ENGINEERING -> convertedValue.toString()
|
||||
OutputFormat.FORCE_ENGINEERING -> convertedValue.toEngineeringString()
|
||||
else -> convertedValue.toPlainString()
|
||||
}
|
||||
}
|
||||
_mainUIState.value = _mainUIState.value.copy(resultValue = resultValue)
|
||||
return resultValue
|
||||
}
|
||||
|
||||
/**
|
||||
@ -133,16 +149,10 @@ class MainViewModel @Inject constructor(
|
||||
unitFrom = clickedUnit
|
||||
|
||||
// Now we check for negate button
|
||||
_mainUIState.value =
|
||||
_mainUIState.value.copy(negateButtonEnabled = clickedUnit.group.canNegate)
|
||||
_negateButtonEnabled.update { clickedUnit.group.canNegate }
|
||||
// Now we change to positive if the group we switched to supports negate
|
||||
if (!clickedUnit.group.canNegate) {
|
||||
_mainUIState.value =
|
||||
_mainUIState.value.copy(
|
||||
inputValue = _mainUIState.value.inputValue.removePrefix(
|
||||
KEY_MINUS
|
||||
)
|
||||
)
|
||||
_inputValue.update { _inputValue.value.removePrefix(KEY_MINUS) }
|
||||
}
|
||||
|
||||
// Now setting up right unit (pair for the left one)
|
||||
@ -157,8 +167,6 @@ class MainViewModel @Inject constructor(
|
||||
incrementCounter(clickedUnit)
|
||||
// Currencies require us to get data from the internet
|
||||
updateCurrenciesBasicUnits()
|
||||
// We can't call outside of this block. It will set precision to 0 in that case
|
||||
convertValue()
|
||||
// Saving latest pair
|
||||
saveLatestPairOfUnits()
|
||||
}
|
||||
@ -190,9 +198,6 @@ class MainViewModel @Inject constructor(
|
||||
// Saving latest pair
|
||||
saveLatestPairOfUnits()
|
||||
}
|
||||
|
||||
// Changed units, now we can convert
|
||||
convertValue()
|
||||
}
|
||||
|
||||
private suspend fun incrementCounter(unit: AbstractUnit) {
|
||||
@ -213,12 +218,13 @@ class MainViewModel @Inject constructor(
|
||||
*/
|
||||
private suspend fun updateCurrenciesBasicUnits() {
|
||||
// Resetting error and network loading states in case we are not gonna do anything below
|
||||
_mainUIState.value = _mainUIState.value.copy(isLoadingNetwork = false, showError = false)
|
||||
_isLoadingNetwork.update { false }
|
||||
_showError.update { false }
|
||||
// We update currencies only when needed
|
||||
if (unitFrom.group != UnitGroup.CURRENCY) return
|
||||
|
||||
// Starting to load stuff
|
||||
_mainUIState.value = _mainUIState.value.copy(isLoadingNetwork = true)
|
||||
_isLoadingNetwork.update { true }
|
||||
|
||||
try {
|
||||
val pairs: CurrencyUnitResponse =
|
||||
@ -233,10 +239,10 @@ class MainViewModel @Inject constructor(
|
||||
FirebaseHelper().recordException(e)
|
||||
}
|
||||
}
|
||||
_mainUIState.value = _mainUIState.value.copy(showError = true)
|
||||
_showError.update { true }
|
||||
} finally {
|
||||
// Loaded
|
||||
_mainUIState.value = _mainUIState.value.copy(isLoadingNetwork = false)
|
||||
_isLoadingNetwork.update { false }
|
||||
}
|
||||
}
|
||||
|
||||
@ -251,8 +257,6 @@ class MainViewModel @Inject constructor(
|
||||
updateCurrenciesBasicUnits()
|
||||
saveLatestPairOfUnits()
|
||||
}
|
||||
// Swapped, can convert now
|
||||
convertValue()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -266,17 +270,14 @@ class MainViewModel @Inject constructor(
|
||||
// Here we add a dot to input
|
||||
// Disabling dot button to avoid multiple dots in input value
|
||||
// Enabling delete button to so that we can delete this dot from input
|
||||
_mainUIState.value = _mainUIState.value.copy(
|
||||
inputValue = _mainUIState.value.inputValue + digitToAdd,
|
||||
dotButtonEnabled = false,
|
||||
deleteButtonEnabled = true
|
||||
)
|
||||
_inputValue.update { _inputValue.value + digitToAdd }
|
||||
_dotButtonEnabled.update { false }
|
||||
_deleteButtonEnabled.update { true }
|
||||
}
|
||||
KEY_0 -> {
|
||||
// We shouldn't add zero to another zero in input, i.e. 00
|
||||
if (_mainUIState.value.inputValue != KEY_0) {
|
||||
_mainUIState.value =
|
||||
_mainUIState.value.copy(inputValue = _mainUIState.value.inputValue + digitToAdd)
|
||||
if (_inputValue.value != KEY_0) {
|
||||
_inputValue.update { _inputValue.value + digitToAdd }
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
@ -285,13 +286,12 @@ class MainViewModel @Inject constructor(
|
||||
When there is just a zero, we should replace it with the digit we want to add,
|
||||
avoids input to be like 03 (with this check it will be just 3)
|
||||
*/
|
||||
_mainUIState.value = _mainUIState.value.copy(
|
||||
inputValue = if (_mainUIState.value.inputValue == KEY_0) digitToAdd else _mainUIState.value.inputValue + digitToAdd,
|
||||
deleteButtonEnabled = true
|
||||
)
|
||||
_inputValue.update {
|
||||
if (_inputValue.value == KEY_0) digitToAdd else _inputValue.value + digitToAdd
|
||||
}
|
||||
_deleteButtonEnabled.update { true }
|
||||
}
|
||||
}
|
||||
convertValue()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -300,13 +300,12 @@ class MainViewModel @Inject constructor(
|
||||
fun deleteDigit() {
|
||||
// Last symbol is a dot
|
||||
// We enable DOT button
|
||||
if (_mainUIState.value.inputValue.endsWith(KEY_DOT)) {
|
||||
_mainUIState.value = _mainUIState.value.copy(dotButtonEnabled = true)
|
||||
if (_inputValue.value.endsWith(KEY_DOT)) {
|
||||
_dotButtonEnabled.update { true }
|
||||
}
|
||||
|
||||
// Deleting last symbol
|
||||
_mainUIState.value =
|
||||
_mainUIState.value.copy(inputValue = _mainUIState.value.inputValue.dropLast(1))
|
||||
var inputToSet = _inputValue.value.dropLast(1)
|
||||
|
||||
/*
|
||||
Now we check what we have left
|
||||
@ -316,42 +315,37 @@ class MainViewModel @Inject constructor(
|
||||
Skipping this block means that we are left we acceptable value, i.e. 123.03
|
||||
*/
|
||||
if (
|
||||
_mainUIState.value.inputValue in listOf(String(), KEY_MINUS, KEY_0)
|
||||
inputToSet in listOf(String(), KEY_MINUS, KEY_0)
|
||||
) {
|
||||
_mainUIState.value =
|
||||
_mainUIState.value.copy(deleteButtonEnabled = false, inputValue = KEY_0)
|
||||
_deleteButtonEnabled.update { false }
|
||||
inputToSet = KEY_0
|
||||
}
|
||||
|
||||
// We are sure that input has acceptable value, so we convert it
|
||||
convertValue()
|
||||
_inputValue.update { inputToSet }
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears input value and sets it to default (ZERO)
|
||||
*/
|
||||
fun clearInput() {
|
||||
_mainUIState.value = _mainUIState.value.copy(
|
||||
inputValue = KEY_0,
|
||||
deleteButtonEnabled = false,
|
||||
dotButtonEnabled = true
|
||||
)
|
||||
convertValue()
|
||||
_inputValue.update { KEY_0 }
|
||||
_deleteButtonEnabled.update { false }
|
||||
_dotButtonEnabled.update { true }
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes input from positive to negative and vice versa
|
||||
*/
|
||||
fun negateInput() {
|
||||
_mainUIState.value = _mainUIState.value.copy(
|
||||
inputValue = if (_mainUIState.value.inputValue.getOrNull(0) != KEY_MINUS.single()) {
|
||||
_inputValue.update {
|
||||
if (_inputValue.value.getOrNull(0) != KEY_MINUS.single()) {
|
||||
// If input doesn't have minus at the beginning, we give it to it
|
||||
KEY_MINUS + _mainUIState.value.inputValue
|
||||
KEY_MINUS + _inputValue.value
|
||||
} else {
|
||||
// Input has minus, meaning we need to remove it
|
||||
_mainUIState.value.inputValue.removePrefix(KEY_MINUS)
|
||||
_inputValue.value.removePrefix(KEY_MINUS)
|
||||
}
|
||||
)
|
||||
convertValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -363,34 +357,29 @@ class MainViewModel @Inject constructor(
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
userPrefs = userPrefsRepository.userPreferencesFlow.first()
|
||||
val initialUserPrefs = userPrefsRepository.userPreferencesFlow.first()
|
||||
|
||||
// First we load latest pair of units
|
||||
unitFrom = try {
|
||||
allUnitsRepository.getById(userPrefs.latestLeftSideUnit)
|
||||
allUnitsRepository.getById(initialUserPrefs.latestLeftSideUnit)
|
||||
} catch (e: java.util.NoSuchElementException) {
|
||||
Log.w("MainViewModel", "No unit with the given unitId")
|
||||
allUnitsRepository.getById(MyUnitIDS.kilometer)
|
||||
}
|
||||
|
||||
unitTo = try {
|
||||
allUnitsRepository.getById(userPrefs.latestRightSideUnit)
|
||||
allUnitsRepository.getById(initialUserPrefs.latestRightSideUnit)
|
||||
} catch (e: java.util.NoSuchElementException) {
|
||||
Log.w("MainViewModel", "No unit with the given unitId")
|
||||
allUnitsRepository.getById(MyUnitIDS.mile)
|
||||
}
|
||||
|
||||
_mainUIState.value =
|
||||
_mainUIState.value.copy(negateButtonEnabled = unitFrom.group.canNegate)
|
||||
|
||||
// Now we load units data from database
|
||||
val allBasedUnits = basedUnitRepository.getAll()
|
||||
allUnitsRepository.loadFromDatabase(application, allBasedUnits)
|
||||
|
||||
// User is free to convert values and units on units screen can be sorted properly
|
||||
_mainUIState.value = _mainUIState.value.copy(isLoadingDatabase = false)
|
||||
_negateButtonEnabled.update { unitFrom.group.canNegate }
|
||||
_isLoadingDatabase.update { false }
|
||||
updateCurrenciesBasicUnits()
|
||||
convertValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
@ -43,25 +44,35 @@ class SecondViewModel @Inject constructor(
|
||||
unitGroupsRepository: UnitGroupsRepository
|
||||
) : ViewModel() {
|
||||
|
||||
private val _uiStateFlow = MutableStateFlow(SecondScreenUIState())
|
||||
private val _favoritesOnly = MutableStateFlow(false)
|
||||
private val _unitsToShow = MutableStateFlow(emptyMap<UnitGroup, List<AbstractUnit>>())
|
||||
private val _searchQuery = MutableStateFlow("")
|
||||
private val _chosenUnitGroup: MutableStateFlow<UnitGroup?> = MutableStateFlow(null)
|
||||
private val _shownUnitGroups = unitGroupsRepository.shownUnitGroups
|
||||
|
||||
val mainFlow = combine(_uiStateFlow, unitGroupsRepository.shownUnitGroups) { uiState, shown ->
|
||||
val newState = uiState.copy(shownUnitGroups = shown)
|
||||
_uiStateFlow.value = newState
|
||||
return@combine newState
|
||||
}
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5000),
|
||||
initialValue = SecondScreenUIState()
|
||||
val mainFlow = combine(
|
||||
_favoritesOnly,
|
||||
_unitsToShow,
|
||||
_searchQuery,
|
||||
_chosenUnitGroup,
|
||||
_shownUnitGroups
|
||||
) { favoritesOnly, unitsToShow, searchQuery, chosenUnitGroup, shownUnitGroups ->
|
||||
return@combine SecondScreenUIState(
|
||||
favoritesOnly = favoritesOnly,
|
||||
unitsToShow = unitsToShow,
|
||||
searchQuery = searchQuery,
|
||||
chosenUnitGroup = chosenUnitGroup,
|
||||
shownUnitGroups = shownUnitGroups
|
||||
)
|
||||
}
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), SecondScreenUIState())
|
||||
|
||||
fun toggleFavoritesOnly() {
|
||||
_uiStateFlow.value = _uiStateFlow.value.copy(favoritesOnly = !_uiStateFlow.value.favoritesOnly)
|
||||
_favoritesOnly.update { !_favoritesOnly.value }
|
||||
}
|
||||
|
||||
fun onSearchQueryChange(newValue: String) {
|
||||
_uiStateFlow.value = _uiStateFlow.value.copy(searchQuery = newValue)
|
||||
_searchQuery.update { newValue }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,7 +81,7 @@ class SecondViewModel @Inject constructor(
|
||||
* @param unitGroup Chip to change to.
|
||||
*/
|
||||
fun setSelectedChip(unitGroup: UnitGroup) {
|
||||
_uiStateFlow.value = _uiStateFlow.value.copy(chosenUnitGroup = unitGroup)
|
||||
_chosenUnitGroup.update { unitGroup }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,8 +93,8 @@ class SecondViewModel @Inject constructor(
|
||||
* @param unitGroup [UnitGroup], currently selected chip.
|
||||
*/
|
||||
fun toggleSelectedChip(unitGroup: UnitGroup) {
|
||||
val newUnitGroup = if (_uiStateFlow.value.chosenUnitGroup == unitGroup) null else unitGroup
|
||||
_uiStateFlow.value = _uiStateFlow.value.copy(chosenUnitGroup = newUnitGroup)
|
||||
val newUnitGroup = if (_chosenUnitGroup.value == unitGroup) null else unitGroup
|
||||
_chosenUnitGroup.update { newUnitGroup }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -101,13 +112,13 @@ class SecondViewModel @Inject constructor(
|
||||
withContext(Dispatchers.Default) {
|
||||
val unitsToShow = allUnitsRepository.filterUnits(
|
||||
hideBrokenCurrencies = hideBrokenCurrencies,
|
||||
chosenUnitGroup = _uiStateFlow.value.chosenUnitGroup,
|
||||
favoritesOnly = _uiStateFlow.value.favoritesOnly,
|
||||
searchQuery = _uiStateFlow.value.searchQuery,
|
||||
allUnitsGroups = _uiStateFlow.value.shownUnitGroups
|
||||
chosenUnitGroup = _chosenUnitGroup.value,
|
||||
favoritesOnly = _favoritesOnly.value,
|
||||
searchQuery = _searchQuery.value,
|
||||
allUnitsGroups = _shownUnitGroups.value
|
||||
)
|
||||
|
||||
_uiStateFlow.value = _uiStateFlow.value.copy(unitsToShow = unitsToShow)
|
||||
_unitsToShow.update { unitsToShow }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.sadellie.unitto.BuildConfig
|
||||
import com.sadellie.unitto.R
|
||||
import com.sadellie.unitto.data.NavRoutes.ABOUT_SCREEN
|
||||
@ -51,6 +52,7 @@ fun SettingsScreen(
|
||||
navControllerAction: (String) -> Unit
|
||||
) {
|
||||
val mContext = LocalContext.current
|
||||
val userPrefs = viewModel.userPrefs.collectAsStateWithLifecycle()
|
||||
var dialogState: DialogState by rememberSaveable {
|
||||
mutableStateOf(DialogState.NONE)
|
||||
}
|
||||
@ -151,7 +153,7 @@ fun SettingsScreen(
|
||||
UnittoListItem(
|
||||
label = stringResource(R.string.send_usage_statistics),
|
||||
supportText = stringResource(R.string.send_usage_statistics_support),
|
||||
switchState = viewModel.userPrefs.enableAnalytics
|
||||
switchState = userPrefs.value.enableAnalytics
|
||||
) { viewModel.updateEnableAnalytics(it) }
|
||||
}
|
||||
}
|
||||
@ -198,7 +200,7 @@ fun SettingsScreen(
|
||||
AlertDialogWithList(
|
||||
title = stringResource(R.string.precision_setting),
|
||||
listItems = PRECISIONS,
|
||||
selectedItemIndex = viewModel.userPrefs.digitsPrecision,
|
||||
selectedItemIndex = userPrefs.value.digitsPrecision,
|
||||
selectAction = { viewModel.updatePrecision(it) },
|
||||
dismissAction = { resetDialog() },
|
||||
supportText = stringResource(R.string.precision_setting_info)
|
||||
@ -208,7 +210,7 @@ fun SettingsScreen(
|
||||
AlertDialogWithList(
|
||||
title = stringResource(R.string.separator_setting),
|
||||
listItems = SEPARATORS,
|
||||
selectedItemIndex = viewModel.userPrefs.separator,
|
||||
selectedItemIndex = userPrefs.value.separator,
|
||||
selectAction = { viewModel.updateSeparator(it) },
|
||||
dismissAction = { resetDialog() }
|
||||
)
|
||||
@ -217,7 +219,7 @@ fun SettingsScreen(
|
||||
AlertDialogWithList(
|
||||
title = stringResource(R.string.output_format_setting),
|
||||
listItems = OUTPUT_FORMAT,
|
||||
selectedItemIndex = viewModel.userPrefs.outputFormat,
|
||||
selectedItemIndex = userPrefs.value.outputFormat,
|
||||
selectAction = { viewModel.updateOutputFormat(it) },
|
||||
dismissAction = { resetDialog() },
|
||||
supportText = stringResource(R.string.output_format_setting_info)
|
||||
|
@ -19,9 +19,6 @@
|
||||
package com.sadellie.unitto.screens.setttings
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.sadellie.unitto.FirebaseHelper
|
||||
@ -32,7 +29,10 @@ import com.sadellie.unitto.data.units.UnitGroupsRepository
|
||||
import com.sadellie.unitto.screens.Formatter
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import io.github.sadellie.themmo.ThemingMode
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.burnoutcrew.reorderable.ItemPosition
|
||||
import javax.inject.Inject
|
||||
@ -43,7 +43,9 @@ class SettingsViewModel @Inject constructor(
|
||||
private val unitGroupsRepository: UnitGroupsRepository,
|
||||
private val application: Application,
|
||||
) : ViewModel() {
|
||||
var userPrefs: UserPreferences by mutableStateOf(UserPreferences())
|
||||
var userPrefs = userPrefsRepository.userPreferencesFlow
|
||||
.onEach { Formatter.setSeparator(it.separator) }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), UserPreferences())
|
||||
val shownUnitGroups = unitGroupsRepository.shownUnitGroups
|
||||
val hiddenUnitGroups = unitGroupsRepository.hiddenUnitGroups
|
||||
|
||||
@ -164,11 +166,6 @@ class SettingsViewModel @Inject constructor(
|
||||
unitGroupsRepository.updateShownGroups(
|
||||
userPrefsRepository.userPreferencesFlow.first().shownUnitGroups
|
||||
)
|
||||
|
||||
userPrefsRepository.userPreferencesFlow.collect {
|
||||
userPrefs = it
|
||||
Formatter.setSeparator(it.separator)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user