From 8caa4032bf69fb73352cce452a77f44cd5c111d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Font=C3=A1n?= Date: Tue, 28 Jan 2025 10:35:12 +0100 Subject: [PATCH] refactor: Improve image loading placeholders 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. --- .../com/bobbyesp/metadator/MainActivity.kt | 2 + .../components/image/AsyncImage.kt | 30 +++++++----- .../components/others/LoadingPlaceholder.kt | 46 +++++++++++++++++++ .../{PlaceholderCreator.kt => Placeholder.kt} | 42 +++++++++-------- 4 files changed, 90 insertions(+), 30 deletions(-) create mode 100644 app/ui/src/main/java/com/bobbyesp/ui/components/others/LoadingPlaceholder.kt rename app/ui/src/main/java/com/bobbyesp/ui/components/others/{PlaceholderCreator.kt => Placeholder.kt} (75%) diff --git a/app/src/main/java/com/bobbyesp/metadator/MainActivity.kt b/app/src/main/java/com/bobbyesp/metadator/MainActivity.kt index f272f5d..bd98ab8 100644 --- a/app/src/main/java/com/bobbyesp/metadator/MainActivity.kt +++ b/app/src/main/java/com/bobbyesp/metadator/MainActivity.kt @@ -38,8 +38,10 @@ class MainActivity : ComponentActivity(), KoinComponent { setCrashlyticsCollection() setContent { KoinContext { + val sonner = rememberToasterState() val windowSizeClass = calculateWindowSizeClass(this) + AppLocalSettingsProvider( windowWidthSize = windowSizeClass.widthSizeClass, playerConnectionHandler = connectionHandler, diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/components/image/AsyncImage.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/components/image/AsyncImage.kt index 8802808..dbcbab0 100644 --- a/app/src/main/java/com/bobbyesp/metadator/presentation/components/image/AsyncImage.kt +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/components/image/AsyncImage.kt @@ -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 @@ -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 = { _ -> } @@ -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, diff --git a/app/ui/src/main/java/com/bobbyesp/ui/components/others/LoadingPlaceholder.kt b/app/ui/src/main/java/com/bobbyesp/ui/components/others/LoadingPlaceholder.kt new file mode 100644 index 0000000..510fa7c --- /dev/null +++ b/app/ui/src/main/java/com/bobbyesp/ui/components/others/LoadingPlaceholder.kt @@ -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, + ) + } + + } +} \ No newline at end of file diff --git a/app/ui/src/main/java/com/bobbyesp/ui/components/others/PlaceholderCreator.kt b/app/ui/src/main/java/com/bobbyesp/ui/components/others/Placeholder.kt similarity index 75% rename from app/ui/src/main/java/com/bobbyesp/ui/components/others/PlaceholderCreator.kt rename to app/ui/src/main/java/com/bobbyesp/ui/components/others/Placeholder.kt index cebbe2d..45c2d33 100644 --- a/app/ui/src/main/java/com/bobbyesp/ui/components/others/PlaceholderCreator.kt +++ b/app/ui/src/main/java/com/bobbyesp/ui/components/others/Placeholder.kt @@ -22,7 +22,7 @@ import androidx.compose.ui.unit.dp @Stable @Composable -fun PlaceholderCreator( +fun Placeholder( modifier: Modifier = Modifier, icon: ImageVector?, colorful: Boolean, @@ -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" + ) + } } \ No newline at end of file