Refactor UnitGroupsScreen

This commit is contained in:
Sad Ellie 2024-02-06 18:07:25 +03:00
parent 5c81a1c675
commit 32eb7422d5
13 changed files with 219 additions and 238 deletions

View File

@ -21,17 +21,10 @@ package com.sadellie.unitto.data.model
import androidx.annotation.StringRes
import com.sadellie.unitto.core.base.R
val ALL_UNIT_GROUPS: List<UnitGroup> by lazy {
UnitGroup.entries
}
/**
* As not all measurements can be converted between each other, we separate them into groups.
* Within one group all measurements can be converted
*/
enum class UnitGroup(
@StringRes val res: Int
) {
// NOTE: This order is used as default for new users
LENGTH(res = R.string.unit_group_length),
CURRENCY(res = R.string.unit_group_currency),
MASS(res = R.string.unit_group_mass),

View File

@ -71,6 +71,10 @@ interface UserPreferencesRepository {
suspend fun updateShownUnitGroups(shownUnitGroups: List<UnitGroup>)
suspend fun addShownUnitGroup(unitGroup: UnitGroup)
suspend fun removeShownUnitGroup(unitGroup: UnitGroup)
suspend fun updateLastReadChangelog(value: String)
suspend fun updateVibrations(enabled: Boolean)

View File

@ -23,90 +23,105 @@ import com.sadellie.unitto.core.base.OutputFormat
import com.sadellie.unitto.core.base.Separator
import com.sadellie.unitto.core.base.TopLevelDestinations
import com.sadellie.unitto.data.converter.UnitID
import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.UnitsListSorting
import io.github.sadellie.themmo.core.MonetMode
import io.github.sadellie.themmo.core.ThemingMode
fun Preferences.getEnableDynamicTheme(): Boolean {
internal fun Preferences.getEnableDynamicTheme(): Boolean {
return this[PrefsKeys.ENABLE_DYNAMIC_THEME] ?: true
}
fun Preferences.getThemingMode(): ThemingMode {
internal fun Preferences.getThemingMode(): ThemingMode {
return this[PrefsKeys.THEMING_MODE]
?.letTryOrNull { ThemingMode.valueOf(it) }
?: ThemingMode.AUTO
}
fun Preferences.getEnableAmoledTheme(): Boolean {
internal fun Preferences.getEnableAmoledTheme(): Boolean {
return this[PrefsKeys.ENABLE_AMOLED_THEME] ?: false
}
fun Preferences.getCustomColor(): Long {
internal fun Preferences.getCustomColor(): Long {
return this[PrefsKeys.CUSTOM_COLOR] ?: 16L // From Color.Unspecified
}
fun Preferences.getMonetMode(): MonetMode {
internal fun Preferences.getMonetMode(): MonetMode {
return this[PrefsKeys.MONET_MODE]
?.letTryOrNull { MonetMode.valueOf(it) }
?: MonetMode.TonalSpot
}
fun Preferences.getStartingScreen(): String {
internal fun Preferences.getStartingScreen(): String {
return this[PrefsKeys.STARTING_SCREEN] ?: TopLevelDestinations.CALCULATOR_GRAPH
}
fun Preferences.getEnableToolsExperiment(): Boolean {
internal fun Preferences.getEnableToolsExperiment(): Boolean {
return this[PrefsKeys.ENABLE_TOOLS_EXPERIMENT] ?: false
}
fun Preferences.getSystemFont(): Boolean {
internal fun Preferences.getSystemFont(): Boolean {
return this[PrefsKeys.SYSTEM_FONT] ?: false
}
fun Preferences.getLastReadChangelog(): String {
internal fun Preferences.getLastReadChangelog(): String {
return this[PrefsKeys.LAST_READ_CHANGELOG] ?: ""
}
fun Preferences.getEnableVibrations(): Boolean {
internal fun Preferences.getEnableVibrations(): Boolean {
return this[PrefsKeys.ENABLE_VIBRATIONS] ?: true
}
fun Preferences.getRadianMode(): Boolean {
internal fun Preferences.getRadianMode(): Boolean {
return this[PrefsKeys.RADIAN_MODE] ?: true
}
fun Preferences.getSeparator(): Int {
internal fun Preferences.getSeparator(): Int {
return this[PrefsKeys.SEPARATOR] ?: Separator.SPACE
}
fun Preferences.getMiddleZero(): Boolean {
internal fun Preferences.getMiddleZero(): Boolean {
return this[PrefsKeys.MIDDLE_ZERO] ?: true
}
fun Preferences.getPartialHistoryView(): Boolean {
internal fun Preferences.getPartialHistoryView(): Boolean {
return this[PrefsKeys.PARTIAL_HISTORY_VIEW] ?: true
}
fun Preferences.getDigitsPrecision(): Int {
internal fun Preferences.getDigitsPrecision(): Int {
return this[PrefsKeys.DIGITS_PRECISION] ?: 3
}
fun Preferences.getOutputFormat(): Int {
internal fun Preferences.getOutputFormat(): Int {
return this[PrefsKeys.OUTPUT_FORMAT] ?: OutputFormat.PLAIN
}
fun Preferences.getUnitConverterFormatTime(): Boolean {
internal fun Preferences.getUnitConverterFormatTime(): Boolean {
return this[PrefsKeys.UNIT_CONVERTER_FORMAT_TIME] ?: false
}
fun Preferences.getUnitConverterSorting(): UnitsListSorting {
internal fun Preferences.getUnitConverterSorting(): UnitsListSorting {
return this[PrefsKeys.UNIT_CONVERTER_SORTING]
?.let { UnitsListSorting.valueOf(it) } ?: UnitsListSorting.USAGE
}
fun Preferences.getShownUnitGroups(): List<UnitGroup> {
// TODO Remove when 80% users are on sets
internal fun Preferences.getShownUnitGroups(): List<UnitGroup> {
// Uncomment once legacy is gone
// return this[PrefsKeys.ENABLED_UNIT_GROUPS]
// ?.letTryOrNull { stringSet: Set<String> ->
// stringSet.map { UnitGroup.valueOf(it) }
// } ?: UnitGroup.entries
// Try new method
val unitGroups: List<UnitGroup>? = this[PrefsKeys.ENABLED_UNIT_GROUPS]
?.letTryOrNull { stringSet: Set<String> ->
stringSet.map { UnitGroup.valueOf(it) }
}
if (!unitGroups.isNullOrEmpty()) return unitGroups
// Failed to get from sets, try old method
return this[PrefsKeys.SHOWN_UNIT_GROUPS]
?.letTryOrNull { list ->
list
@ -114,23 +129,23 @@ fun Preferences.getShownUnitGroups(): List<UnitGroup> {
.split(",")
.map { UnitGroup.valueOf(it) }
}
?: ALL_UNIT_GROUPS
?: UnitGroup.entries
}
fun Preferences.getUnitConverterFavoritesOnly(): Boolean {
internal fun Preferences.getUnitConverterFavoritesOnly(): Boolean {
return this[PrefsKeys.UNIT_CONVERTER_FAVORITES_ONLY]
?: false
}
fun Preferences.getLatestLeftSide(): String {
internal fun Preferences.getLatestLeftSide(): String {
return this[PrefsKeys.LATEST_LEFT_SIDE] ?: UnitID.kilometer
}
fun Preferences.getLatestRightSide(): String {
internal fun Preferences.getLatestRightSide(): String {
return this[PrefsKeys.LATEST_RIGHT_SIDE] ?: UnitID.mile
}
fun Preferences.getAcButton(): Boolean {
internal fun Preferences.getAcButton(): Boolean {
return this[PrefsKeys.AC_BUTTON] ?: true
}

View File

@ -18,7 +18,6 @@
package com.sadellie.unitto.data.userprefs
import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.data.model.userprefs.AboutPreferences
@ -90,7 +89,7 @@ data class FormattingPreferencesImpl(
) : FormattingPreferences
data class UnitGroupsPreferencesImpl(
override val shownUnitGroups: List<UnitGroup> = ALL_UNIT_GROUPS,
override val shownUnitGroups: List<UnitGroup> = UnitGroup.entries,
) : UnitGroupsPreferences
data class AddSubtractPreferencesImpl(

View File

@ -22,6 +22,7 @@ import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.core.stringSetPreferencesKey
object PrefsKeys {
// COMMON
@ -52,6 +53,7 @@ object PrefsKeys {
val LATEST_LEFT_SIDE = stringPreferencesKey("LATEST_LEFT_SIDE_PREF_KEY")
val LATEST_RIGHT_SIDE = stringPreferencesKey("LATEST_RIGHT_SIDE_PREF_KEY")
val SHOWN_UNIT_GROUPS = stringPreferencesKey("SHOWN_UNIT_GROUPS_PREF_KEY")
val ENABLED_UNIT_GROUPS = stringSetPreferencesKey("ENABLED_UNIT_GROUPS_PREF_KEY")
val UNIT_CONVERTER_FAVORITES_ONLY = booleanPreferencesKey("UNIT_CONVERTER_FAVORITES_ONLY_PREF_KEY")
val UNIT_CONVERTER_FORMAT_TIME = booleanPreferencesKey("UNIT_CONVERTER_FORMAT_TIME_PREF_KEY")
val UNIT_CONVERTER_SORTING = stringPreferencesKey("UNIT_CONVERTER_SORTING_PREF_KEY")

View File

@ -221,7 +221,25 @@ class UserPreferencesRepositoryImpl @Inject constructor(
override suspend fun updateShownUnitGroups(shownUnitGroups: List<UnitGroup>) {
dataStore.edit { preferences ->
preferences[PrefsKeys.SHOWN_UNIT_GROUPS] = shownUnitGroups.joinToString(",")
preferences[PrefsKeys.ENABLED_UNIT_GROUPS] = shownUnitGroups
.map { it.name }
.toSet()
}
}
override suspend fun addShownUnitGroup(unitGroup: UnitGroup) {
dataStore.edit { preferences ->
preferences[PrefsKeys.ENABLED_UNIT_GROUPS] = preferences[PrefsKeys.ENABLED_UNIT_GROUPS]
?.plus(unitGroup.name)
?: emptySet()
}
}
override suspend fun removeShownUnitGroup(unitGroup: UnitGroup) {
dataStore.edit { preferences ->
preferences[PrefsKeys.ENABLED_UNIT_GROUPS] = preferences[PrefsKeys.ENABLED_UNIT_GROUPS]
?.minus(unitGroup.name)
?: emptySet()
}
}

View File

@ -41,7 +41,6 @@ import androidx.compose.ui.unit.dp
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.ui.common.AssistChip
import com.sadellie.unitto.core.ui.common.FilterChip
import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
import com.sadellie.unitto.data.model.UnitGroup
/**
@ -55,7 +54,7 @@ import com.sadellie.unitto.data.model.UnitGroup
*/
@Composable
internal fun ChipsRow(
items: List<UnitGroup> = ALL_UNIT_GROUPS,
items: List<UnitGroup> = UnitGroup.entries,
chosenUnitGroup: UnitGroup?,
selectAction: (UnitGroup?) -> Unit,
navigateToSettingsAction: () -> Unit,
@ -105,7 +104,7 @@ fun PreviewUnittoChips() {
}
ChipsRow(
items = ALL_UNIT_GROUPS,
items = UnitGroup.entries,
chosenUnitGroup = selected,
selectAction = { selectAction(it) },
navigateToSettingsAction = {},

View File

@ -41,7 +41,7 @@ import com.sadellie.unitto.core.ui.common.EmptyScreen
import com.sadellie.unitto.core.ui.common.ListItem
import com.sadellie.unitto.core.ui.common.NavigateUpButton
import com.sadellie.unitto.core.ui.common.ScaffoldWithLargeTopBar
import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.data.model.userprefs.ConverterPreferences
import com.sadellie.unitto.data.userprefs.ConverterPreferencesImpl
@ -139,7 +139,7 @@ private fun PreviewConverterSettingsScreen() {
outputFormat = OutputFormat.PLAIN,
unitConverterFormatTime = false,
unitConverterSorting = UnitsListSorting.USAGE,
shownUnitGroups = ALL_UNIT_GROUPS,
shownUnitGroups = UnitGroup.entries,
unitConverterFavoritesOnly = false,
enableToolsExperiment = false,
latestLeftSideUnit = "kilometer",

View File

@ -34,7 +34,7 @@ import com.sadellie.unitto.feature.settings.formatting.FormattingRoute
import com.sadellie.unitto.feature.settings.language.LanguageRoute
import com.sadellie.unitto.feature.settings.startingscreen.StartingScreenRoute
import com.sadellie.unitto.feature.settings.thirdparty.ThirdPartyLicensesScreen
import com.sadellie.unitto.feature.settings.unitgroups.UnitGroupsScreen
import com.sadellie.unitto.feature.settings.unitgroups.UnitGroupsRoute
import io.github.sadellie.themmo.ThemmoController
private val graph = DrawerItem.Settings.graph
@ -115,7 +115,7 @@ fun NavGraphBuilder.settingGraph(
}
unittoStackedComposable(unitsGroupRoute) {
UnitGroupsScreen(
UnitGroupsRoute(
navigateUpAction = navController::navigateUp,
)
}

View File

@ -1,115 +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.settings.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)
)
}
}
}
}

View File

@ -40,18 +40,23 @@ 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.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
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 androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.ui.common.EmptyScreen
import com.sadellie.unitto.core.ui.common.Header
import com.sadellie.unitto.core.ui.common.NavigateUpButton
import com.sadellie.unitto.core.ui.common.ScaffoldWithLargeTopBar
import com.sadellie.unitto.data.model.UnitGroup
import org.burnoutcrew.reorderable.ReorderableItem
import org.burnoutcrew.reorderable.detectReorder
import org.burnoutcrew.reorderable.detectReorderAfterLongPress
@ -59,22 +64,52 @@ import org.burnoutcrew.reorderable.rememberReorderableLazyListState
import org.burnoutcrew.reorderable.reorderable
@Composable
internal fun UnitGroupsScreen(
internal fun UnitGroupsRoute(
viewModel: UnitGroupsViewModel = hiltViewModel(),
navigateUpAction: () -> Unit,
) {
when (val uiState = viewModel.uiState.collectAsStateWithLifecycle().value) {
UnitGroupsUIState.Loading -> EmptyScreen()
is UnitGroupsUIState.Ready -> UnitGroupsScreen(
uiState = uiState,
navigateUpAction = navigateUpAction,
updateShownUnitGroups = viewModel::updateShownUnitGroups,
addShownUnitGroup = viewModel::addShownUnitGroup,
removeShownUnitGroup = viewModel::removeShownUnitGroup,
)
}
}
@Composable
private fun UnitGroupsScreen(
uiState: UnitGroupsUIState.Ready,
navigateUpAction: () -> Unit,
updateShownUnitGroups: (List<UnitGroup>) -> Unit,
addShownUnitGroup: (UnitGroup) -> Unit,
removeShownUnitGroup: (UnitGroup) -> Unit,
) {
ScaffoldWithLargeTopBar(
title = stringResource(R.string.settings_unit_groups_title),
navigationIcon = { NavigateUpButton(navigateUpAction) }
) { paddingValues ->
val shownUnits = viewModel.shownUnitGroups.collectAsState()
val hiddenUnits = viewModel.hiddenUnitGroups.collectAsState()
val copiedShownList = rememberUpdatedState(uiState.shownUnitGroups) as MutableState
val state = rememberReorderableLazyListState(
onMove = viewModel::onMove,
canDragOver = { from, _ -> viewModel.canDragOver(from) },
onDragEnd = { _, _ -> viewModel.onDragEnd() }
onMove = { from, to ->
copiedShownList.value = copiedShownList.value
.toMutableList()
.apply {
// -1 for list header
add(to.index - 1, removeAt(from.index - 1))
}
},
canDragOver = { draggedOver, _ ->
// offset by 1 for list header
draggedOver.index in 1..(copiedShownList.value.lastIndex + 1)
},
onDragEnd = onDragEnd@{ from, to ->
if (from == to) return@onDragEnd
updateShownUnitGroups(copiedShownList.value)
}
)
LazyColumn(
@ -90,12 +125,18 @@ internal fun UnitGroupsScreen(
)
}
items(shownUnits.value, { it }) { item ->
items(copiedShownList.value, { it }) { item ->
ReorderableItem(state, key = item) { isDragging ->
val transition = updateTransition(isDragging, label = "draggedTransition")
val background by transition.animateColor(label = "background") {
if (it) MaterialTheme.colorScheme.primaryContainer else MaterialTheme.colorScheme.surface
}
val textColor by transition.animateColor(label = "background") {
if (it) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSurface
}
val iconColor by transition.animateColor(label = "background") {
if (it) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.outline
}
val itemPadding by transition.animateDp(label = "itemPadding") {
if (it) 16.dp else 0.dp
}
@ -105,28 +146,29 @@ internal fun UnitGroupsScreen(
modifier = Modifier
.padding(horizontal = itemPadding)
.clip(CircleShape)
.clickable { viewModel.hideUnitGroup(item) }
.clickable { removeShownUnitGroup(item) }
.detectReorderAfterLongPress(state),
colors = ListItemDefaults.colors(
containerColor = background
containerColor = background,
headlineColor = textColor,
leadingIconColor = iconColor,
trailingIconColor = iconColor,
),
leadingContent = {
Icon(
Icons.Default.RemoveCircle,
stringResource(R.string.settings_disable_unit_group_description),
tint = MaterialTheme.colorScheme.outline,
imageVector = Icons.Default.RemoveCircle,
contentDescription = stringResource(R.string.settings_disable_unit_group_description),
modifier = Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(false),
onClick = { viewModel.hideUnitGroup(item) }
onClick = { removeShownUnitGroup(item) }
)
)
},
trailingContent = {
Icon(
Icons.Default.DragHandle,
stringResource(R.string.settings_reorder_unit_group_description),
tint = MaterialTheme.colorScheme.outline,
imageVector = Icons.Default.DragHandle,
contentDescription = stringResource(R.string.settings_reorder_unit_group_description),
modifier = Modifier
.clickable(
interactionSource = remember { MutableInteractionSource() },
@ -148,11 +190,11 @@ internal fun UnitGroupsScreen(
)
}
items(hiddenUnits.value, { it }) {
items(uiState.hiddenUnitGroups, { it }) {
ListItem(
modifier = Modifier
.background(MaterialTheme.colorScheme.surface)
.clickable { viewModel.returnUnitGroup(it) }
.clickable { addShownUnitGroup(it) }
.animateItemPlacement(),
headlineContent = { Text(stringResource(it.res)) },
trailingContent = {
@ -163,7 +205,7 @@ internal fun UnitGroupsScreen(
modifier = Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(false),
onClick = { viewModel.returnUnitGroup(it) }
onClick = { addShownUnitGroup(it) }
)
)
}
@ -172,3 +214,20 @@ internal fun UnitGroupsScreen(
}
}
}
@Preview
@Composable
private fun PreviewUnitGroupsScreen() {
val shownUnitGroups = UnitGroup.entries.take(4)
UnitGroupsScreen(
uiState = UnitGroupsUIState.Ready(
shownUnitGroups = shownUnitGroups,
hiddenUnitGroups = UnitGroup.entries - shownUnitGroups.toSet()
),
navigateUpAction = {},
updateShownUnitGroups = {},
addShownUnitGroup = {},
removeShownUnitGroup = {},
)
}

View File

@ -0,0 +1,30 @@
/*
* 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.settings.unitgroups
import com.sadellie.unitto.data.model.UnitGroup
internal sealed class UnitGroupsUIState {
data object Loading: UnitGroupsUIState()
data class Ready(
val shownUnitGroups: List<UnitGroup>,
val hiddenUnitGroups: List<UnitGroup>
): UnitGroupsUIState()
}

View File

@ -20,75 +20,52 @@ package com.sadellie.unitto.feature.settings.unitgroups
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.data.common.stateIn
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.burnoutcrew.reorderable.ItemPosition
import javax.inject.Inject
@HiltViewModel
class UnitGroupsViewModel @Inject constructor(
internal class UnitGroupsViewModel @Inject constructor(
private val userPrefsRepository: UserPreferencesRepository,
private val unitGroupsRepository: UnitGroupsRepository,
) : ViewModel() {
val shownUnitGroups = unitGroupsRepository.shownUnitGroups
val hiddenUnitGroups = unitGroupsRepository.hiddenUnitGroups
/**
* @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)
}
}
/**
* 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.unitGroupsPrefs.first().shownUnitGroups
val uiState = userPrefsRepository.unitGroupsPrefs
.map {
UnitGroupsUIState.Ready(
shownUnitGroups = it.shownUnitGroups,
hiddenUnitGroups = UnitGroup.entries - it.shownUnitGroups.toSet()
)
}
.stateIn(viewModelScope, UnitGroupsUIState.Loading)
/**
* @see UserPreferencesRepository.removeShownUnitGroup
*/
fun removeShownUnitGroup(unitGroup: UnitGroup) {
viewModelScope.launch {
userPrefsRepository.removeShownUnitGroup(unitGroup)
}
}
/**
* @see UserPreferencesRepository.addShownUnitGroup
*/
fun addShownUnitGroup(unitGroup: UnitGroup) {
viewModelScope.launch {
userPrefsRepository.addShownUnitGroup(unitGroup)
}
}
/**
* @see UserPreferencesRepository.updateShownUnitGroups
*/
fun updateShownUnitGroups(unitGroups: List<UnitGroup>) {
viewModelScope.launch {
userPrefsRepository.updateShownUnitGroups(unitGroups)
}
}
}