diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/unitgroups/UnitGroupsRepository .kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/unitgroups/UnitGroupsRepository .kt
new file mode 100644
index 00000000..eb0decf0
--- /dev/null
+++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/unitgroups/UnitGroupsRepository .kt
@@ -0,0 +1,115 @@
+/*
+ * 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 .
+ */
+
+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())
+ private set
+
+ /**
+ * Currently hidden [UnitGroup]s.
+ */
+ var hiddenUnitGroups = MutableStateFlow(listOf())
+ 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) {
+ 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)
+ )
+ }
+ }
+ }
+}
diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/unitgroups/UnitGroupsScreen.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/unitgroups/UnitGroupsScreen.kt
index 520631ee..6956c7ed 100644
--- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/unitgroups/UnitGroupsScreen.kt
+++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/unitgroups/UnitGroupsScreen.kt
@@ -40,6 +40,7 @@ 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
@@ -47,7 +48,6 @@ 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
@@ -63,17 +63,18 @@ internal fun UnitGroupsScreen(
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::moveShownUnitGroups,
+ onMove = viewModel::onMove,
canDragOver = { from, _ -> viewModel.canDragOver(from) },
- onDragEnd = { _, _ -> viewModel.saveShownUnitGroups() }
+ onDragEnd = { _, _ -> viewModel.onDragEnd() }
)
LazyColumn(
@@ -89,7 +90,7 @@ internal fun UnitGroupsScreen(
)
}
- items(uiState.value.shownGroups, { it }) { item ->
+ items(shownUnits.value, { it }) { item ->
ReorderableItem(state, key = item) { isDragging ->
val transition = updateTransition(isDragging, label = "draggedTransition")
val background by transition.animateColor(label = "background") {
@@ -104,7 +105,7 @@ internal fun UnitGroupsScreen(
modifier = Modifier
.padding(horizontal = itemPadding)
.clip(CircleShape)
- .clickable { viewModel.markUnitGroupAsHidden(item) }
+ .clickable { viewModel.hideUnitGroup(item) }
.detectReorderAfterLongPress(state),
colors = ListItemDefaults.colors(
containerColor = background
@@ -117,7 +118,7 @@ internal fun UnitGroupsScreen(
modifier = Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(false),
- onClick = { viewModel.markUnitGroupAsHidden(item) }
+ onClick = { viewModel.hideUnitGroup(item) }
)
)
},
@@ -147,11 +148,11 @@ internal fun UnitGroupsScreen(
)
}
- items(uiState.value.hiddenGroups, { it }) {
+ items(hiddenUnits.value, { it }) {
ListItem(
modifier = Modifier
.background(MaterialTheme.colorScheme.surface)
- .clickable { viewModel.markUnitGroupAsShown(it) }
+ .clickable { viewModel.returnUnitGroup(it) }
.animateItemPlacement(),
headlineContent = { Text(stringResource(it.res)) },
trailingContent = {
@@ -162,7 +163,7 @@ internal fun UnitGroupsScreen(
modifier = Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(false),
- onClick = { viewModel.markUnitGroupAsShown(it) }
+ onClick = { viewModel.returnUnitGroup(it) }
)
)
}
diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/unitgroups/UnitGroupsUIState.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/unitgroups/UnitGroupsUIState.kt
deleted file mode 100644
index 3051e863..00000000
--- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/unitgroups/UnitGroupsUIState.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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 .
- */
-
-package com.sadellie.unitto.feature.settings.unitgroups
-
-import com.sadellie.unitto.data.model.UnitGroup
-
-data class UnitGroupsUIState(
- val shownGroups: List,
- val hiddenGroups: List
-)
diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/unitgroups/UnitGroupsViewModel.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/unitgroups/UnitGroupsViewModel.kt
index 3b6fd155..229f6119 100644
--- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/unitgroups/UnitGroupsViewModel.kt
+++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/unitgroups/UnitGroupsViewModel.kt
@@ -20,116 +20,75 @@ 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,
+ private val userPrefsRepository: UserPreferencesRepository,
+ private val unitGroupsRepository: UnitGroupsRepository,
) : ViewModel() {
-
- private var mutex: Mutex = Mutex()
+ val shownUnitGroups = unitGroupsRepository.shownUnitGroups
+ val hiddenUnitGroups = unitGroupsRepository.hiddenUnitGroups
/**
- * Currently shown [UnitGroup]s.
+ * @see UnitGroupsRepository.markUnitGroupAsHidden
+ * @see UserPreferencesRepository.updateShownUnitGroups
*/
- private val _shownUnitGroups = MutableStateFlow(listOf())
+ fun hideUnitGroup(unitGroup: UnitGroup) {
+ viewModelScope.launch {
+ unitGroupsRepository.markUnitGroupAsHidden(unitGroup)
+ userPrefsRepository.updateShownUnitGroups(unitGroupsRepository.shownUnitGroups.value)
+ }
+ }
/**
- * Currently hidden [UnitGroup]s.
+ * @see UnitGroupsRepository.markUnitGroupAsShown
+ * @see UserPreferencesRepository.updateShownUnitGroups
*/
- private val _hiddenUnitGroups = MutableStateFlow(listOf())
+ 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 {
- val shown = userPreferencesRepository.mainPreferencesFlow.first().shownUnitGroups
- mutex.withLock {
- _shownUnitGroups.update { shown }
- _hiddenUnitGroups.update { ALL_UNIT_GROUPS - shown.toSet() }
- }
+ unitGroupsRepository.updateShownGroups(
+ userPrefsRepository.mainPreferencesFlow.first().shownUnitGroups
+ )
}
}
-
- 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
- )
- }
}