diff --git a/app/src/main/java/xyz/pixelatedw/recipe/data/Recipe.kt b/app/src/main/java/xyz/pixelatedw/recipe/data/Recipe.kt index 32d35c2..d31bc06 100644 --- a/app/src/main/java/xyz/pixelatedw/recipe/data/Recipe.kt +++ b/app/src/main/java/xyz/pixelatedw/recipe/data/Recipe.kt @@ -25,8 +25,8 @@ data class Recipe( val content: String, val hash: Int ) { - fun previewImage(ctx: Context): Bitmap? { - return showImage(ctx, 0) + fun previewImage(ctx: Context, idx: Int): Bitmap? { + return showImage(ctx, idx) } fun showImage(ctx: Context, idx: Int): Bitmap? { 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 1757267..3789a55 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 @@ -33,6 +33,7 @@ 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) { @@ -91,8 +92,8 @@ 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) ) { @@ -140,9 +141,8 @@ 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, previewUri, isSelected, onClick = { + RecipePreview(entry, isSelected, onClick = { view.setActive(entry) navController.navigate("info") }, onSelected = { flag -> @@ -167,6 +167,13 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) { // 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) } 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 c99ae4d..ac0b69d 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 @@ -1,9 +1,12 @@ package xyz.pixelatedw.recipe.ui.components -import android.graphics.Bitmap +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 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 @@ -14,52 +17,98 @@ 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.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf 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, 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), - ) +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 } - else { + } + } + + 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 { 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(), @@ -69,7 +118,12 @@ fun RecipePreview(entry: RecipeWithTags, previewUri: Bitmap?, isSelected: Boolea ) ) } - 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) }