From a7d961393f53ad25296c46713c435aa19583b969 Mon Sep 17 00:00:00 2001 From: Wynd Date: Sun, 21 Dec 2025 00:58:56 +0200 Subject: [PATCH] Added long press toggles for easier mass deletion --- .../recipe/ui/components/MainScreen.kt | 65 ++++++++++++++----- .../recipe/ui/components/RecipeInfo.kt | 24 ------- .../recipe/ui/components/RecipePreview.kt | 13 +++- 3 files changed, 60 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/xyz/pixelatedw/recipe/ui/components/MainScreen.kt b/app/src/main/java/xyz/pixelatedw/recipe/ui/components/MainScreen.kt index c30fbc6..0b12538 100644 --- a/app/src/main/java/xyz/pixelatedw/recipe/ui/components/MainScreen.kt +++ b/app/src/main/java/xyz/pixelatedw/recipe/ui/components/MainScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.Delete import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.OutlinedTextField @@ -20,6 +21,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.vectorResource @@ -41,6 +43,9 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) { val navController = rememberNavController() + val openTagFilterDialog = remember { mutableStateOf(false) } + val selectedEntries = remember { mutableStateOf(listOf()) } + val isInSearch = isInSearch@{ entry: RecipeWithTags -> val isSearchEmpty = search.value == null || search.value!!.isEmpty() val hasTitle = entry.recipe.title.contains(search.value.orEmpty(), ignoreCase = true) @@ -52,7 +57,7 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) { return@isInSearch false } - val totalFilters = filters.value.stream().filter{ f -> f.checked }.count() + val totalFilters = filters.value.stream().filter { f -> f.checked }.count() var checkedFilters = 0 for (filter in filters.value) { @@ -61,10 +66,9 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) { .filter { tag -> tag.name.contains(filter.tag, ignoreCase = true) } .count() > 0 - if(hasTagFilters) { + if (hasTagFilters) { checkedFilters += 1 - } - else { + } else { checkedFilters -= 1 } } @@ -78,8 +82,6 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) { true } - val openTagFilterDialog = remember { mutableStateOf(false) } - NavHost( navController = navController, startDestination = "list" @@ -108,24 +110,55 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) { contentDescription = "Toggle tags filtering menu" ) } - // Load - IconButton( - modifier = Modifier.weight(0.15f), - onClick = { ctx.sourceChooser.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)) }, - ) { - Icon( - imageVector = Icons.Default.Add, - contentDescription = "Load recipes from filesystem" - ) + // Load / Delete + if (selectedEntries.value.isNotEmpty()) { + IconButton( + modifier = Modifier.weight(0.15f), + onClick = { + // TODO I feel like this could be done in batch or something...but I truly don't care atm + for (entry in selectedEntries.value) { + view.removeRecipe(entry) + ctx.db.recipeDao().delete(entry.recipe) + ctx.db.recipeWithTagsDao().delete(entry.recipe.title) + } + }, + ) { + Icon( + imageVector = Icons.Default.Delete, + tint = Color(0xFFFF0000), + contentDescription = "Load recipes from filesystem" + ) + } + } + else { + IconButton( + modifier = Modifier.weight(0.15f), + onClick = { ctx.sourceChooser.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)) }, + ) { + Icon( + imageVector = Icons.Default.Add, + contentDescription = "Load recipes from filesystem" + ) + } } } LazyColumn { items(recipes.value) { entry -> if (isInSearch(entry)) { val previewUri = entry.recipe.previewImage(LocalContext.current) - RecipePreview(entry, previewUri, onClick = { + val isSelected = selectedEntries.value.contains(entry) + RecipePreview(entry, previewUri, isSelected, onClick = { view.setActive(entry) navController.navigate("info") + }, onSelected = { flag -> + selectedEntries.value = + selectedEntries.value.toMutableList().apply { + if (flag) { + add(entry) + } else { + remove(entry) + } + }.toList() }) } } diff --git a/app/src/main/java/xyz/pixelatedw/recipe/ui/components/RecipeInfo.kt b/app/src/main/java/xyz/pixelatedw/recipe/ui/components/RecipeInfo.kt index 8b1a1f3..e2de34c 100644 --- a/app/src/main/java/xyz/pixelatedw/recipe/ui/components/RecipeInfo.kt +++ b/app/src/main/java/xyz/pixelatedw/recipe/ui/components/RecipeInfo.kt @@ -136,30 +136,6 @@ fun RecipeInfo( style = MaterialTheme.typography.bodyMedium, ) } - Row( - modifier = Modifier - .fillMaxWidth() - .padding(end = 16.dp), - horizontalArrangement = Arrangement.End - ) { - Box( - modifier = Modifier - .fillMaxHeight() - .padding(start = 16.dp) - ) { - Button( - onClick = { - openDeletionDialog.value = true - }, - colors = ButtonDefaults.buttonColors(containerColor = Color.Red) - ) { - Text( - text = "Delete", - style = MaterialTheme.typography.bodyMedium - ) - } - } - } } Box( diff --git a/app/src/main/java/xyz/pixelatedw/recipe/ui/components/RecipePreview.kt b/app/src/main/java/xyz/pixelatedw/recipe/ui/components/RecipePreview.kt index cf58ef6..c99ae4d 100644 --- a/app/src/main/java/xyz/pixelatedw/recipe/ui/components/RecipePreview.kt +++ b/app/src/main/java/xyz/pixelatedw/recipe/ui/components/RecipePreview.kt @@ -2,7 +2,9 @@ package xyz.pixelatedw.recipe.ui.components import android.graphics.Bitmap import androidx.compose.foundation.Image +import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -12,7 +14,10 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.vector.ImageVector @@ -28,10 +33,14 @@ import xyz.pixelatedw.recipe.data.Recipe import xyz.pixelatedw.recipe.data.RecipeWithTags @Composable -fun RecipePreview(entry: RecipeWithTags, previewUri: Bitmap?, onClick: () -> Unit) { +fun RecipePreview(entry: RecipeWithTags, previewUri: Bitmap?, isSelected: Boolean, onClick: () -> Unit, onSelected: (Boolean) -> Unit) { Column(modifier = Modifier + .background(color = if(isSelected) Color(0x11FF0000) else Color(0x00FFFFFF) ) .padding(8.dp) - .clickable(onClick = onClick)) { + .combinedClickable( + onLongClick = { onSelected(!isSelected) }, + onClick = onClick + )) { Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth().height(256.dp)) { if (previewUri != null) { Image(