From b291ac5f384774610a144ddc7c61f3bb181f7bfa Mon Sep 17 00:00:00 2001 From: qamarelsafadi Date: Thu, 10 Aug 2023 21:35:30 +0300 Subject: [PATCH] feat: replacing SubcomposeAsyncImage as its not recommended to use with lazyLayout --- .../component/DynamicAsyncImage.kt | 58 +++++++++++------ .../nowinandroid/core/ui/NewsResourceCard.kt | 65 +++++++++++-------- 2 files changed, 77 insertions(+), 46 deletions(-) diff --git a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/DynamicAsyncImage.kt b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/DynamicAsyncImage.kt index 7a3c39393..4a5632078 100644 --- a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/DynamicAsyncImage.kt +++ b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/DynamicAsyncImage.kt @@ -18,19 +18,30 @@ package com.google.samples.apps.nowinandroid.core.designsystem.component import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.size import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import coil.compose.AsyncImage +import coil.compose.AsyncImagePainter.State.Error +import coil.compose.AsyncImagePainter.State.Loading import coil.compose.SubcomposeAsyncImage +import coil.compose.rememberAsyncImagePainter import com.google.samples.apps.nowinandroid.core.designsystem.R +import com.google.samples.apps.nowinandroid.core.designsystem.R.drawable import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalTintTheme /** @@ -44,27 +55,34 @@ fun DynamicAsyncImage( placeholder: Painter = painterResource(R.drawable.ic_placeholder_default), ) { val iconTint = LocalTintTheme.current.iconTint - SubcomposeAsyncImage( - error = { - Image( - painter = placeholder, - contentDescription = "placeholder image", - ) - }, + var isLoading by remember { mutableStateOf(true) } + var isError by remember { mutableStateOf(false) } + val imageLoader = rememberAsyncImagePainter( model = imageUrl, - contentDescription = contentDescription, - colorFilter = if (iconTint != null) ColorFilter.tint(iconTint) else null, - modifier = modifier, - loading = { - Box( - modifier = Modifier, - contentAlignment = Alignment.Center, - ) { - CircularProgressIndicator( - Modifier.size(80.dp), - color = MaterialTheme.colorScheme.tertiary, - ) - } + onState = { state -> + isLoading = state is Loading + isError = state is Error }, ) + Box( + modifier = modifier, + contentAlignment = Alignment.Center, + ) { + if (isLoading) { + // Display a progress bar while loading + CircularProgressIndicator( + modifier = Modifier + .align(Alignment.Center) + .size(80.dp), + color = MaterialTheme.colorScheme.tertiary, + ) + } + Image( + contentScale = ContentScale.Crop, + painter = if (isError.not()) imageLoader else placeholder, + contentDescription = contentDescription, + colorFilter = if (iconTint != null) ColorFilter.tint(iconTint) else null, + modifier = modifier, + ) + } } diff --git a/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt b/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt index 621bf143c..1fb8d41e5 100644 --- a/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt +++ b/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt @@ -44,6 +44,7 @@ import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -59,7 +60,12 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp -import coil.compose.SubcomposeAsyncImage +import coil.compose.AsyncImage +import coil.compose.AsyncImagePainter +import coil.compose.rememberAsyncImagePainter +import coil.compose.rememberImagePainter +import coil.request.ImageRequest +import com.google.samples.apps.nowinandroid.core.designsystem.R.drawable import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaIconToggleButton import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopicTag import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons @@ -74,7 +80,6 @@ import java.time.ZoneId import java.time.format.DateTimeFormatter import java.time.format.FormatStyle import java.util.Locale -import com.google.samples.apps.nowinandroid.core.designsystem.R as DesignsystemR /** * [NewsResource] card used on the following screens: For You, Saved @@ -149,32 +154,41 @@ fun NewsResourceCardExpanded( fun NewsResourceHeaderImage( headerImageUrl: String?, ) { - SubcomposeAsyncImage( - modifier = Modifier - .fillMaxWidth() - .height(180.dp), - contentScale = ContentScale.Crop, + var isLoading by remember { mutableStateOf(true) } + var isError by remember { mutableStateOf(false) } + val imageLoader = rememberAsyncImagePainter( model = headerImageUrl, - // TODO b/226661685: Investigate using alt text of image to populate content description - contentDescription = null, // decorative image, - error = { - Image( - painter = painterResource(DesignsystemR.drawable.ic_placeholder_default), - contentDescription = "placeholder image", - ) - }, - loading = { - Box( - modifier = Modifier.size(180.dp), - contentAlignment = Alignment.Center, - ) { - CircularProgressIndicator( - Modifier.size(80.dp), - color = MaterialTheme.colorScheme.tertiary, - ) - } + onState = { state -> + isLoading = state is AsyncImagePainter.State.Loading + isError = state is AsyncImagePainter.State.Error }, ) + Box( + modifier = Modifier + .fillMaxWidth() + .height(180.dp), + contentAlignment = Alignment.Center, + ) { + if (isLoading) { + // Display a progress bar while loading + CircularProgressIndicator( + modifier = Modifier + .align(Alignment.Center) + .size(80.dp), + color = MaterialTheme.colorScheme.tertiary, + ) + } + + Image( + modifier = Modifier + .fillMaxWidth() + .height(180.dp), + contentScale = ContentScale.Crop, + painter = if (isError.not()) imageLoader else painterResource(drawable.ic_placeholder_default), + // TODO b/226661685: Investigate using alt text of image to populate content description + contentDescription = null, // decorative image, + ) + } } @Composable @@ -249,7 +263,6 @@ fun dateFormatted(publishDate: Instant): String { .withLocale(Locale.getDefault()) .withZone(zoneId) .format(publishDate.toJavaInstant()) - } @Composable