Skip to content

Commit

Permalink
refactor: Improve image loading placeholders
Browse files Browse the repository at this point in the history
This commit introduces two new components: `LoadingPlaceholder` and `Placeholder`.

- `LoadingPlaceholder` displays a circular progress indicator while content is loading. It can be configured to be colorful or monochrome.
- `Placeholder` displays an icon within a surface, providing a visual cue when content is unavailable. It can also be configured to be colorful or monochrome.

The `AsyncImage` component now uses these new components to provide better feedback to the user during image loading and in cases of errors or missing images. Additionally, the component has been updated to allow for optional placeholders and to handle file-not-found errors more gracefully.

This change improves the overall user experience by providing more informative and visually appealing placeholders during image loading and error states.
  • Loading branch information
BobbyESP committed Jan 28, 2025
1 parent bff2d52 commit 8caa403
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 30 deletions.
2 changes: 2 additions & 0 deletions app/src/main/java/com/bobbyesp/metadator/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ class MainActivity : ComponentActivity(), KoinComponent {
setCrashlyticsCollection()
setContent {
KoinContext {

val sonner = rememberToasterState()
val windowSizeClass = calculateWindowSizeClass(this)

AppLocalSettingsProvider(
windowWidthSize = windowSizeClass.widthSizeClass,
playerConnectionHandler = connectionHandler,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import androidx.compose.ui.platform.LocalContext
import coil.ImageLoader
import coil.request.ImageRequest
import coil.request.SuccessResult
import com.bobbyesp.ui.components.others.PlaceholderCreator
import com.bobbyesp.ui.components.others.LoadingPlaceholder
import com.bobbyesp.ui.components.others.Placeholder
import com.skydoves.landscapist.ImageOptions
import com.skydoves.landscapist.coil.CoilImage
import com.skydoves.landscapist.coil.CoilImageState
Expand All @@ -35,7 +36,7 @@ fun AsyncImage(
imageModel: Any? = null,
imageModifier: Modifier = Modifier,
shape: Shape = MaterialTheme.shapes.small,
placeholder: ImageVector = Icons.Rounded.MusicNote,
placeholder: ImageVector?,
context: Context = LocalContext.current,
imageLoader: ImageLoader? = LocalCoilImageLoader.current,
onSuccessData: (CoilImageState.Success) -> Unit = { _ -> }
Expand All @@ -59,24 +60,31 @@ fun AsyncImage(
}
},
loading = {
PlaceholderCreator(
modifier = imageModifier
.fillMaxSize(),
icon = placeholder,
colorful = false,
contentDescription = "Song cover placeholder"
)
if(placeholder != null) {
Placeholder(
modifier = imageModifier
.fillMaxSize(),
icon = placeholder,
colorful = false,
contentDescription = "Song cover placeholder"
)
} else {
LoadingPlaceholder(
modifier = imageModifier
.fillMaxSize(),
colorful = false
)
}
},
failure = { error ->
//if the error exception if FileNotFoundException, then the icon is a music note, else error outline

val icon = if (error.reason != null && error.reason is java.io.FileNotFoundException) {
Icons.Rounded.MusicNote
} else {
Icons.Rounded.ErrorOutline
}

PlaceholderCreator(
Placeholder(
modifier = imageModifier
.fillMaxSize(),
icon = icon,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.bobbyesp.ui.components.others

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

@Composable
fun LoadingPlaceholder(
modifier: Modifier = Modifier,
progress: Float? = null,
colorful: Boolean,
) {

val color = if (colorful) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surface
val onColor = if (colorful) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.onSurface
val elevation = if (colorful) 0.dp else 8.dp

Surface(
tonalElevation = elevation,
color = color,
modifier = modifier
) {
if (progress == null) {
CircularProgressIndicator(
modifier = Modifier
.fillMaxSize()
.padding(8.dp),
color = onColor,
)
} else {
CircularProgressIndicator(
progress = { progress },
modifier = Modifier
.fillMaxSize()
.padding(8.dp),
color = onColor,
)
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import androidx.compose.ui.unit.dp

@Stable
@Composable
fun PlaceholderCreator(
fun Placeholder(
modifier: Modifier = Modifier,
icon: ImageVector?,
colorful: Boolean,
Expand Down Expand Up @@ -51,27 +51,31 @@ fun PlaceholderCreator(
@Preview
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun PlaceholderCreatorPreview() {
PlaceholderCreator(
modifier = Modifier
.width(200.dp)
.aspectRatio(1f),
icon = Icons.Rounded.Lyrics,
colorful = true,
contentDescription = "Song cover"
)
private fun PlaceholderPreview() {
MaterialTheme {
Placeholder(
modifier = Modifier
.width(200.dp)
.aspectRatio(1f),
icon = Icons.Rounded.Lyrics,
colorful = true,
contentDescription = "Song cover"
)
}
}

@Preview
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun PlaceholderCreatorPreviewNonColourful() {
PlaceholderCreator(
modifier = Modifier
.width(200.dp)
.aspectRatio(1f),
icon = Icons.Default.Lyrics,
colorful = false,
contentDescription = "Song cover"
)
private fun PlaceholderPreviewNonColourful() {
MaterialTheme {
Placeholder(
modifier = Modifier
.width(200.dp)
.aspectRatio(1f),
icon = Icons.Default.Lyrics,
colorful = false,
contentDescription = "Song cover"
)
}
}

0 comments on commit 8caa403

Please sign in to comment.