Temporarily return old unit groups setting logic

i tried to make it better and it broke
This commit is contained in:
Sad Ellie 2023-05-21 23:05:18 +03:00
parent 7ec8cf934a
commit 11f2d82b50
4 changed files with 176 additions and 127 deletions

View File

@ -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 <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,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) }
)
)
}

View File

@ -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 <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>
)

View File

@ -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<UnitGroup>())
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<UnitGroup>())
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() }
}
}
}
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)
unitGroupsRepository.updateShownGroups(
userPrefsRepository.mainPreferencesFlow.first().shownUnitGroups
)
}
}
}
}
fun canDragOver(pos: ItemPosition) = uiState.value.shownGroups.any { it == pos.key }
fun saveShownUnitGroups() = viewModelScope.launch {
userPreferencesRepository.updateShownUnitGroups(
uiState.value.shownGroups
)
}
}