Compare commits

..

No commits in common. "06949f0f8ddfa8ffd769959d9a1182aa81f8ac76" and "a7d961393f53ad25296c46713c435aa19583b969" have entirely different histories.

5 changed files with 55 additions and 111 deletions

View File

@ -25,8 +25,8 @@ data class Recipe(
val content: String,
val hash: Int
) {
fun previewImage(ctx: Context, idx: Int): Bitmap? {
return showImage(ctx, idx)
fun previewImage(ctx: Context): Bitmap? {
return showImage(ctx, 0)
}
fun showImage(ctx: Context, idx: Int): Bitmap? {

View File

@ -33,7 +33,7 @@ fun DeleteRecipeDialog(onAccept: ( ) -> Unit, onDismiss: () -> Unit) {
modifier = Modifier.height(100.dp).wrapContentSize(Alignment.Center)
) {
Text(
text = "Do you really wish to permanently delete these recipes ?",
text = "Do you really wish to permanently delete this recipe ?",
textAlign = TextAlign.Center,
)
}

View File

@ -33,7 +33,6 @@ import xyz.pixelatedw.recipe.MainActivity
import xyz.pixelatedw.recipe.R
import xyz.pixelatedw.recipe.data.RecipeWithTags
import xyz.pixelatedw.recipe.data.RecipesView
import java.io.File
@Composable
fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
@ -44,7 +43,6 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
val navController = rememberNavController()
val openDeletionDialog = remember { mutableStateOf(false) }
val openTagFilterDialog = remember { mutableStateOf(false) }
val selectedEntries = remember { mutableStateOf(listOf<RecipeWithTags>()) }
@ -117,7 +115,12 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
IconButton(
modifier = Modifier.weight(0.15f),
onClick = {
openDeletionDialog.value = true
// 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(
@ -126,7 +129,8 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
contentDescription = "Load recipes from filesystem"
)
}
} else {
}
else {
IconButton(
modifier = Modifier.weight(0.15f),
onClick = { ctx.sourceChooser.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)) },
@ -141,8 +145,9 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
LazyColumn {
items(recipes.value) { entry ->
if (isInSearch(entry)) {
val previewUri = entry.recipe.previewImage(LocalContext.current)
val isSelected = selectedEntries.value.contains(entry)
RecipePreview(entry, isSelected, onClick = {
RecipePreview(entry, previewUri, isSelected, onClick = {
view.setActive(entry)
navController.navigate("info")
}, onSelected = { flag ->
@ -161,29 +166,6 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
}
when {
openDeletionDialog.value -> {
DeleteRecipeDialog(
onAccept = {
// 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)
// TODO This needs some refcounting or database stuff so it doesn't delete pics if they're used by multiple recipes, however this is not a problem atm
// Make sure to delete the pics from phone's storage so they don't waste space
for (picPath in entry.recipe.pics) {
File(ctx.filesDir, picPath).delete()
}
ctx.db.recipeDao().delete(entry.recipe)
ctx.db.recipeWithTagsDao().delete(entry.recipe.title)
}
selectedEntries.value = listOf()
openDeletionDialog.value = false
},
onDismiss = { openDeletionDialog.value = false }
)
}
openTagFilterDialog.value -> {
TagFilterDialog(
onAccept = {

View File

@ -49,6 +49,7 @@ fun RecipeInfo(
active: RecipeWithTags
) {
val keepScreen = view.keepScreenOn.collectAsState()
val openDeletionDialog = remember { mutableStateOf(false) }
val picsCounts = remember { active.recipe.pics.size };
val timestamp = view.activeRecipe.collectAsState().value?.recipe?.lastModified ?: 0
@ -148,4 +149,19 @@ fun RecipeInfo(
)
}
}
when {
openDeletionDialog.value -> {
DeleteRecipeDialog(
onAccept = {
view.removeRecipe(active)
ctx.db.recipeDao().delete(active.recipe)
ctx.db.recipeWithTagsDao().delete(active.recipe.title)
openDeletionDialog.value = false
nav.popBackStack()
},
onDismiss = { openDeletionDialog.value = false }
)
}
}
}

View File

@ -1,12 +1,9 @@
package xyz.pixelatedw.recipe.ui.components
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
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
@ -17,98 +14,52 @@ 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.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
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
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.imageResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.em
import kotlinx.coroutines.delay
import xyz.pixelatedw.recipe.R
import xyz.pixelatedw.recipe.data.Recipe
import xyz.pixelatedw.recipe.data.RecipeWithTags
import kotlin.time.Duration.Companion.seconds
@Composable
fun RecipePreview(
entry: RecipeWithTags,
isSelected: Boolean,
onClick: () -> Unit,
onSelected: (Boolean) -> Unit
) {
val availablePics = entry.recipe.pics.size
var displayImageId by remember { mutableIntStateOf(0) }
if (availablePics > 0) {
LaunchedEffect(Unit) {
while (true) {
delay(5.seconds)
displayImageId = (displayImageId + 1) % availablePics
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)
.combinedClickable(
onLongClick = { onSelected(!isSelected) },
onClick = onClick
)) {
Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth().height(256.dp)) {
if (previewUri != null) {
Image(
bitmap = previewUri.asImageBitmap(),
contentDescription = "Recipe image",
contentScale = ContentScale.Crop,
modifier = Modifier.size(256.dp).padding(top = 16.dp, bottom = 8.dp),
)
}
}
}
val displayImage = entry.recipe.previewImage(LocalContext.current, displayImageId)
Column(
modifier = Modifier
.background(color = if (isSelected) Color(0x11FF0000) else Color(0x00FFFFFF))
.padding(8.dp)
.combinedClickable(
onLongClick = { onSelected(!isSelected) },
onClick = onClick
)
) {
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxWidth()
.height(256.dp)
) {
if (displayImage != null) {
AnimatedContent(
displayImage,
label = "Recipe Preview",
transitionSpec = {
fadeIn(animationSpec = tween(500))
.togetherWith(fadeOut(animationSpec = tween(500)))
}
) { targetImage ->
Image(
bitmap = targetImage.asImageBitmap(),
contentDescription = "Recipe image",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(256.dp)
.padding(top = 16.dp, bottom = 8.dp),
)
}
} else {
else {
Image(
bitmap = ImageBitmap.imageResource(R.drawable.missing_image),
contentDescription = "Missing recipe image",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(256.dp)
.padding(top = 16.dp, bottom = 8.dp),
modifier = Modifier.size(256.dp).padding(top = 16.dp, bottom = 8.dp),
)
}
}
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 8.dp)
) {
Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp)) {
Text(
text = entry.recipe.title,
modifier = Modifier.fillMaxWidth(),
@ -118,12 +69,7 @@ fun RecipePreview(
)
)
}
Row(
horizontalArrangement = Arrangement.End,
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp)
) {
Row(horizontalArrangement = Arrangement.End, modifier = Modifier.fillMaxWidth().padding(bottom = 16.dp)) {
for (tag in entry.tags) {
Tag(tag)
}