Skip to content

Commit 153b34f

Browse files
authored
Merge pull request #850 from qamarelsafadi/loading-progress-for-image
Fix #849: Loading progress for image
2 parents 492697c + 308f51f commit 153b34f

File tree

3 files changed

+82
-20
lines changed
  • core
  • feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou

3 files changed

+82
-20
lines changed

core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/DynamicAsyncImage.kt

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,28 @@
1616

1717
package com.google.samples.apps.nowinandroid.core.designsystem.component
1818

19+
import androidx.compose.foundation.Image
20+
import androidx.compose.foundation.layout.Box
21+
import androidx.compose.foundation.layout.size
22+
import androidx.compose.material3.CircularProgressIndicator
23+
import androidx.compose.material3.MaterialTheme
1924
import androidx.compose.runtime.Composable
25+
import androidx.compose.runtime.getValue
26+
import androidx.compose.runtime.mutableStateOf
27+
import androidx.compose.runtime.remember
28+
import androidx.compose.runtime.setValue
29+
import androidx.compose.ui.Alignment
2030
import androidx.compose.ui.Modifier
2131
import androidx.compose.ui.graphics.ColorFilter
2232
import androidx.compose.ui.graphics.painter.Painter
33+
import androidx.compose.ui.layout.ContentScale
34+
import androidx.compose.ui.res.painterResource
35+
import androidx.compose.ui.unit.dp
2336
import coil.compose.AsyncImage
37+
import coil.compose.AsyncImagePainter.State.Error
38+
import coil.compose.AsyncImagePainter.State.Loading
39+
import coil.compose.rememberAsyncImagePainter
40+
import com.google.samples.apps.nowinandroid.core.designsystem.R
2441
import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalTintTheme
2542

2643
/**
@@ -31,14 +48,37 @@ fun DynamicAsyncImage(
3148
imageUrl: String,
3249
contentDescription: String?,
3350
modifier: Modifier = Modifier,
34-
placeholder: Painter? = null,
51+
placeholder: Painter = painterResource(R.drawable.ic_placeholder_default),
3552
) {
3653
val iconTint = LocalTintTheme.current.iconTint
37-
AsyncImage(
38-
placeholder = placeholder,
54+
var isLoading by remember { mutableStateOf(true) }
55+
var isError by remember { mutableStateOf(false) }
56+
val imageLoader = rememberAsyncImagePainter(
3957
model = imageUrl,
40-
contentDescription = contentDescription,
41-
colorFilter = if (iconTint != null) ColorFilter.tint(iconTint) else null,
42-
modifier = modifier,
58+
onState = { state ->
59+
isLoading = state is Loading
60+
isError = state is Error
61+
},
4362
)
63+
Box(
64+
modifier = modifier,
65+
contentAlignment = Alignment.Center,
66+
) {
67+
if (isLoading) {
68+
// Display a progress bar while loading
69+
CircularProgressIndicator(
70+
modifier = Modifier
71+
.align(Alignment.Center)
72+
.size(80.dp),
73+
color = MaterialTheme.colorScheme.tertiary,
74+
)
75+
}
76+
Image(
77+
contentScale = ContentScale.Crop,
78+
painter = if (isError.not()) imageLoader else placeholder,
79+
contentDescription = contentDescription,
80+
colorFilter = if (iconTint != null) ColorFilter.tint(iconTint) else null,
81+
modifier = modifier,
82+
)
83+
}
4484
}

core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.google.samples.apps.nowinandroid.core.ui
1818

1919
import androidx.compose.foundation.Canvas
20+
import androidx.compose.foundation.Image
2021
import androidx.compose.foundation.horizontalScroll
2122
import androidx.compose.foundation.layout.Arrangement
2223
import androidx.compose.foundation.layout.Box
@@ -31,6 +32,7 @@ import androidx.compose.foundation.rememberScrollState
3132
import androidx.compose.foundation.shape.RoundedCornerShape
3233
import androidx.compose.material3.Card
3334
import androidx.compose.material3.CardDefaults
35+
import androidx.compose.material3.CircularProgressIndicator
3436
import androidx.compose.material3.ExperimentalMaterial3Api
3537
import androidx.compose.material3.Icon
3638
import androidx.compose.material3.MaterialTheme
@@ -57,7 +59,9 @@ import androidx.compose.ui.semantics.semantics
5759
import androidx.compose.ui.tooling.preview.Preview
5860
import androidx.compose.ui.tooling.preview.PreviewParameter
5961
import 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
6165
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaIconToggleButton
6266
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopicTag
6367
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
@@ -72,7 +76,6 @@ import java.time.ZoneId
7276
import java.time.format.DateTimeFormatter
7377
import java.time.format.FormatStyle
7478
import 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(
147150
fun 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

feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,6 @@ fun TopicIcon(
434434
modifier: Modifier = Modifier,
435435
) {
436436
DynamicAsyncImage(
437-
// TODO b/228077205, show loading image visual instead of static placeholder
438437
placeholder = painterResource(R.drawable.ic_icon_placeholder),
439438
imageUrl = imageUrl,
440439
contentDescription = null, // decorative

0 commit comments

Comments
 (0)