Skip to content

Commit f203e9a

Browse files
committed
feat: replacing SubcomposeAsyncImage as its not recommended to use with lazyLayout
1 parent 5abc69f commit f203e9a

File tree

2 files changed

+77
-46
lines changed
  • core

2 files changed

+77
-46
lines changed

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

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,30 @@ package com.google.samples.apps.nowinandroid.core.designsystem.component
1818

1919
import androidx.compose.foundation.Image
2020
import androidx.compose.foundation.layout.Box
21+
import androidx.compose.foundation.layout.fillMaxWidth
22+
import androidx.compose.foundation.layout.height
2123
import androidx.compose.foundation.layout.size
2224
import androidx.compose.material3.CircularProgressIndicator
2325
import androidx.compose.material3.MaterialTheme
2426
import androidx.compose.runtime.Composable
27+
import androidx.compose.runtime.getValue
28+
import androidx.compose.runtime.mutableStateOf
29+
import androidx.compose.runtime.remember
30+
import androidx.compose.runtime.setValue
2531
import androidx.compose.ui.Alignment
2632
import androidx.compose.ui.Modifier
2733
import androidx.compose.ui.graphics.ColorFilter
2834
import androidx.compose.ui.graphics.painter.Painter
35+
import androidx.compose.ui.layout.ContentScale
2936
import androidx.compose.ui.res.painterResource
3037
import androidx.compose.ui.unit.dp
3138
import coil.compose.AsyncImage
39+
import coil.compose.AsyncImagePainter.State.Error
40+
import coil.compose.AsyncImagePainter.State.Loading
3241
import coil.compose.SubcomposeAsyncImage
42+
import coil.compose.rememberAsyncImagePainter
3343
import com.google.samples.apps.nowinandroid.core.designsystem.R
44+
import com.google.samples.apps.nowinandroid.core.designsystem.R.drawable
3445
import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalTintTheme
3546

3647
/**
@@ -44,27 +55,34 @@ fun DynamicAsyncImage(
4455
placeholder: Painter = painterResource(R.drawable.ic_placeholder_default),
4556
) {
4657
val iconTint = LocalTintTheme.current.iconTint
47-
SubcomposeAsyncImage(
48-
error = {
49-
Image(
50-
painter = placeholder,
51-
contentDescription = "placeholder image",
52-
)
53-
},
58+
var isLoading by remember { mutableStateOf(true) }
59+
var isError by remember { mutableStateOf(false) }
60+
val imageLoader = rememberAsyncImagePainter(
5461
model = imageUrl,
55-
contentDescription = contentDescription,
56-
colorFilter = if (iconTint != null) ColorFilter.tint(iconTint) else null,
57-
modifier = modifier,
58-
loading = {
59-
Box(
60-
modifier = Modifier,
61-
contentAlignment = Alignment.Center,
62-
) {
63-
CircularProgressIndicator(
64-
Modifier.size(80.dp),
65-
color = MaterialTheme.colorScheme.tertiary,
66-
)
67-
}
62+
onState = { state ->
63+
isLoading = state is Loading
64+
isError = state is Error
6865
},
6966
)
67+
Box(
68+
modifier = modifier,
69+
contentAlignment = Alignment.Center,
70+
) {
71+
if (isLoading) {
72+
// Display a progress bar while loading
73+
CircularProgressIndicator(
74+
modifier = Modifier
75+
.align(Alignment.Center)
76+
.size(80.dp),
77+
color = MaterialTheme.colorScheme.tertiary,
78+
)
79+
}
80+
Image(
81+
contentScale = ContentScale.Crop,
82+
painter = if (isError.not()) imageLoader else placeholder,
83+
contentDescription = contentDescription,
84+
colorFilter = if (iconTint != null) ColorFilter.tint(iconTint) else null,
85+
modifier = modifier,
86+
)
87+
}
7088
}

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

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import androidx.compose.runtime.DisposableEffect
4444
import androidx.compose.runtime.getValue
4545
import androidx.compose.runtime.mutableStateOf
4646
import androidx.compose.runtime.remember
47+
import androidx.compose.runtime.rememberCoroutineScope
4748
import androidx.compose.runtime.setValue
4849
import androidx.compose.ui.Alignment
4950
import androidx.compose.ui.Modifier
@@ -59,7 +60,12 @@ import androidx.compose.ui.semantics.semantics
5960
import androidx.compose.ui.tooling.preview.Preview
6061
import androidx.compose.ui.tooling.preview.PreviewParameter
6162
import androidx.compose.ui.unit.dp
62-
import coil.compose.SubcomposeAsyncImage
63+
import coil.compose.AsyncImage
64+
import coil.compose.AsyncImagePainter
65+
import coil.compose.rememberAsyncImagePainter
66+
import coil.compose.rememberImagePainter
67+
import coil.request.ImageRequest
68+
import com.google.samples.apps.nowinandroid.core.designsystem.R.drawable
6369
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaIconToggleButton
6470
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopicTag
6571
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
@@ -74,7 +80,6 @@ import java.time.ZoneId
7480
import java.time.format.DateTimeFormatter
7581
import java.time.format.FormatStyle
7682
import java.util.Locale
77-
import com.google.samples.apps.nowinandroid.core.designsystem.R as DesignsystemR
7883

7984
/**
8085
* [NewsResource] card used on the following screens: For You, Saved
@@ -149,32 +154,41 @@ fun NewsResourceCardExpanded(
149154
fun NewsResourceHeaderImage(
150155
headerImageUrl: String?,
151156
) {
152-
SubcomposeAsyncImage(
153-
modifier = Modifier
154-
.fillMaxWidth()
155-
.height(180.dp),
156-
contentScale = ContentScale.Crop,
157+
var isLoading by remember { mutableStateOf(true) }
158+
var isError by remember { mutableStateOf(false) }
159+
val imageLoader = rememberAsyncImagePainter(
157160
model = headerImageUrl,
158-
// TODO b/226661685: Investigate using alt text of image to populate content description
159-
contentDescription = null, // decorative image,
160-
error = {
161-
Image(
162-
painter = painterResource(DesignsystemR.drawable.ic_placeholder_default),
163-
contentDescription = "placeholder image",
164-
)
165-
},
166-
loading = {
167-
Box(
168-
modifier = Modifier.size(180.dp),
169-
contentAlignment = Alignment.Center,
170-
) {
171-
CircularProgressIndicator(
172-
Modifier.size(80.dp),
173-
color = MaterialTheme.colorScheme.tertiary,
174-
)
175-
}
161+
onState = { state ->
162+
isLoading = state is AsyncImagePainter.State.Loading
163+
isError = state is AsyncImagePainter.State.Error
176164
},
177165
)
166+
Box(
167+
modifier = Modifier
168+
.fillMaxWidth()
169+
.height(180.dp),
170+
contentAlignment = Alignment.Center,
171+
) {
172+
if (isLoading) {
173+
// Display a progress bar while loading
174+
CircularProgressIndicator(
175+
modifier = Modifier
176+
.align(Alignment.Center)
177+
.size(80.dp),
178+
color = MaterialTheme.colorScheme.tertiary,
179+
)
180+
}
181+
182+
Image(
183+
modifier = Modifier
184+
.fillMaxWidth()
185+
.height(180.dp),
186+
contentScale = ContentScale.Crop,
187+
painter = if (isError.not()) imageLoader else painterResource(drawable.ic_placeholder_default),
188+
// TODO b/226661685: Investigate using alt text of image to populate content description
189+
contentDescription = null, // decorative image,
190+
)
191+
}
178192
}
179193

180194
@Composable
@@ -249,7 +263,6 @@ fun dateFormatted(publishDate: Instant): String {
249263
.withLocale(Locale.getDefault())
250264
.withZone(zoneId)
251265
.format(publishDate.toJavaInstant())
252-
253266
}
254267

255268
@Composable

0 commit comments

Comments
 (0)