mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-19 00:35:26 +02:00
Separate User Preferences
This commit is contained in:
parent
1b61b4bd85
commit
86dce329ac
@ -120,8 +120,7 @@ dependencies {
|
||||
implementation(project(mapOf("path" to ":feature:calculator")))
|
||||
implementation(project(mapOf("path" to ":feature:settings")))
|
||||
implementation(project(mapOf("path" to ":feature:unitslist")))
|
||||
implementation(project(mapOf("path" to ":feature:datedifference")))
|
||||
implementation(project(mapOf("path" to ":data:units")))
|
||||
implementation(project(mapOf("path" to ":feature:datedifference")))
|
||||
implementation(project(mapOf("path" to ":data:model")))
|
||||
implementation(project(mapOf("path" to ":data:userprefs")))
|
||||
implementation(project(mapOf("path" to ":core:ui")))
|
||||
|
@ -40,13 +40,11 @@ internal class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val userPrefsFlow = userPrefsRepository.userPreferencesFlow
|
||||
|
||||
setContent {
|
||||
val userPrefs = userPrefsFlow
|
||||
val uiPrefs = userPrefsRepository.uiPreferencesFlow
|
||||
.collectAsStateWithLifecycle(null).value
|
||||
|
||||
if (userPrefs != null) UnittoApp(userPrefs)
|
||||
if (uiPrefs != null) UnittoApp(uiPrefs)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,23 +44,23 @@ import com.sadellie.unitto.core.ui.model.DrawerItems
|
||||
import com.sadellie.unitto.core.ui.theme.AppTypography
|
||||
import com.sadellie.unitto.core.ui.theme.DarkThemeColors
|
||||
import com.sadellie.unitto.core.ui.theme.LightThemeColors
|
||||
import com.sadellie.unitto.data.userprefs.UserPreferences
|
||||
import com.sadellie.unitto.data.userprefs.UIPreferences
|
||||
import io.github.sadellie.themmo.Themmo
|
||||
import io.github.sadellie.themmo.rememberThemmoController
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
internal fun UnittoApp(userPrefs: UserPreferences) {
|
||||
internal fun UnittoApp(uiPrefs: UIPreferences) {
|
||||
|
||||
val themmoController = rememberThemmoController(
|
||||
lightColorScheme = LightThemeColors,
|
||||
darkColorScheme = DarkThemeColors,
|
||||
// Anything below will not be called if theming mode is still loading from DataStore
|
||||
themingMode = userPrefs.themingMode,
|
||||
dynamicThemeEnabled = userPrefs.enableDynamicTheme,
|
||||
amoledThemeEnabled = userPrefs.enableAmoledTheme,
|
||||
customColor = userPrefs.customColor,
|
||||
monetMode = userPrefs.monetMode
|
||||
themingMode = uiPrefs.themingMode,
|
||||
dynamicThemeEnabled = uiPrefs.enableDynamicTheme,
|
||||
amoledThemeEnabled = uiPrefs.enableAmoledTheme,
|
||||
customColor = uiPrefs.customColor,
|
||||
monetMode = uiPrefs.monetMode
|
||||
)
|
||||
val navController = rememberNavController()
|
||||
val sysUiController = rememberSystemUiController()
|
||||
@ -131,7 +131,7 @@ internal fun UnittoApp(userPrefs: UserPreferences) {
|
||||
UnittoNavigation(
|
||||
navController = navController,
|
||||
themmoController = it,
|
||||
startDestination = userPrefs.startingScreen,
|
||||
startDestination = uiPrefs.startingScreen,
|
||||
openDrawer = { drawerScope.launch { drawerState.open() } }
|
||||
)
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ import com.sadellie.unitto.feature.calculator.navigation.calculatorScreen
|
||||
import com.sadellie.unitto.feature.converter.ConverterViewModel
|
||||
import com.sadellie.unitto.feature.converter.navigation.converterScreen
|
||||
import com.sadellie.unitto.feature.datedifference.navigation.dateDifferenceScreen
|
||||
import com.sadellie.unitto.feature.settings.SettingsViewModel
|
||||
import com.sadellie.unitto.feature.settings.navigation.navigateToSettings
|
||||
import com.sadellie.unitto.feature.settings.navigation.navigateToUnitGroups
|
||||
import com.sadellie.unitto.feature.settings.navigation.settingGraph
|
||||
@ -50,7 +49,6 @@ internal fun UnittoNavigation(
|
||||
) {
|
||||
val converterViewModel: ConverterViewModel = hiltViewModel()
|
||||
val unitsListViewModel: UnitsListViewModel = hiltViewModel()
|
||||
val settingsViewModel: SettingsViewModel = hiltViewModel()
|
||||
|
||||
NavHost(
|
||||
navController = navController,
|
||||
@ -90,7 +88,6 @@ internal fun UnittoNavigation(
|
||||
)
|
||||
|
||||
settingGraph(
|
||||
settingsViewModel = settingsViewModel,
|
||||
themmoController = themmoController,
|
||||
navController = navController,
|
||||
menuButtonClick = openDrawer
|
||||
|
@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2022-2023 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.data.unitgroups
|
||||
|
||||
import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
|
||||
import com.sadellie.unitto.data.model.UnitGroup
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import org.burnoutcrew.reorderable.ItemPosition
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Repository that holds information about shown and hidden [UnitGroup]s and provides methods to
|
||||
* show/hide [UnitGroup]s.
|
||||
*/
|
||||
@Singleton
|
||||
class UnitGroupsRepository @Inject constructor() {
|
||||
|
||||
/**
|
||||
* Mutex is need needed because we work with flow (sync stuff).
|
||||
*/
|
||||
private val mutex = Mutex()
|
||||
|
||||
/**
|
||||
* Currently shown [UnitGroup]s.
|
||||
*/
|
||||
var shownUnitGroups = MutableStateFlow(listOf<UnitGroup>())
|
||||
private set
|
||||
|
||||
/**
|
||||
* Currently hidden [UnitGroup]s.
|
||||
*/
|
||||
var hiddenUnitGroups = MutableStateFlow(listOf<UnitGroup>())
|
||||
private set
|
||||
|
||||
/**
|
||||
* Sets [shownUnitGroups] and updates [hiddenUnitGroups] as a side effect. [hiddenUnitGroups] is
|
||||
* everything from [ALL_UNIT_GROUPS] that was not in [shownUnitGroups].
|
||||
*
|
||||
* @param list List of [UnitGroup]s that need to be shown.
|
||||
*/
|
||||
suspend fun updateShownGroups(list: List<UnitGroup>) {
|
||||
mutex.withLock {
|
||||
shownUnitGroups.value = list
|
||||
hiddenUnitGroups.value = ALL_UNIT_GROUPS - list.toSet()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves [UnitGroup] from [shownUnitGroups] to [hiddenUnitGroups]
|
||||
*
|
||||
* @param unitGroup [UnitGroup] to hide.
|
||||
*/
|
||||
suspend fun markUnitGroupAsHidden(unitGroup: UnitGroup) {
|
||||
mutex.withLock {
|
||||
shownUnitGroups.value = shownUnitGroups.value - unitGroup
|
||||
// Newly hidden unit will appear at the top of the list
|
||||
hiddenUnitGroups.value = listOf(unitGroup) + hiddenUnitGroups.value
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves [UnitGroup] from [hiddenUnitGroups] to [shownUnitGroups]
|
||||
*
|
||||
* @param unitGroup [UnitGroup] to show.
|
||||
*/
|
||||
suspend fun markUnitGroupAsShown(unitGroup: UnitGroup) {
|
||||
mutex.withLock {
|
||||
hiddenUnitGroups.value = hiddenUnitGroups.value - unitGroup
|
||||
shownUnitGroups.value = shownUnitGroups.value + unitGroup
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves [UnitGroup] in [shownUnitGroups] from one index to another (reorder).
|
||||
*
|
||||
* @param from Position from which we need to move from
|
||||
* @param to Position where to put [UnitGroup]
|
||||
*/
|
||||
suspend fun moveShownUnitGroups(from: ItemPosition, to: ItemPosition) {
|
||||
mutex.withLock {
|
||||
shownUnitGroups.value = shownUnitGroups.value.toMutableList().apply {
|
||||
val initialIndex = shownUnitGroups.value.indexOfFirst { it == from.key }
|
||||
/**
|
||||
* No such item. Happens when dragging item and clicking "remove" while item is
|
||||
* still being dragged.
|
||||
*/
|
||||
if (initialIndex == -1) return
|
||||
|
||||
add(
|
||||
shownUnitGroups.value.indexOfFirst { it == to.key },
|
||||
removeAt(initialIndex)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -39,6 +39,7 @@ import io.github.sadellie.themmo.MonetMode
|
||||
import io.github.sadellie.themmo.ThemingMode
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
@ -84,6 +85,29 @@ data class UserPreferences(
|
||||
val unitConverterSorting: UnitsListSorting = UnitsListSorting.USAGE,
|
||||
)
|
||||
|
||||
data class UIPreferences(
|
||||
val themingMode: ThemingMode = ThemingMode.AUTO,
|
||||
val enableDynamicTheme: Boolean = false,
|
||||
val enableAmoledTheme: Boolean = false,
|
||||
val customColor: Color = Color.Unspecified,
|
||||
val monetMode: MonetMode = MonetMode.TONAL_SPOT,
|
||||
val startingScreen: String = TopLevelDestinations.Converter.route,
|
||||
)
|
||||
|
||||
data class MainPreferences(
|
||||
val digitsPrecision: Int = 3,
|
||||
val separator: Int = Separator.SPACES,
|
||||
val outputFormat: Int = OutputFormat.PLAIN,
|
||||
val latestLeftSideUnit: String = MyUnitIDS.kilometer,
|
||||
val latestRightSideUnit: String = MyUnitIDS.mile,
|
||||
val shownUnitGroups: List<UnitGroup> = ALL_UNIT_GROUPS,
|
||||
val enableVibrations: Boolean = true,
|
||||
val radianMode: Boolean = true,
|
||||
val unitConverterFavoritesOnly: Boolean = false,
|
||||
val unitConverterFormatTime: Boolean = false,
|
||||
val unitConverterSorting: UnitsListSorting = UnitsListSorting.USAGE,
|
||||
)
|
||||
|
||||
/**
|
||||
* Repository that works with DataStore
|
||||
*/
|
||||
@ -112,7 +136,7 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
||||
val UNIT_CONVERTER_SORTING = stringPreferencesKey("UNIT_CONVERTER_SORTING_PREF_KEY")
|
||||
}
|
||||
|
||||
val userPreferencesFlow: Flow<UserPreferences> = dataStore.data
|
||||
val uiPreferencesFlow: Flow<UIPreferences> = dataStore.data
|
||||
.catch { exception ->
|
||||
if (exception is IOException) {
|
||||
emit(emptyPreferences())
|
||||
@ -128,6 +152,27 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
||||
val customColor: Color = preferences[PrefsKeys.CUSTOM_COLOR]?.let { Color(it.toULong()) } ?: Color.Unspecified
|
||||
val monetMode: MonetMode = preferences[PrefsKeys.MONET_MODE]?.let { MonetMode.valueOf(it) }
|
||||
?: MonetMode.TONAL_SPOT
|
||||
val startingScreen: String = preferences[PrefsKeys.STARTING_SCREEN] ?: TopLevelDestinations.Converter.route
|
||||
|
||||
UIPreferences(
|
||||
themingMode = themingMode,
|
||||
enableDynamicTheme = enableDynamicTheme,
|
||||
enableAmoledTheme = enableAmoledTheme,
|
||||
customColor = customColor,
|
||||
monetMode = monetMode,
|
||||
startingScreen = startingScreen
|
||||
)
|
||||
}
|
||||
|
||||
val mainPreferencesFlow: Flow<MainPreferences> = dataStore.data
|
||||
.catch { exception ->
|
||||
if (exception is IOException) {
|
||||
emit(emptyPreferences())
|
||||
} else {
|
||||
throw exception
|
||||
}
|
||||
}
|
||||
.map { preferences ->
|
||||
val digitsPrecision: Int = preferences[PrefsKeys.DIGITS_PRECISION] ?: 3
|
||||
val separator: Int = preferences[PrefsKeys.SEPARATOR] ?: Separator.SPACES
|
||||
val outputFormat: Int = preferences[PrefsKeys.OUTPUT_FORMAT] ?: OutputFormat.PLAIN
|
||||
@ -147,19 +192,12 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
||||
|
||||
} ?: ALL_UNIT_GROUPS
|
||||
val enableVibrations: Boolean = preferences[PrefsKeys.ENABLE_VIBRATIONS] ?: true
|
||||
val enableToolsExperiment: Boolean = preferences[PrefsKeys.ENABLE_TOOLS_EXPERIMENT] ?: false
|
||||
val startingScreen: String = preferences[PrefsKeys.STARTING_SCREEN] ?: TopLevelDestinations.Converter.route
|
||||
val radianMode: Boolean = preferences[PrefsKeys.RADIAN_MODE] ?: true
|
||||
val unitConverterFavoritesOnly: Boolean = preferences[PrefsKeys.UNIT_CONVERTER_FAVORITES_ONLY] ?: false
|
||||
val unitConverterFormatTime: Boolean = preferences[PrefsKeys.UNIT_CONVERTER_FORMAT_TIME] ?: false
|
||||
val unitConverterSorting: UnitsListSorting = preferences[PrefsKeys.UNIT_CONVERTER_SORTING]?.let { UnitsListSorting.valueOf(it) } ?: UnitsListSorting.USAGE
|
||||
|
||||
UserPreferences(
|
||||
themingMode = themingMode,
|
||||
enableDynamicTheme = enableDynamicTheme,
|
||||
enableAmoledTheme = enableAmoledTheme,
|
||||
customColor = customColor,
|
||||
monetMode = monetMode,
|
||||
MainPreferences(
|
||||
digitsPrecision = digitsPrecision,
|
||||
separator = separator,
|
||||
outputFormat = outputFormat,
|
||||
@ -167,8 +205,6 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
||||
latestRightSideUnit = latestRightSideUnit,
|
||||
shownUnitGroups = shownUnitGroups,
|
||||
enableVibrations = enableVibrations,
|
||||
enableToolsExperiment = enableToolsExperiment,
|
||||
startingScreen = startingScreen,
|
||||
radianMode = radianMode,
|
||||
unitConverterFavoritesOnly = unitConverterFavoritesOnly,
|
||||
unitConverterFormatTime = unitConverterFormatTime,
|
||||
@ -176,6 +212,31 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
||||
)
|
||||
}
|
||||
|
||||
val allPreferencesFlow = combine(
|
||||
mainPreferencesFlow, uiPreferencesFlow
|
||||
) { main, ui ->
|
||||
return@combine UserPreferences(
|
||||
themingMode = ui.themingMode,
|
||||
enableDynamicTheme = ui.enableDynamicTheme,
|
||||
enableAmoledTheme = ui.enableAmoledTheme,
|
||||
customColor = ui.customColor,
|
||||
monetMode = ui.monetMode,
|
||||
digitsPrecision = main.digitsPrecision,
|
||||
separator = main.separator,
|
||||
outputFormat = main.outputFormat,
|
||||
latestLeftSideUnit = main.latestLeftSideUnit,
|
||||
latestRightSideUnit = main.latestRightSideUnit,
|
||||
shownUnitGroups = main.shownUnitGroups,
|
||||
enableVibrations = main.enableVibrations,
|
||||
enableToolsExperiment = false,
|
||||
startingScreen = ui.startingScreen,
|
||||
radianMode = main.radianMode,
|
||||
unitConverterFavoritesOnly = main.unitConverterFavoritesOnly,
|
||||
unitConverterFormatTime = main.unitConverterFormatTime,
|
||||
unitConverterSorting = main.unitConverterSorting,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update precision preference in DataStore
|
||||
*
|
||||
|
@ -29,7 +29,6 @@ android {
|
||||
|
||||
dependencies {
|
||||
testImplementation(libs.junit)
|
||||
implementation(libs.com.github.sadellie.themmo)
|
||||
|
||||
implementation(project(mapOf("path" to ":data:common")))
|
||||
implementation(project(mapOf("path" to ":data:userprefs")))
|
||||
|
@ -31,7 +31,7 @@ import com.sadellie.unitto.data.common.isExpression
|
||||
import com.sadellie.unitto.data.common.setMinimumRequiredScale
|
||||
import com.sadellie.unitto.data.common.toStringWith
|
||||
import com.sadellie.unitto.data.common.trimZeros
|
||||
import com.sadellie.unitto.data.userprefs.UserPreferences
|
||||
import com.sadellie.unitto.data.userprefs.MainPreferences
|
||||
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import io.github.sadellie.evaluatto.Expression
|
||||
@ -54,11 +54,11 @@ internal class CalculatorViewModel @Inject constructor(
|
||||
private val userPrefsRepository: UserPreferencesRepository,
|
||||
private val calculatorHistoryRepository: CalculatorHistoryRepository,
|
||||
) : ViewModel() {
|
||||
private val _userPrefs: StateFlow<UserPreferences> =
|
||||
userPrefsRepository.userPreferencesFlow.stateIn(
|
||||
private val _userPrefs: StateFlow<MainPreferences> =
|
||||
userPrefsRepository.mainPreferencesFlow.stateIn(
|
||||
viewModelScope,
|
||||
SharingStarted.WhileSubscribed(5000L),
|
||||
UserPreferences()
|
||||
MainPreferences()
|
||||
)
|
||||
|
||||
private val _input: MutableStateFlow<TextFieldValue> = MutableStateFlow(TextFieldValue())
|
||||
|
@ -36,7 +36,6 @@ dependencies {
|
||||
kapt(libs.androidx.room.compiler)
|
||||
testImplementation(libs.androidx.datastore)
|
||||
|
||||
implementation(libs.com.github.sadellie.themmo)
|
||||
implementation(libs.com.squareup.moshi)
|
||||
implementation(libs.com.squareup.retrofit2)
|
||||
|
||||
|
@ -39,7 +39,7 @@ import com.sadellie.unitto.data.units.MyUnitIDS
|
||||
import com.sadellie.unitto.data.units.combine
|
||||
import com.sadellie.unitto.data.units.remote.CurrencyApi
|
||||
import com.sadellie.unitto.data.units.remote.CurrencyUnitResponse
|
||||
import com.sadellie.unitto.data.userprefs.UserPreferences
|
||||
import com.sadellie.unitto.data.userprefs.MainPreferences
|
||||
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import io.github.sadellie.evaluatto.Expression
|
||||
@ -65,10 +65,10 @@ class ConverterViewModel @Inject constructor(
|
||||
private val allUnitsRepository: AllUnitsRepository
|
||||
) : ViewModel() {
|
||||
|
||||
private val _userPrefs = userPrefsRepository.userPreferencesFlow.stateIn(
|
||||
private val _userPrefs = userPrefsRepository.mainPreferencesFlow.stateIn(
|
||||
viewModelScope,
|
||||
SharingStarted.WhileSubscribed(5000),
|
||||
UserPreferences()
|
||||
MainPreferences()
|
||||
)
|
||||
|
||||
/**
|
||||
@ -334,7 +334,7 @@ class ConverterViewModel @Inject constructor(
|
||||
|
||||
private fun loadInitialUnitPair() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val initialUserPrefs = userPrefsRepository.userPreferencesFlow.first()
|
||||
val initialUserPrefs = userPrefsRepository.mainPreferencesFlow.first()
|
||||
|
||||
// First we load latest pair of units
|
||||
_unitFrom.update {
|
||||
|
@ -43,6 +43,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.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.sadellie.unitto.core.base.BuildConfig
|
||||
import com.sadellie.unitto.core.base.R
|
||||
@ -54,7 +55,7 @@ import com.sadellie.unitto.core.ui.openLink
|
||||
internal fun AboutScreen(
|
||||
navigateUpAction: () -> Unit,
|
||||
navigateToThirdParty: () -> Unit,
|
||||
viewModel: SettingsViewModel
|
||||
viewModel: SettingsViewModel = hiltViewModel()
|
||||
) {
|
||||
val mContext = LocalContext.current
|
||||
val userPrefs = viewModel.userPrefs.collectAsStateWithLifecycle()
|
||||
|
@ -43,6 +43,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.sadellie.unitto.core.base.BuildConfig
|
||||
import com.sadellie.unitto.core.base.OUTPUT_FORMAT
|
||||
@ -63,7 +64,7 @@ import com.sadellie.unitto.feature.settings.navigation.unitsGroupRoute
|
||||
|
||||
@Composable
|
||||
internal fun SettingsScreen(
|
||||
viewModel: SettingsViewModel,
|
||||
viewModel: SettingsViewModel = hiltViewModel(),
|
||||
menuButtonClick: () -> Unit,
|
||||
navControllerAction: (String) -> Unit
|
||||
) {
|
||||
|
@ -18,80 +18,27 @@
|
||||
|
||||
package com.sadellie.unitto.feature.settings
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.sadellie.unitto.data.model.UnitGroup
|
||||
import com.sadellie.unitto.data.model.UnitsListSorting
|
||||
import com.sadellie.unitto.data.unitgroups.UnitGroupsRepository
|
||||
import com.sadellie.unitto.data.userprefs.UserPreferences
|
||||
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import io.github.sadellie.themmo.MonetMode
|
||||
import io.github.sadellie.themmo.ThemingMode
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.burnoutcrew.reorderable.ItemPosition
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class SettingsViewModel @Inject constructor(
|
||||
private val userPrefsRepository: UserPreferencesRepository,
|
||||
private val unitGroupsRepository: UnitGroupsRepository,
|
||||
) : ViewModel() {
|
||||
val userPrefs = userPrefsRepository.userPreferencesFlow
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000),
|
||||
val userPrefs = userPrefsRepository.allPreferencesFlow
|
||||
.stateIn(
|
||||
viewModelScope,
|
||||
SharingStarted.WhileSubscribed(5000),
|
||||
UserPreferences()
|
||||
)
|
||||
val shownUnitGroups = unitGroupsRepository.shownUnitGroups
|
||||
val hiddenUnitGroups = unitGroupsRepository.hiddenUnitGroups
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateThemingMode
|
||||
*/
|
||||
fun updateThemingMode(themingMode: ThemingMode) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateThemingMode(themingMode)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateDynamicTheme
|
||||
*/
|
||||
fun updateDynamicTheme(enabled: Boolean) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateDynamicTheme(enabled)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateAmoledTheme
|
||||
*/
|
||||
fun updateAmoledTheme(enabled: Boolean) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateAmoledTheme(enabled)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateCustomColor
|
||||
*/
|
||||
fun updateCustomColor(color: Color) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateCustomColor(color)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateMonetMode
|
||||
*/
|
||||
fun updateMonetMode(monetMode: MonetMode) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateMonetMode(monetMode)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateDigitsPrecision
|
||||
@ -138,46 +85,6 @@ class SettingsViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UnitGroupsRepository.markUnitGroupAsHidden
|
||||
* @see UserPreferencesRepository.updateShownUnitGroups
|
||||
*/
|
||||
fun hideUnitGroup(unitGroup: UnitGroup) {
|
||||
viewModelScope.launch {
|
||||
unitGroupsRepository.markUnitGroupAsHidden(unitGroup)
|
||||
userPrefsRepository.updateShownUnitGroups(unitGroupsRepository.shownUnitGroups.value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UnitGroupsRepository.markUnitGroupAsShown
|
||||
* @see UserPreferencesRepository.updateShownUnitGroups
|
||||
*/
|
||||
fun returnUnitGroup(unitGroup: UnitGroup) {
|
||||
viewModelScope.launch {
|
||||
unitGroupsRepository.markUnitGroupAsShown(unitGroup)
|
||||
userPrefsRepository.updateShownUnitGroups(unitGroupsRepository.shownUnitGroups.value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UnitGroupsRepository.moveShownUnitGroups
|
||||
*/
|
||||
fun onMove(from: ItemPosition, to: ItemPosition) {
|
||||
viewModelScope.launch {
|
||||
unitGroupsRepository.moveShownUnitGroups(from, to)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateShownUnitGroups
|
||||
*/
|
||||
fun onDragEnd() {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateShownUnitGroups(unitGroupsRepository.shownUnitGroups.value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateToolsExperiment
|
||||
*/
|
||||
@ -204,20 +111,4 @@ class SettingsViewModel @Inject constructor(
|
||||
userPrefsRepository.updateUnitConverterSorting(sorting)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent from dragging over non-draggable items (headers and hidden)
|
||||
*
|
||||
* @param pos Position we are dragging over.
|
||||
* @return True if can drag over given item.
|
||||
*/
|
||||
fun canDragOver(pos: ItemPosition) = shownUnitGroups.value.any { it == pos.key }
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
unitGroupsRepository.updateShownGroups(
|
||||
userPrefsRepository.userPreferencesFlow.first().shownUnitGroups
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,10 +27,9 @@ import androidx.navigation.compose.navigation
|
||||
import com.sadellie.unitto.core.base.TopLevelDestinations
|
||||
import com.sadellie.unitto.feature.settings.AboutScreen
|
||||
import com.sadellie.unitto.feature.settings.SettingsScreen
|
||||
import com.sadellie.unitto.feature.settings.SettingsViewModel
|
||||
import com.sadellie.unitto.feature.settings.ThemesRoute
|
||||
import com.sadellie.unitto.feature.settings.themes.ThemesRoute
|
||||
import com.sadellie.unitto.feature.settings.ThirdPartyLicensesScreen
|
||||
import com.sadellie.unitto.feature.settings.UnitGroupsScreen
|
||||
import com.sadellie.unitto.feature.settings.unitgroups.UnitGroupsScreen
|
||||
import io.github.sadellie.themmo.ThemmoController
|
||||
|
||||
private val settingsGraph: String by lazy { TopLevelDestinations.Settings.route }
|
||||
@ -49,7 +48,6 @@ fun NavController.navigateToUnitGroups() {
|
||||
}
|
||||
|
||||
fun NavGraphBuilder.settingGraph(
|
||||
settingsViewModel: SettingsViewModel,
|
||||
themmoController: ThemmoController,
|
||||
navController: NavHostController,
|
||||
menuButtonClick: () -> Unit
|
||||
@ -57,37 +55,34 @@ fun NavGraphBuilder.settingGraph(
|
||||
navigation(settingsRoute, settingsGraph) {
|
||||
composable(settingsRoute) {
|
||||
SettingsScreen(
|
||||
viewModel = settingsViewModel,
|
||||
menuButtonClick = menuButtonClick
|
||||
) { route -> navController.navigate(route) }
|
||||
menuButtonClick = menuButtonClick,
|
||||
navControllerAction = navController::navigate
|
||||
)
|
||||
}
|
||||
|
||||
composable(themesRoute) {
|
||||
ThemesRoute(
|
||||
navigateUpAction = { navController.navigateUp() },
|
||||
navigateUpAction = navController::navigateUp,
|
||||
themmoController = themmoController,
|
||||
viewModel = settingsViewModel
|
||||
)
|
||||
}
|
||||
|
||||
composable(thirdPartyRoute) {
|
||||
ThirdPartyLicensesScreen(
|
||||
navigateUpAction = { navController.navigateUp() }
|
||||
navigateUpAction = navController::navigateUp,
|
||||
)
|
||||
}
|
||||
|
||||
composable(aboutRoute) {
|
||||
AboutScreen(
|
||||
navigateUpAction = { navController.navigateUp() },
|
||||
navigateUpAction = navController::navigateUp,
|
||||
navigateToThirdParty = { navController.navigate(thirdPartyRoute) },
|
||||
viewModel = settingsViewModel
|
||||
)
|
||||
}
|
||||
|
||||
composable(unitsGroupRoute) {
|
||||
UnitGroupsScreen(
|
||||
viewModel = settingsViewModel,
|
||||
navigateUpAction = { navController.navigateUp() }
|
||||
navigateUpAction = navController::navigateUp,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.feature.settings
|
||||
package com.sadellie.unitto.feature.settings.themes
|
||||
|
||||
import android.os.Build
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
@ -49,6 +49,7 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.sadellie.unitto.core.base.R
|
||||
import com.sadellie.unitto.core.ui.common.Header
|
||||
import com.sadellie.unitto.core.ui.common.NavigateUpButton
|
||||
@ -82,7 +83,7 @@ private val colorSchemes: List<Color> by lazy {
|
||||
internal fun ThemesRoute(
|
||||
navigateUpAction: () -> Unit = {},
|
||||
themmoController: ThemmoController,
|
||||
viewModel: SettingsViewModel
|
||||
viewModel: ThemesViewModel = hiltViewModel()
|
||||
) {
|
||||
ThemesScreen(
|
||||
navigateUpAction = navigateUpAction,
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 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.settings.themes
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import io.github.sadellie.themmo.MonetMode
|
||||
import io.github.sadellie.themmo.ThemingMode
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class ThemesViewModel @Inject constructor(
|
||||
private val userPrefsRepository: UserPreferencesRepository
|
||||
) : ViewModel() {
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateThemingMode
|
||||
*/
|
||||
fun updateThemingMode(themingMode: ThemingMode) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateThemingMode(themingMode)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateDynamicTheme
|
||||
*/
|
||||
fun updateDynamicTheme(enabled: Boolean) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateDynamicTheme(enabled)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateAmoledTheme
|
||||
*/
|
||||
fun updateAmoledTheme(enabled: Boolean) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateAmoledTheme(enabled)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateCustomColor
|
||||
*/
|
||||
fun updateCustomColor(color: Color) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateCustomColor(color)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateMonetMode
|
||||
*/
|
||||
fun updateMonetMode(monetMode: MonetMode) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateMonetMode(monetMode)
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.feature.settings
|
||||
package com.sadellie.unitto.feature.settings.unitgroups
|
||||
|
||||
import androidx.compose.animation.animateColor
|
||||
import androidx.compose.animation.core.animateDp
|
||||
@ -40,13 +40,14 @@ import androidx.compose.material3.ListItemDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.sadellie.unitto.core.base.R
|
||||
import com.sadellie.unitto.core.ui.common.Header
|
||||
import com.sadellie.unitto.core.ui.common.NavigateUpButton
|
||||
@ -59,21 +60,20 @@ import org.burnoutcrew.reorderable.reorderable
|
||||
|
||||
@Composable
|
||||
internal fun UnitGroupsScreen(
|
||||
viewModel: SettingsViewModel,
|
||||
viewModel: UnitGroupsViewModel = hiltViewModel(),
|
||||
navigateUpAction: () -> Unit
|
||||
) {
|
||||
val uiState = viewModel.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
UnittoScreenWithLargeTopBar(
|
||||
title = stringResource(R.string.unit_groups_setting),
|
||||
navigationIcon = { NavigateUpButton(navigateUpAction) }
|
||||
) { paddingValues ->
|
||||
|
||||
val shownUnits = viewModel.shownUnitGroups.collectAsState()
|
||||
val hiddenUnits = viewModel.hiddenUnitGroups.collectAsState()
|
||||
|
||||
val state = rememberReorderableLazyListState(
|
||||
onMove = viewModel::onMove,
|
||||
onMove = viewModel::moveShownUnitGroups,
|
||||
canDragOver = { from, _ -> viewModel.canDragOver(from) },
|
||||
onDragEnd = { _, _ -> viewModel.onDragEnd() }
|
||||
onDragEnd = { _, _ -> viewModel.saveShownUnitGroups() }
|
||||
)
|
||||
|
||||
LazyColumn(
|
||||
@ -89,7 +89,7 @@ internal fun UnitGroupsScreen(
|
||||
)
|
||||
}
|
||||
|
||||
items(shownUnits.value, { it }) { item ->
|
||||
items(uiState.value.shownGroups, { it }) { item ->
|
||||
ReorderableItem(state, key = item) { isDragging ->
|
||||
val transition = updateTransition(isDragging, label = "draggedTransition")
|
||||
val background by transition.animateColor(label = "background") {
|
||||
@ -104,7 +104,7 @@ internal fun UnitGroupsScreen(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = itemPadding)
|
||||
.clip(CircleShape)
|
||||
.clickable { viewModel.hideUnitGroup(item) }
|
||||
.clickable { viewModel.markUnitGroupAsHidden(item) }
|
||||
.detectReorderAfterLongPress(state),
|
||||
colors = ListItemDefaults.colors(
|
||||
containerColor = background
|
||||
@ -117,7 +117,7 @@ internal fun UnitGroupsScreen(
|
||||
modifier = Modifier.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(false),
|
||||
onClick = { viewModel.hideUnitGroup(item) }
|
||||
onClick = { viewModel.markUnitGroupAsHidden(item) }
|
||||
)
|
||||
)
|
||||
},
|
||||
@ -147,11 +147,11 @@ internal fun UnitGroupsScreen(
|
||||
)
|
||||
}
|
||||
|
||||
items(hiddenUnits.value, { it }) {
|
||||
items(uiState.value.hiddenGroups, { it }) {
|
||||
ListItem(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.surface)
|
||||
.clickable { viewModel.returnUnitGroup(it) }
|
||||
.clickable { viewModel.markUnitGroupAsShown(it) }
|
||||
.animateItemPlacement(),
|
||||
headlineContent = { Text(stringResource(it.res)) },
|
||||
trailingContent = {
|
||||
@ -162,7 +162,7 @@ internal fun UnitGroupsScreen(
|
||||
modifier = Modifier.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(false),
|
||||
onClick = { viewModel.returnUnitGroup(it) }
|
||||
onClick = { viewModel.markUnitGroupAsShown(it) }
|
||||
)
|
||||
)
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 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.settings.unitgroups
|
||||
|
||||
import com.sadellie.unitto.data.model.UnitGroup
|
||||
|
||||
data class UnitGroupsUIState(
|
||||
val shownGroups: List<UnitGroup>,
|
||||
val hiddenGroups: List<UnitGroup>
|
||||
)
|
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 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.settings.unitgroups
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
|
||||
import com.sadellie.unitto.data.model.UnitGroup
|
||||
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
|
||||
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 kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import org.burnoutcrew.reorderable.ItemPosition
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class UnitGroupsViewModel @Inject constructor(
|
||||
private val userPreferencesRepository: UserPreferencesRepository,
|
||||
) : ViewModel() {
|
||||
|
||||
private var mutex: Mutex = Mutex()
|
||||
|
||||
/**
|
||||
* Currently shown [UnitGroup]s.
|
||||
*/
|
||||
private val _shownUnitGroups = MutableStateFlow(listOf<UnitGroup>())
|
||||
|
||||
/**
|
||||
* Currently hidden [UnitGroup]s.
|
||||
*/
|
||||
private val _hiddenUnitGroups = MutableStateFlow(listOf<UnitGroup>())
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
val shown = userPreferencesRepository.mainPreferencesFlow.first().shownUnitGroups
|
||||
mutex.withLock {
|
||||
_shownUnitGroups.update { shown }
|
||||
_hiddenUnitGroups.update { ALL_UNIT_GROUPS - shown.toSet() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val uiState = combine(_shownUnitGroups, _hiddenUnitGroups) { shown, hidden ->
|
||||
return@combine UnitGroupsUIState(
|
||||
shownGroups = shown,
|
||||
hiddenGroups = hidden
|
||||
)
|
||||
}.stateIn(
|
||||
viewModelScope,
|
||||
SharingStarted.WhileSubscribed(5000L),
|
||||
UnitGroupsUIState(emptyList(), emptyList())
|
||||
)
|
||||
|
||||
/**
|
||||
* Moves [UnitGroup] from [_shownUnitGroups] to [_hiddenUnitGroups]
|
||||
*
|
||||
* @param unitGroup [UnitGroup] to hide.
|
||||
*/
|
||||
fun markUnitGroupAsHidden(unitGroup: UnitGroup) = viewModelScope.launch {
|
||||
mutex.withLock {
|
||||
_shownUnitGroups.update { it - unitGroup }
|
||||
// Newly hidden unit will appear at the top of the list
|
||||
_hiddenUnitGroups.update { listOf(unitGroup) + it }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves [UnitGroup] from [_hiddenUnitGroups] to [_shownUnitGroups]
|
||||
*
|
||||
* @param unitGroup [UnitGroup] to show.
|
||||
*/
|
||||
fun markUnitGroupAsShown(unitGroup: UnitGroup) = viewModelScope.launch {
|
||||
mutex.withLock {
|
||||
_hiddenUnitGroups.update { it - unitGroup }
|
||||
_shownUnitGroups.update { it + unitGroup }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves [UnitGroup] in [_shownUnitGroups] from one index to another (reorder).
|
||||
*
|
||||
* @param from Position from which we need to move from
|
||||
* @param to Position where to put [UnitGroup]
|
||||
*/
|
||||
fun moveShownUnitGroups(from: ItemPosition, to: ItemPosition) = viewModelScope.launch {
|
||||
mutex.withLock {
|
||||
_shownUnitGroups.update { shown ->
|
||||
shown.toMutableList().apply {
|
||||
val initialIndex = shown.indexOfFirst { it == from.key }
|
||||
/**
|
||||
* No such item. Happens when dragging item and clicking "remove" while item is
|
||||
* still being dragged.
|
||||
*/
|
||||
if (initialIndex == -1) return@launch
|
||||
|
||||
add(
|
||||
shown.indexOfFirst { it == to.key },
|
||||
removeAt(initialIndex)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun canDragOver(pos: ItemPosition) = uiState.value.shownGroups.any { it == pos.key }
|
||||
|
||||
fun saveShownUnitGroups() = viewModelScope.launch {
|
||||
userPreferencesRepository.updateShownUnitGroups(
|
||||
uiState.value.shownGroups
|
||||
)
|
||||
}
|
||||
}
|
@ -26,9 +26,8 @@ import com.sadellie.unitto.data.database.UnitsEntity
|
||||
import com.sadellie.unitto.data.database.UnitsRepository
|
||||
import com.sadellie.unitto.data.model.AbstractUnit
|
||||
import com.sadellie.unitto.data.model.UnitGroup
|
||||
import com.sadellie.unitto.data.unitgroups.UnitGroupsRepository
|
||||
import com.sadellie.unitto.data.units.AllUnitsRepository
|
||||
import com.sadellie.unitto.data.userprefs.UserPreferences
|
||||
import com.sadellie.unitto.data.userprefs.MainPreferences
|
||||
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -48,33 +47,30 @@ class UnitsListViewModel @Inject constructor(
|
||||
private val allUnitsRepository: AllUnitsRepository,
|
||||
private val mContext: Application,
|
||||
private val userPrefsRepository: UserPreferencesRepository,
|
||||
unitGroupsRepository: UnitGroupsRepository,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _userPrefs: StateFlow<UserPreferences> =
|
||||
userPrefsRepository.userPreferencesFlow.stateIn(
|
||||
private val _userPrefs: StateFlow<MainPreferences> =
|
||||
userPrefsRepository.mainPreferencesFlow.stateIn(
|
||||
viewModelScope,
|
||||
SharingStarted.WhileSubscribed(5000L),
|
||||
UserPreferences()
|
||||
MainPreferences()
|
||||
)
|
||||
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(
|
||||
_userPrefs,
|
||||
_unitsToShow,
|
||||
_searchQuery,
|
||||
_chosenUnitGroup,
|
||||
_shownUnitGroups,
|
||||
) { userPrefs, unitsToShow, searchQuery, chosenUnitGroup, shownUnitGroups ->
|
||||
) { userPrefs, unitsToShow, searchQuery, chosenUnitGroup ->
|
||||
return@combine SecondScreenUIState(
|
||||
favoritesOnly = userPrefs.unitConverterFavoritesOnly,
|
||||
unitsToShow = unitsToShow,
|
||||
searchQuery = searchQuery,
|
||||
chosenUnitGroup = chosenUnitGroup,
|
||||
shownUnitGroups = shownUnitGroups,
|
||||
shownUnitGroups = userPrefs.shownUnitGroups,
|
||||
formatterSymbols = AllFormatterSymbols.getById(userPrefs.separator)
|
||||
)
|
||||
}
|
||||
@ -136,7 +132,7 @@ class UnitsListViewModel @Inject constructor(
|
||||
chosenUnitGroup = _chosenUnitGroup.value,
|
||||
favoritesOnly = _userPrefs.value.unitConverterFavoritesOnly,
|
||||
searchQuery = _searchQuery.value,
|
||||
allUnitsGroups = _shownUnitGroups.value,
|
||||
allUnitsGroups = _userPrefs.value.shownUnitGroups,
|
||||
sorting = _userPrefs.value.unitConverterSorting
|
||||
)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user