mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-07-26 22:42:17 +00:00
feat: implement image caching for cast avatars in detail screens
This commit is contained in:
parent
bc3400fd0f
commit
e4e619695e
3 changed files with 53 additions and 4 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -21,4 +21,5 @@ logs/
|
|||
Docs
|
||||
keystore/
|
||||
scripts/build-distribution.sh
|
||||
asset
|
||||
asset
|
||||
scripts/scrape_android_compose_animation_docs.py
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.unit.lerp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil3.compose.AsyncImage
|
||||
import coil3.compose.LocalPlatformContext
|
||||
import coil3.request.ImageRequest
|
||||
import com.nuvio.app.features.details.components.DetailPosterRailSection
|
||||
import com.nuvio.app.features.home.MetaPreview
|
||||
import com.nuvio.app.features.tmdb.TmdbMetadataService
|
||||
|
|
@ -297,6 +299,20 @@ private fun HeroSection(
|
|||
val heroScale = 1f - (collapseProgress * 0.12f)
|
||||
val heroAlpha = 1f - (collapseProgress * 0.35f)
|
||||
val avatarUrl = person.profilePhoto?.takeIf { it.isNotBlank() } ?: fallbackProfilePhoto
|
||||
val avatarCacheKey = castAvatarSharedTransitionKey(person.tmdbId)
|
||||
val platformContext = LocalPlatformContext.current
|
||||
val avatarRequest = if (!avatarUrl.isNullOrBlank()) {
|
||||
remember(platformContext, avatarUrl, avatarCacheKey) {
|
||||
ImageRequest.Builder(platformContext)
|
||||
.data(avatarUrl)
|
||||
.memoryCacheKey(avatarCacheKey)
|
||||
.placeholderMemoryCacheKey(avatarCacheKey)
|
||||
.diskCacheKey(avatarUrl)
|
||||
.build()
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val avatarSharedElementModifier = if (sharedTransitionScope != null && animatedVisibilityScope != null) {
|
||||
with(sharedTransitionScope) {
|
||||
Modifier.sharedElement(
|
||||
|
|
@ -333,7 +349,7 @@ private fun HeroSection(
|
|||
) {
|
||||
if (!avatarUrl.isNullOrBlank()) {
|
||||
AsyncImage(
|
||||
model = avatarUrl,
|
||||
model = avatarRequest ?: avatarUrl,
|
||||
contentDescription = person.name,
|
||||
modifier = Modifier.matchParentSize(),
|
||||
contentScale = ContentScale.Crop,
|
||||
|
|
@ -422,6 +438,20 @@ private fun PersonDetailSkeleton(
|
|||
animatedVisibilityScope: AnimatedVisibilityScope? = null,
|
||||
) {
|
||||
val accentColor = MaterialTheme.colorScheme.primary
|
||||
val avatarCacheKey = castAvatarSharedTransitionKey(personId)
|
||||
val platformContext = LocalPlatformContext.current
|
||||
val avatarRequest = if (!profilePhoto.isNullOrBlank()) {
|
||||
remember(platformContext, profilePhoto, avatarCacheKey) {
|
||||
ImageRequest.Builder(platformContext)
|
||||
.data(profilePhoto)
|
||||
.memoryCacheKey(avatarCacheKey)
|
||||
.placeholderMemoryCacheKey(avatarCacheKey)
|
||||
.diskCacheKey(profilePhoto)
|
||||
.build()
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val accentGradient = remember(accentColor) {
|
||||
Brush.verticalGradient(
|
||||
colorStops = arrayOf(
|
||||
|
|
@ -480,7 +510,7 @@ private fun PersonDetailSkeleton(
|
|||
) {
|
||||
if (!profilePhoto.isNullOrBlank()) {
|
||||
AsyncImage(
|
||||
model = profilePhoto,
|
||||
model = avatarRequest ?: profilePhoto,
|
||||
contentDescription = personName,
|
||||
modifier = Modifier.matchParentSize(),
|
||||
contentScale = ContentScale.Crop,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import androidx.compose.ui.draw.clip
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
|
|
@ -29,6 +30,8 @@ import androidx.compose.ui.unit.TextUnit
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil3.compose.AsyncImage
|
||||
import coil3.compose.LocalPlatformContext
|
||||
import coil3.request.ImageRequest
|
||||
import com.nuvio.app.features.details.MetaPerson
|
||||
import com.nuvio.app.features.details.castAvatarSharedTransitionKey
|
||||
|
||||
|
|
@ -86,6 +89,21 @@ private fun CastItem(
|
|||
animatedVisibilityScope: AnimatedVisibilityScope? = null,
|
||||
onClick: (() -> Unit)? = null,
|
||||
) {
|
||||
val avatarCacheKey = person.tmdbId?.takeIf { it > 0 }?.let(::castAvatarSharedTransitionKey)
|
||||
val platformContext = LocalPlatformContext.current
|
||||
val avatarRequest = if (!person.photo.isNullOrBlank() && !avatarCacheKey.isNullOrBlank()) {
|
||||
remember(platformContext, person.photo, avatarCacheKey) {
|
||||
ImageRequest.Builder(platformContext)
|
||||
.data(person.photo)
|
||||
.memoryCacheKey(avatarCacheKey)
|
||||
.placeholderMemoryCacheKey(avatarCacheKey)
|
||||
.diskCacheKey(person.photo)
|
||||
.build()
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val avatarSharedElementModifier = if (
|
||||
sharedTransitionScope != null &&
|
||||
animatedVisibilityScope != null &&
|
||||
|
|
@ -124,7 +142,7 @@ private fun CastItem(
|
|||
) {
|
||||
if (person.photo != null) {
|
||||
AsyncImage(
|
||||
model = person.photo,
|
||||
model = avatarRequest ?: person.photo,
|
||||
contentDescription = person.name,
|
||||
modifier = Modifier.matchParentSize(),
|
||||
contentScale = ContentScale.Crop,
|
||||
|
|
|
|||
Loading…
Reference in a new issue