Add detail cover placeholder & error.

This commit is contained in:
Thomas Andres Gomez 2023-04-06 17:17:08 +02:00
parent b338ea221a
commit 406e1f67d5
4 changed files with 118 additions and 21 deletions

View file

@ -2,6 +2,10 @@ package com.pixelized.biblib.ui.screen.home.detail
import android.content.res.Configuration.UI_MODE_NIGHT_NO
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import android.graphics.drawable.Drawable
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
@ -18,6 +22,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
@ -26,6 +31,10 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.core.text.HtmlCompat
import androidx.core.text.toSpannable
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.pixelized.biblib.R
import com.pixelized.biblib.ui.composable.SpannedText
import com.pixelized.biblib.ui.composable.animation.AnimatedDelayer
@ -114,24 +123,27 @@ fun DetailScreenContent(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
GlideImage(
modifier = Modifier.height(MaterialTheme.bibLib.dimen.detail.cover),
previewPlaceholder = R.drawable.ic_fondatoin_cover,
circularReveal = CircularReveal(duration = 1000),
contentScale = ContentScale.FillHeight,
imageModel = book.cover,
)
Text(
modifier = Modifier
.clickable(onClick = onOpenOnBibLib)
.padding(
horizontal = 8.dp,
vertical = 2.dp,
),
style = MaterialTheme.bibLib.typography.base.caption,
color = MaterialTheme.bibLib.colors.typography.emphasis,
text = stringResource(id = R.string.detail_open_on_biblib)
)
AnimatedOffset {
Cover(
modifier = Modifier
.fillMaxWidth()
.height(MaterialTheme.bibLib.dimen.detail.cover),
cover = book.cover,
)
}
AnimatedOffset {
Text(
modifier = Modifier
.clickable(onClick = onOpenOnBibLib)
.padding(
horizontal = 8.dp,
vertical = 2.dp,
),
style = MaterialTheme.bibLib.typography.base.caption,
color = MaterialTheme.bibLib.colors.typography.emphasis,
text = stringResource(id = R.string.detail_open_on_biblib)
)
}
}
AnimatedOffset {
@ -240,6 +252,52 @@ fun DetailScreenContent(
}
}
@Composable
private fun Cover(
modifier: Modifier = Modifier,
cover: String,
) {
val placeholder = remember(cover) { mutableStateOf(true) }
val error = remember(cover) { mutableStateOf(false) }
Box(
modifier = modifier,
contentAlignment = Alignment.Center
) {
GlideImage(
requestListener = rememberRequestListener(
placeholder = placeholder,
error = error,
),
previewPlaceholder = R.drawable.ic_fondatoin_cover,
circularReveal = CircularReveal(duration = 500),
contentScale = ContentScale.FillHeight,
imageModel = cover,
)
Box(
modifier = Modifier
.height(MaterialTheme.bibLib.dimen.detail.cover)
.aspectRatio(ratio = remember { 1f / 1.5f })
.placeholder(
shape = MaterialTheme.bibLib.shapes.bookThumbnailCoverLarge,
isShimmering = { error.value },
visible = { placeholder.value },
)
)
AnimatedVisibility(
visible = error.value,
enter = fadeIn(),
exit = fadeOut(),
) {
Icon(
modifier = Modifier.size(64.dp),
painter = painterResource(id = R.drawable.ic_no_photography_24),
contentDescription = null
)
}
}
}
@Composable
private fun Spacer(height: State<Dp>) {
Spacer(modifier = Modifier.height(height = height.value))
@ -269,6 +327,37 @@ private fun TitleLabel(
}
}
@Composable
fun rememberRequestListener(
placeholder: MutableState<Boolean>,
error: MutableState<Boolean>,
): RequestListener<Drawable> {
return remember(placeholder, error) {
object : RequestListener<Drawable> {
override fun onLoadFailed(
exception: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
error.value = true
return true
}
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
placeholder.value = false
return false
}
}
}
}
@Composable
@Preview(showBackground = true, uiMode = UI_MODE_NIGHT_NO, heightDp = 1000)
@Preview(showBackground = true, uiMode = UI_MODE_NIGHT_YES, heightDp = 1000)

View file

@ -75,7 +75,7 @@ fun bibLibLightColors(
),
placeHolder: BibLibColor.PlaceHolder = BibLibColor.PlaceHolder(
color = BibLibColorPalette.LightGrey,
shimmer = BibLibColorPalette.Grey,
shimmer = BibLibColorPalette.VeryLightGrey,
),
) = BibLibColor(
base = base,

View file

@ -48,12 +48,15 @@ fun Modifier.autofill(
@Composable
fun Modifier.placeholder(
color: Color = MaterialTheme.bibLib.colors.placeHolder.color,
shimmer: Color = MaterialTheme.bibLib.colors.placeHolder.shimmer,
shimmer: Color? = MaterialTheme.bibLib.colors.placeHolder.shimmer,
shape: Shape = CircleShape,
isShimmering: () -> Boolean = { true },
visible: () -> Boolean,
) = this.placeholder(
visible = visible(),
color = color,
shape = shape,
highlight = PlaceholderHighlight.shimmer(highlightColor = shimmer),
highlight = shimmer
?.takeIf { isShimmering() }
?.let { PlaceholderHighlight.shimmer(highlightColor = it) },
)

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#DFDFDF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M8.9,6.07L7.48,4.66L9,3h6l1.83,2H20c1.1,0 2,0.9 2,2v12c0,0.05 -0.01,0.1 -0.02,0.16L20,17.17V7h-4.05l-1.83,-2H9.88L8.9,6.07zM20.49,23.31L18.17,21H4c-1.1,0 -2,-0.9 -2,-2V7c0,-0.59 0.27,-1.12 0.68,-1.49l-2,-2L2.1,2.1l19.8,19.8L20.49,23.31zM9.19,12.02C9.08,12.33 9,12.65 9,13c0,1.66 1.34,3 3,3c0.35,0 0.67,-0.08 0.98,-0.19L9.19,12.02zM16.17,19l-1.68,-1.68C13.76,17.75 12.91,18 12,18c-2.76,0 -5,-2.24 -5,-5c0,-0.91 0.25,-1.76 0.68,-2.49L4.17,7H4v12H16.17zM14.81,11.98l2.07,2.07C16.96,13.71 17,13.36 17,13c0,-2.76 -2.24,-5 -5,-5c-0.36,0 -0.71,0.04 -1.06,0.12l2.07,2.07C13.85,10.49 14.51,11.15 14.81,11.98z"/>
</vector>