1717package com.google.samples.apps.nowinandroid.core.ui
1818
1919import androidx.compose.foundation.Canvas
20+ import androidx.compose.foundation.Image
2021import androidx.compose.foundation.horizontalScroll
2122import androidx.compose.foundation.layout.Arrangement
2223import androidx.compose.foundation.layout.Box
@@ -31,6 +32,7 @@ import androidx.compose.foundation.rememberScrollState
3132import androidx.compose.foundation.shape.RoundedCornerShape
3233import androidx.compose.material3.Card
3334import androidx.compose.material3.CardDefaults
35+ import androidx.compose.material3.CircularProgressIndicator
3436import androidx.compose.material3.ExperimentalMaterial3Api
3537import androidx.compose.material3.Icon
3638import androidx.compose.material3.MaterialTheme
@@ -57,7 +59,9 @@ import androidx.compose.ui.semantics.semantics
5759import androidx.compose.ui.tooling.preview.Preview
5860import androidx.compose.ui.tooling.preview.PreviewParameter
5961import androidx.compose.ui.unit.dp
60- import coil.compose.AsyncImage
62+ import coil.compose.AsyncImagePainter
63+ import coil.compose.rememberAsyncImagePainter
64+ import com.google.samples.apps.nowinandroid.core.designsystem.R.drawable
6165import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaIconToggleButton
6266import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopicTag
6367import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
@@ -72,7 +76,6 @@ import java.time.ZoneId
7276import java.time.format.DateTimeFormatter
7377import java.time.format.FormatStyle
7478import java.util.Locale
75- import com.google.samples.apps.nowinandroid.core.designsystem.R as DesignsystemR
7679
7780/* *
7881 * [NewsResource] card used on the following screens: For You, Saved
@@ -147,21 +150,41 @@ fun NewsResourceCardExpanded(
147150fun NewsResourceHeaderImage (
148151 headerImageUrl : String? ,
149152) {
150- AsyncImage (
151- placeholder = if (LocalInspectionMode .current) {
152- painterResource(DesignsystemR .drawable.ic_placeholder_default)
153- } else {
154- // TODO b/228077205, show specific loading image visual
155- null
153+ var isLoading by remember { mutableStateOf(true ) }
154+ var isError by remember { mutableStateOf(false ) }
155+ val imageLoader = rememberAsyncImagePainter(
156+ model = headerImageUrl,
157+ onState = { state ->
158+ isLoading = state is AsyncImagePainter .State .Loading
159+ isError = state is AsyncImagePainter .State .Error
156160 },
161+ )
162+ Box (
157163 modifier = Modifier
158164 .fillMaxWidth()
159165 .height(180 .dp),
160- contentScale = ContentScale .Crop ,
161- model = headerImageUrl,
162- // TODO b/226661685: Investigate using alt text of image to populate content description
163- contentDescription = null , // decorative image
164- )
166+ contentAlignment = Alignment .Center ,
167+ ) {
168+ if (isLoading) {
169+ // Display a progress bar while loading
170+ CircularProgressIndicator (
171+ modifier = Modifier
172+ .align(Alignment .Center )
173+ .size(80 .dp),
174+ color = MaterialTheme .colorScheme.tertiary,
175+ )
176+ }
177+
178+ Image (
179+ modifier = Modifier
180+ .fillMaxWidth()
181+ .height(180 .dp),
182+ contentScale = ContentScale .Crop ,
183+ painter = if (isError.not ()) imageLoader else painterResource(drawable.ic_placeholder_default),
184+ // TODO b/226661685: Investigate using alt text of image to populate content description
185+ contentDescription = null , // decorative image,
186+ )
187+ }
165188}
166189
167190@Composable
0 commit comments