-
Notifications
You must be signed in to change notification settings - Fork 749
Open
Description
Describe the bug
Hello, We have some legacy screens in our codebase in which the activity handles uiMode in manifest manually:
<activity
android:name="sample.compose.MainActivity"
android:exported="true"
android:configChanges="uiMode"> // Can't touch this
The issue is, when AsyncImage is used, it does not load the drawable-night variant or rather, AsyncImage thinks it's the same exact painter resource:
| Video | Light Mode | Dark Mode |
|---|---|---|
![]() |
![]() |
In here, the icon used has 2 versions, one in drawable and one in drawable-night.
To Reproduce
Option A: checkout branch
- Checkout the branch https://github.com/nishatoma/coil/tree/async-error-painter-no-recompose-reproducer
- Run the
samples.composeapp
Option B: manual code snippet
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:enableOnBackInvokedCallback="true"
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
<profileable
android:shell="true"
tools:targetApi="q"/>
<activity
android:name="sample.compose.MainActivity"
android:exported="true"
android:configChanges="uiMode">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
Code:
setContent {
val painter = painterResource(R.drawable.sample_icon)
val isDark = isSystemInDarkTheme()
val lightColors = lightColorScheme()
val darkColors = darkColorScheme()
MaterialTheme(
colorScheme = if (isDark) darkColors else lightColors,
) {
Surface(
modifier = Modifier
.background(MaterialTheme.colorScheme.background)
.fillMaxSize()
) {
Column(
modifier = Modifier.padding(vertical = 8.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = if (isDark) {
"Dark Mode"
} else {
"Light Mode"
},
style = MaterialTheme.typography.headlineLarge
)
Spacer(modifier = Modifier.height(24.dp))
Text("Regular Image")
Spacer(modifier = Modifier.height(8.dp))
Image(
painter = painter,
contentDescription = null
)
Spacer(modifier = Modifier.height(20.dp))
HorizontalDivider(thickness = 2.dp)
Spacer(modifier = Modifier.height(20.dp))
Text("Async Image")
Spacer(modifier = Modifier.height(8.dp))
AsyncImage(
model = "https://imagedoesnotexist.com/image.png",
contentDescription = "Image",
error = painter
)
}
}
}
}
Sample Icon (drawable):
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M0,0h24v24H0z" />
<path
android:pathData="M0.5,0.5h23v23h-23z"
android:fillColor="@android:color/transparent"
android:strokeColor="#000000"
android:strokeWidth="1"/>
<path
android:fillColor="#000000"
android:pathData="M12,7a5,5 0 1,1 -0.001,0zM12,1v3M12,20v3M4.22,4.22l2.12,2.12M17.66,17.66l2.12,2.12M1,12h3M20,12h3M4.22,19.78l2.12,-2.12M17.66,6.34l2.12,-2.12" />
</vector>
Sample Icon (drawable-night):
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000000"
android:pathData="M0,0h24v24H0z" />
<path
android:pathData="M0.5,0.5h23v23h-23z"
android:fillColor="@android:color/transparent"
android:strokeColor="#FFFFFF"
android:strokeWidth="1"/>
<path
android:fillColor="#FFFF00"
android:pathData="M12,7a5,5 0 1,1 -0.001,0zM12,1v3M12,20v3M4.22,4.22l2.12,2.12M17.66,17.66l2.12,2.12M1,12h3M20,12h3M4.22,19.78l2.12,-2.12M17.66,6.34l2.12,-2.12" />
</vector>
Solutions we can't implement due to legacy code:
- Changing manifest property
- Using Subcompose image
- Changing the actual drawable resources breaks current regressions / snapshot tests and is shared between other teams
Possible temporary work-around:
- Have an if-statement that checks if there is an error, and if there is, use a regular image instead of async..
- Force entire AsyncImage to recompose by creating a new size constraint / modifying the model, but this makes network request again
If there is an easier way to handle this I would appreciate some guidance, thank you!
Version
From master branch of coil3
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels

