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
class RecipesView : ViewModel() {
private val _activeRecipe = MutableStateFlow<RecipeWithTags?>( null )
private val _activeRecipe = MutableStateFlow<RecipeWithTags?>(null)
val activeRecipe = _activeRecipe.asStateFlow()
private val _recipes = MutableStateFlow<List<RecipeWithTags>>( arrayListOf() )
private val _recipes = MutableStateFlow<List<RecipeWithTags>>(arrayListOf())
val recipes = _recipes.asStateFlow()
private val _tagFilters = MutableStateFlow<List<TagFilter>>( arrayListOf() )
private val _tagFilters = MutableStateFlow<List<TagFilter>>(arrayListOf())
val tagFilters = _tagFilters.asStateFlow()
private val _search = MutableStateFlow<String?>(null)
@ -22,11 +22,42 @@ class RecipesView : ViewModel() {
val keepScreenOn = _keepScreenOn.asStateFlow()
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) {
_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) {
@ -48,7 +79,6 @@ class RecipesView : ViewModel() {
}
val filters = filtersMap.map { it -> TagFilter(it.key, count = it.value) }.toList()
_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.filled.Delete
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.IconButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@ -43,6 +46,8 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
val search = view.search.collectAsState()
val filters = view.tagFilters.collectAsState()
var activeTags = 0
val navController = rememberNavController()
var openDeletionDialog by remember { mutableStateOf(false) }
@ -93,15 +98,15 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
Column(modifier = Modifier.padding(padding)) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
.fillMaxWidth()
.padding(8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
OutlinedTextField(
modifier = Modifier
.weight(0.7f)
.padding(end = 4.dp),
.weight(0.7f)
.padding(end = 4.dp),
value = search.value.orEmpty(),
onValueChange = { search -> view.setSearch(search) },
)
@ -124,10 +129,20 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
modifier = Modifier.weight(0.1f),
onClick = { openTagFilterDialog = true },
) {
Icon(
imageVector = ImageVector.vectorResource(R.drawable.filter_24),
contentDescription = "Toggle tags filtering menu"
)
BadgedBox(
badge = {
if (activeTags > 0) {
Badge {
Text("$activeTags")
}
}
}
) {
Icon(
imageVector = ImageVector.vectorResource(R.drawable.filter_24),
contentDescription = "Toggle tags filtering menu"
)
}
}
}
// Options
@ -195,6 +210,7 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
onAccept = {
openTagFilterDialog = false
view.reloadTagFilterState()
activeTags = filters.value.count { f -> f.checked }
},
view,
)