Image caching and using normal grid instead of staggered

master
Wynd 2026-03-01 17:29:36 +02:00
parent 7f67e3e4b7
commit d60cbe4678
3 changed files with 44 additions and 33 deletions

View File

@ -3,8 +3,8 @@ package xyz.pixelatedw.recipe.data
import android.content.Context import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.widget.ImageView
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.documentfile.provider.DocumentFile
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete import androidx.room.Delete
import androidx.room.Entity import androidx.room.Entity
@ -17,6 +17,9 @@ import com.google.gson.Gson
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import java.io.File import java.io.File
private val imagesCache: HashMap<String, Bitmap> = hashMapOf()
@Entity @Entity
data class Recipe( data class Recipe(
@PrimaryKey @PrimaryKey
@ -33,10 +36,17 @@ data class Recipe(
fun showImage(ctx: Context, idx: Int): Bitmap? { fun showImage(ctx: Context, idx: Int): Bitmap? {
val img = this.pics.getOrNull(idx) val img = this.pics.getOrNull(idx)
if (img != null) { if (img != null) {
val cachedImage = imagesCache[img]
if (cachedImage != null) {
return cachedImage
}
val file = File(ctx.filesDir, img) val file = File(ctx.filesDir, img)
if (file.exists()) { if (file.exists()) {
ctx.contentResolver.openInputStream(file.toUri()).use { ctx.contentResolver.openInputStream(file.toUri()).use {
return BitmapFactory.decodeStream(it) val bitmapData = BitmapFactory.decodeStream(it)
imagesCache[img] = bitmapData
return bitmapData
} }
} }
} }

View File

@ -7,12 +7,9 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
import androidx.compose.foundation.lazy.staggeredgrid.items
import androidx.compose.foundation.lazy.staggeredgrid.rememberLazyStaggeredGridState
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Settings import androidx.compose.material.icons.filled.Settings
@ -61,7 +58,7 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
var openTagFilterDialog by remember { mutableStateOf(false) } var openTagFilterDialog by remember { mutableStateOf(false) }
var selectedEntries by remember { mutableStateOf(listOf<RecipeWithTags>()) } var selectedEntries by remember { mutableStateOf(listOf<RecipeWithTags>()) }
val gridState = rememberLazyStaggeredGridState() val gridState = rememberLazyGridState()
NavHost( NavHost(
navController = navController, navController = navController,
@ -136,14 +133,18 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
) )
} }
} }
LazyVerticalStaggeredGrid( LazyVerticalGrid(
columns = StaggeredGridCells.Fixed(3), columns = GridCells.Fixed(3),
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
horizontalArrangement = Arrangement.spacedBy(8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalItemSpacing = 8.dp, verticalArrangement = Arrangement.spacedBy(8.dp),
state = gridState, state = gridState,
) { ) {
items(activeRecipes) { entry -> items(
count = activeRecipes.size,
key = { activeRecipes[it].recipe.title },
itemContent = { entryId ->
val entry = activeRecipes[entryId]
val isSelected = selectedEntries.contains(entry) val isSelected = selectedEntries.contains(entry)
RecipePreview(entry, isSelected, onClick = { RecipePreview(entry, isSelected, onClick = {
view.setActive(entry) view.setActive(entry)
@ -159,6 +160,7 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
}.toList() }.toList()
}) })
} }
)
} }
} }

View File

@ -15,6 +15,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@ -66,11 +67,12 @@ fun RecipePreview(
) { ) {
Row( Row(
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
modifier = Modifier.weight(0.7f) modifier = Modifier.fillMaxWidth().weight(0.7f)
) { ) {
AnimatedContent( AnimatedContent(
displayImageId, displayImageId,
label = "Recipe Preview", label = "Recipe Preview",
modifier = Modifier.fillMaxSize(),
transitionSpec = { transitionSpec = {
fadeIn(animationSpec = tween(500)) fadeIn(animationSpec = tween(500))
.togetherWith(fadeOut(animationSpec = tween(500))) .togetherWith(fadeOut(animationSpec = tween(500)))
@ -82,14 +84,12 @@ fun RecipePreview(
bitmap = displayImage.asImageBitmap(), bitmap = displayImage.asImageBitmap(),
contentDescription = "Recipe image", contentDescription = "Recipe image",
contentScale = ContentScale.FillHeight, contentScale = ContentScale.FillHeight,
modifier = Modifier.fillMaxSize(),
) )
} else { } else {
Image( Image(
bitmap = ImageBitmap.imageResource(R.drawable.missing_image), bitmap = ImageBitmap.imageResource(R.drawable.missing_image),
contentDescription = "Missing recipe image", contentDescription = "Missing recipe image",
contentScale = ContentScale.FillWidth, contentScale = ContentScale.FillHeight,
modifier = Modifier.fillMaxSize(),
) )
} }
} }
@ -104,7 +104,6 @@ fun RecipePreview(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
style = TextStyle( style = TextStyle(
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
// fontSize = 7.em,
) )
) )
} }