Better filtering for both searching and tags

master
Wynd 2025-09-08 14:04:33 +03:00
parent 67659a0af6
commit 357cab1afa
3 changed files with 28 additions and 16 deletions

View File

@ -21,6 +21,10 @@ class RecipesView : ViewModel() {
private val _keepScreenOn = MutableStateFlow<Boolean>(false) private val _keepScreenOn = MutableStateFlow<Boolean>(false)
val keepScreenOn = _keepScreenOn.asStateFlow() val keepScreenOn = _keepScreenOn.asStateFlow()
fun reloadTagFilterState() {
_tagFilters.value = _tagFilters.value
}
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()
} }

View File

@ -29,7 +29,6 @@ import androidx.navigation.compose.rememberNavController
import xyz.pixelatedw.recipe.MainActivity import xyz.pixelatedw.recipe.MainActivity
import xyz.pixelatedw.recipe.data.RecipeWithTags import xyz.pixelatedw.recipe.data.RecipeWithTags
import xyz.pixelatedw.recipe.data.RecipesView import xyz.pixelatedw.recipe.data.RecipesView
import xyz.pixelatedw.recipe.data.TagFilter
@Composable @Composable
fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) { fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
@ -41,32 +40,40 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
val navController = rememberNavController() val navController = rememberNavController()
val isInSearch = isInSearch@{ entry: RecipeWithTags -> val isInSearch = isInSearch@{ entry: RecipeWithTags ->
val hasTitle = search.value != null && search.value!!.isNotEmpty() && entry.recipe.title.contains(search.value.orEmpty(), ignoreCase = true) val isSearchEmpty = search.value == null || search.value!!.isEmpty()
val hasTags = entry.tags.isNotEmpty() && entry.tags.stream() val hasTitle = entry.recipe.title.contains(search.value.orEmpty(), ignoreCase = true)
val hasTags = entry.tags.stream()
.filter { tag -> tag.name.contains(search.value.orEmpty(), ignoreCase = true) } .filter { tag -> tag.name.contains(search.value.orEmpty(), ignoreCase = true) }
.count() > 0 .count() > 0
var hasAtLeastOneFilter = false
var hasTagFilters = false if (!isSearchEmpty && !hasTitle && !hasTags) {
return@isInSearch false
}
val totalFilters = filters.value.stream().filter{ f -> f.checked }.count()
var checkedFilters = 0
for (filter in filters.value) { for (filter in filters.value) {
if (filter.checked) { if (filter.checked) {
hasAtLeastOneFilter = true val hasTagFilters = entry.tags.isNotEmpty() && entry.tags.stream()
hasTagFilters = entry.tags.isNotEmpty() && entry.tags.stream()
.filter { tag -> tag.name.contains(filter.tag, ignoreCase = true) } .filter { tag -> tag.name.contains(filter.tag, ignoreCase = true) }
.count() > 0 .count() > 0
if(hasTagFilters) { if(hasTagFilters) {
break checkedFilters += 1
}
else {
checkedFilters -= 1
} }
} }
} }
// TODO Needs much better filtering val hasTagFilters = checkedFilters >= totalFilters
if (hasAtLeastOneFilter) { if (totalFilters > 0 && !hasTagFilters) {
return@isInSearch hasTagFilters return@isInSearch false
} }
hasTitle || hasTags true
} }
val openTagFilterDialog = remember { mutableStateOf(false) } val openTagFilterDialog = remember { mutableStateOf(false) }
@ -127,9 +134,8 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
openTagFilterDialog.value -> { openTagFilterDialog.value -> {
TagFilterDialog( TagFilterDialog(
onAccept = { onAccept = {
// TODO This calls twice and therefore updates the search twice too, also hella stupid updating logic
openTagFilterDialog.value = false openTagFilterDialog.value = false
view.setTagFilterState("", true) view.reloadTagFilterState()
}, },
view, view,
) )

View File

@ -41,7 +41,7 @@ import xyz.pixelatedw.recipe.data.TagFilter
fun TagFilterDialog(onAccept: ( ) -> Unit, view: RecipesView) { fun TagFilterDialog(onAccept: ( ) -> Unit, view: RecipesView) {
val filters = view.tagFilters.collectAsState() val filters = view.tagFilters.collectAsState()
Dialog(onDismissRequest = onAccept) { Dialog(onDismissRequest = { }) {
Card( Card(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -69,7 +69,9 @@ fun TagFilterDialog(onAccept: ( ) -> Unit, view: RecipesView) {
} }
} }
Row(modifier = Modifier.fillMaxWidth().padding(end = 16.dp), horizontalArrangement = Arrangement.End) { Row(modifier = Modifier
.fillMaxWidth()
.padding(end = 16.dp), horizontalArrangement = Arrangement.End) {
TextButton(onClick = onAccept) { TextButton(onClick = onAccept) {
Text("Done") Text("Done")
} }