Tags list updates based on previously checked tags

master
Wynd 2026-02-28 20:29:01 +02:00
parent 9f740e5bcc
commit 6735593517
2 changed files with 60 additions and 14 deletions

View File

@ -6,13 +6,13 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
class RecipesView : ViewModel() { class RecipesView : ViewModel() {
private val _activeRecipe = MutableStateFlow<RecipeWithTags?>( null ) private val _activeRecipe = MutableStateFlow<RecipeWithTags?>(null)
val activeRecipe = _activeRecipe.asStateFlow() val activeRecipe = _activeRecipe.asStateFlow()
private val _recipes = MutableStateFlow<List<RecipeWithTags>>( arrayListOf() ) private val _recipes = MutableStateFlow<List<RecipeWithTags>>(arrayListOf())
val recipes = _recipes.asStateFlow() val recipes = _recipes.asStateFlow()
private val _tagFilters = MutableStateFlow<List<TagFilter>>( arrayListOf() ) private val _tagFilters = MutableStateFlow<List<TagFilter>>(arrayListOf())
val tagFilters = _tagFilters.asStateFlow() val tagFilters = _tagFilters.asStateFlow()
private val _search = MutableStateFlow<String?>(null) private val _search = MutableStateFlow<String?>(null)
@ -22,11 +22,42 @@ class RecipesView : ViewModel() {
val keepScreenOn = _keepScreenOn.asStateFlow() val keepScreenOn = _keepScreenOn.asStateFlow()
fun reloadTagFilterState() { fun reloadTagFilterState() {
_tagFilters.value = _tagFilters.value // TODO Honestly quite a messy bit of logic, would be nice to have a more streamlined function here.
// If this is empty that means no filters are active, which means we don't do any special tag counting
val activeFilterNames = _tagFilters.value.filter { f -> f.checked }.map { f -> f.tag }
val filtersMap = mutableMapOf<String, Int>()
_recipes.value.stream()
.filter { it.tags.isNotEmpty() }
.filter {
if (activeFilterNames.isNotEmpty()) {
it.tags.count { t -> activeFilterNames.contains(t.name) } >= activeFilterNames.size
} else {
true
}
}
.forEach {
it.tags.forEach { tag ->
val count = filtersMap[tag.name] ?: 0
filtersMap[tag.name] = count + 1;
}
}
if (activeFilterNames.isNotEmpty()) {
_tagFilters.value = _tagFilters.value.map {
it.count = filtersMap[it.tag] ?: 0
it
}.toList()
} else {
val filters = filtersMap.map { TagFilter(it.key, count = it.value) }.toList()
_tagFilters.update { filters.distinct().sortedBy { it.tag } }
}
} }
fun setTagFilterState(tag: String, state: Boolean) { fun setTagFilterState(tag: String, state: Boolean) {
_tagFilters.value = _tagFilters.value.toMutableList().apply { replaceAll { it -> if (tag == it.tag) it.checked = state; it } }.toList() _tagFilters.value = _tagFilters.value.toMutableList()
.apply { replaceAll { it -> if (tag == it.tag) it.checked = state; it } }.toList()
} }
fun setKeepScreenOn(flag: Boolean) { fun setKeepScreenOn(flag: Boolean) {
@ -48,7 +79,6 @@ class RecipesView : ViewModel() {
} }
val filters = filtersMap.map { it -> TagFilter(it.key, count = it.value) }.toList() val filters = filtersMap.map { it -> TagFilter(it.key, count = it.value) }.toList()
_tagFilters.update { filters.distinct().sortedBy { it.tag } } _tagFilters.update { filters.distinct().sortedBy { it.tag } }
} }

View File

@ -11,9 +11,12 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Settings import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.Badge
import androidx.compose.material3.BadgedBox
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@ -43,6 +46,8 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
val search = view.search.collectAsState() val search = view.search.collectAsState()
val filters = view.tagFilters.collectAsState() val filters = view.tagFilters.collectAsState()
var activeTags = 0
val navController = rememberNavController() val navController = rememberNavController()
var openDeletionDialog by remember { mutableStateOf(false) } var openDeletionDialog by remember { mutableStateOf(false) }
@ -123,6 +128,15 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
IconButton( IconButton(
modifier = Modifier.weight(0.1f), modifier = Modifier.weight(0.1f),
onClick = { openTagFilterDialog = true }, onClick = { openTagFilterDialog = true },
) {
BadgedBox(
badge = {
if (activeTags > 0) {
Badge {
Text("$activeTags")
}
}
}
) { ) {
Icon( Icon(
imageVector = ImageVector.vectorResource(R.drawable.filter_24), imageVector = ImageVector.vectorResource(R.drawable.filter_24),
@ -130,6 +144,7 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
) )
} }
} }
}
// Options // Options
IconButton( IconButton(
modifier = Modifier.weight(0.1f), modifier = Modifier.weight(0.1f),
@ -195,6 +210,7 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
onAccept = { onAccept = {
openTagFilterDialog = false openTagFilterDialog = false
view.reloadTagFilterState() view.reloadTagFilterState()
activeTags = filters.value.count { f -> f.checked }
}, },
view, view,
) )