feat(tasks): P1 завершён — 3-state видимость коллекций в настройках + персист
TasksPrefsStore (SharedPreferences) хранит режим Скрыта/Видима/Авто по коллекции. TasksViewModel через Factory(context), setSmartMode персистит; шит настроек 3-state от VM (убраны фиктивные локальные remember). Панель реагирует через visibleKeys. Гейт compile+detekt+test зелёный. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1016,17 +1016,12 @@ fun TasksSettingsSheet(
|
||||
lists: List<TaskListItem>,
|
||||
defaultListHref: String?,
|
||||
onDefaultListChange: (String?) -> Unit,
|
||||
visibility: SmartListVisibility,
|
||||
onSmartModeChange: (SmartListKey, SmartListMode) -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
onSwipeBack: () -> Unit = onDismiss,
|
||||
) {
|
||||
if (!visible) return
|
||||
val visibilityOptions = listOf("Показывать", "Скрывать")
|
||||
var importantVisible by remember { mutableStateOf(visibilityOptions.first()) }
|
||||
var todayVisible by remember { mutableStateOf(visibilityOptions.first()) }
|
||||
var weekVisible by remember { mutableStateOf(visibilityOptions.first()) }
|
||||
var allVisible by remember { mutableStateOf(visibilityOptions.first()) }
|
||||
var currentVisible by remember { mutableStateOf(visibilityOptions.first()) }
|
||||
var completedVisible by remember { mutableStateOf(visibilityOptions.first()) }
|
||||
var defaultMenuOpen by remember { mutableStateOf(false) }
|
||||
|
||||
Dialog(
|
||||
@@ -1099,23 +1094,15 @@ fun TasksSettingsSheet(
|
||||
|
||||
HorizontalDivider(color = F7Colors.Border)
|
||||
|
||||
SmartListSettingRow(serverUrl, "important-gray.svg", "Важное", importantVisible) {
|
||||
importantVisible = it
|
||||
}
|
||||
SmartListSettingRow(serverUrl, "calendar-today-gray.svg", "Сегодня", todayVisible) {
|
||||
todayVisible = it
|
||||
}
|
||||
SmartListSettingRow(serverUrl, "calendar-nextweek-gray.svg", "На неделе", weekVisible) {
|
||||
weekVisible = it
|
||||
}
|
||||
SmartListSettingRow(serverUrl, "calendar-icon-gray.svg", "Все", allVisible) {
|
||||
allVisible = it
|
||||
}
|
||||
SmartListSettingRow(serverUrl, "current-gray.svg", "Текущие", currentVisible) {
|
||||
currentVisible = it
|
||||
}
|
||||
SmartListSettingRow(serverUrl, "check-done-gray.svg", "Завершенные", completedVisible) {
|
||||
completedVisible = it
|
||||
Text("Видимость умных списков", fontSize = 14.sp, fontWeight = FontWeight.Medium)
|
||||
SmartListKey.entries.forEach { key ->
|
||||
SmartListSettingRow(
|
||||
serverUrl = serverUrl,
|
||||
iconPath = key.icon,
|
||||
title = key.title,
|
||||
mode = visibility.mode(key),
|
||||
onModeChange = { onSmartModeChange(key, it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1127,11 +1114,16 @@ private fun SmartListSettingRow(
|
||||
serverUrl: String,
|
||||
iconPath: String,
|
||||
title: String,
|
||||
selected: String,
|
||||
onSelect: (String) -> Unit,
|
||||
mode: SmartListMode,
|
||||
onModeChange: (SmartListMode) -> Unit,
|
||||
) {
|
||||
var menuOpen by remember { mutableStateOf(false) }
|
||||
val options = listOf("Показывать", "Скрывать")
|
||||
val options = listOf(
|
||||
SmartListMode.VISIBLE to "Показывать",
|
||||
SmartListMode.HIDDEN to "Скрывать",
|
||||
SmartListMode.AUTO to "Автоматически",
|
||||
)
|
||||
val currentLabel = options.firstOrNull { it.first == mode }?.second ?: "Автоматически"
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
AsyncImage(model = tasksAsset(serverUrl, iconPath), contentDescription = null, modifier = Modifier.size(18.dp))
|
||||
@@ -1149,7 +1141,7 @@ private fun SmartListSettingRow(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(selected)
|
||||
Text(currentLabel)
|
||||
AsyncImage(
|
||||
model = tasksAsset(serverUrl, "chevron-down-16.svg"),
|
||||
contentDescription = null,
|
||||
@@ -1157,11 +1149,11 @@ private fun SmartListSettingRow(
|
||||
)
|
||||
}
|
||||
DropdownMenu(expanded = menuOpen, onDismissRequest = { menuOpen = false }) {
|
||||
options.forEach { option ->
|
||||
options.forEach { (optionMode, label) ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(option) },
|
||||
text = { Text(label) },
|
||||
onClick = {
|
||||
onSelect(option)
|
||||
onModeChange(optionMode)
|
||||
menuOpen = false
|
||||
},
|
||||
)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package ru.forbion.f7cloud.feature.tasks
|
||||
|
||||
import android.content.Context
|
||||
|
||||
/**
|
||||
* Персист настроек Задач в SharedPreferences (по образцу `CalendarPrefsStore`).
|
||||
* Сейчас — режим видимости умных коллекций (3-state), переживает перезапуск.
|
||||
*/
|
||||
class TasksPrefsStore(context: Context) {
|
||||
private val prefs = context.applicationContext.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
|
||||
fun getVisibility(): SmartListVisibility {
|
||||
val modes = SmartListKey.entries.mapNotNull { key ->
|
||||
val raw = prefs.getString(keyMode(key), null) ?: return@mapNotNull null
|
||||
runCatching { SmartListMode.valueOf(raw) }.getOrNull()?.let { key to it }
|
||||
}.toMap()
|
||||
return SmartListVisibility.of(modes)
|
||||
}
|
||||
|
||||
fun setMode(key: SmartListKey, mode: SmartListMode) {
|
||||
prefs.edit().putString(keyMode(key), mode.name).apply()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val PREFS = "f7_tasks_prefs"
|
||||
|
||||
private fun keyMode(key: SmartListKey) = "smart_mode::${key.name}"
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,8 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -22,6 +22,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import ru.forbion.f7cloud.core.auth.AuthSession
|
||||
@@ -38,7 +39,8 @@ fun TasksScreen(
|
||||
onOpenListConsumed: () -> Unit = {},
|
||||
onUnauthorized: () -> Unit = {},
|
||||
) {
|
||||
val vm: TasksViewModel = viewModel()
|
||||
val context = LocalContext.current
|
||||
val vm: TasksViewModel = viewModel(factory = TasksViewModel.Factory(context))
|
||||
val state by vm.state.collectAsState()
|
||||
// Родитель для создаваемой подзадачи (открывает диалог ввода названия).
|
||||
var subtaskParent by remember { mutableStateOf<TaskItem?>(null) }
|
||||
@@ -156,6 +158,8 @@ fun TasksScreen(
|
||||
lists = state.lists,
|
||||
defaultListHref = state.defaultListHref,
|
||||
onDefaultListChange = vm::setDefaultList,
|
||||
visibility = state.smartVisibility,
|
||||
onSmartModeChange = vm::setSmartMode,
|
||||
onDismiss = vm::closeSettings,
|
||||
onSwipeBack = vm::closeSettings,
|
||||
)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package ru.forbion.f7cloud.feature.tasks
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -88,9 +90,11 @@ data class TasksUiState(
|
||||
}
|
||||
|
||||
class TasksViewModel(
|
||||
context: Context,
|
||||
private val repository: TasksRepository = TasksRepository(),
|
||||
) : ViewModel() {
|
||||
private val _state = MutableStateFlow(TasksUiState())
|
||||
private val prefsStore = TasksPrefsStore(context.applicationContext)
|
||||
private val _state = MutableStateFlow(TasksUiState(smartVisibility = prefsStore.getVisibility()))
|
||||
val state: StateFlow<TasksUiState> = _state.asStateFlow()
|
||||
|
||||
fun load(session: AuthSession) {
|
||||
@@ -174,8 +178,9 @@ class TasksViewModel(
|
||||
loadAllTasks(session)
|
||||
}
|
||||
|
||||
/** Сменить режим видимости умной коллекции (шит настроек). */
|
||||
/** Сменить режим видимости умной коллекции (шит настроек) + персист. */
|
||||
fun setSmartMode(key: SmartListKey, mode: SmartListMode) {
|
||||
prefsStore.setMode(key, mode)
|
||||
_state.update { it.copy(smartVisibility = it.smartVisibility.withMode(key, mode)) }
|
||||
}
|
||||
|
||||
@@ -503,4 +508,10 @@ class TasksViewModel(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Factory(private val context: Context) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T =
|
||||
TasksViewModel(context.applicationContext) as T
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user