Add route detail photo tile loaders

This commit is contained in:
admin
2026-07-05 23:29:49 +02:00
parent 62c0469669
commit 1834763f19
4 changed files with 127 additions and 3 deletions
@@ -2490,13 +2490,44 @@ private fun PhotoTile(
onDeletePhoto: (RoutePhotoDto) -> Unit,
modifier: Modifier = Modifier,
) {
Box(modifier.aspectRatio(1f)) {
val hasPhoto = photo.url.isNotBlank()
var imageLoading by remember(photo.url) { mutableStateOf(hasPhoto) }
var imageError by remember(photo.url) { mutableStateOf(!hasPhoto) }
Box(modifier.aspectRatio(1f).background(TppTheme.colors.panel, RoundedCornerShape(4.dp))) {
AsyncImage(
model = imageRequest(photo.url, imageAuthHeader),
contentDescription = "Zdjecie ladunku",
contentScale = ContentScale.Crop,
onLoading = {
imageLoading = true
imageError = false
},
onSuccess = {
imageLoading = false
imageError = false
},
onError = {
imageLoading = false
imageError = true
},
modifier = Modifier.fillMaxSize().clickable { onPhoto(photo) },
)
AnimatedVisibility(
visible = shouldShowPhotoTileLoadingState(hasPhoto, imageLoading, imageError),
enter = fadeIn(),
exit = fadeOut(),
modifier = Modifier.align(Alignment.Center),
) {
PhotoTileLoadingOverlay()
}
AnimatedVisibility(
visible = shouldShowPhotoTileErrorState(hasPhoto, imageError),
enter = fadeIn(),
exit = fadeOut(),
modifier = Modifier.align(Alignment.Center),
) {
PhotoTileErrorOverlay()
}
if (isDeleting) {
Box(
Modifier.fillMaxSize().background(Color.White.copy(alpha = 0.72f)),
@@ -2546,14 +2577,45 @@ private fun PendingPhotoTile(
onDismiss = { showFailureDetails = false },
)
}
val hasPhoto = upload.localPath.isNotBlank()
var imageLoading by remember(upload.localPath) { mutableStateOf(hasPhoto) }
var imageError by remember(upload.localPath) { mutableStateOf(!hasPhoto) }
Box(modifier.aspectRatio(1f).background(TppTheme.colors.panel, RoundedCornerShape(4.dp))) {
AsyncImage(
model = File(upload.localPath),
contentDescription = "Zdjęcie oczekujące na zapis",
contentScale = ContentScale.Crop,
onLoading = {
imageLoading = true
imageError = false
},
onSuccess = {
imageLoading = false
imageError = false
},
onError = {
imageLoading = false
imageError = true
},
modifier = Modifier.fillMaxSize().clickable { onPhoto(upload) },
)
Box(Modifier.fillMaxSize().background(Color.Black.copy(alpha = 0.34f)))
AnimatedVisibility(
visible = shouldShowPhotoTileLoadingState(hasPhoto, imageLoading, imageError),
enter = fadeIn(),
exit = fadeOut(),
modifier = Modifier.align(Alignment.Center),
) {
PhotoTileLoadingOverlay()
}
AnimatedVisibility(
visible = shouldShowPhotoTileErrorState(hasPhoto, imageError),
enter = fadeIn(),
exit = fadeOut(),
modifier = Modifier.align(Alignment.Center),
) {
PhotoTileErrorOverlay()
}
if (isDeleting) {
Box(
Modifier.fillMaxSize().background(Color.White.copy(alpha = 0.72f)),
@@ -2642,6 +2704,50 @@ private fun PendingPhotoTile(
}
}
@Composable
private fun PhotoTileLoadingOverlay() {
Box(
modifier = Modifier
.size(54.dp)
.background(TppTheme.colors.card.copy(alpha = 0.94f), RoundedCornerShape(8.dp))
.border(1.dp, TppTheme.colors.outline.copy(alpha = 0.7f), RoundedCornerShape(8.dp)),
contentAlignment = Alignment.Center,
) {
CircularProgressIndicator(
modifier = Modifier.size(25.dp),
color = TppTheme.colors.forest,
trackColor = TppTheme.colors.outline.copy(alpha = 0.32f),
strokeWidth = 2.5.dp,
)
}
}
@Composable
private fun PhotoTileErrorOverlay() {
Column(
modifier = Modifier
.background(TppTheme.colors.card.copy(alpha = 0.96f), RoundedCornerShape(8.dp))
.border(1.dp, TppTheme.colors.error.copy(alpha = 0.36f), RoundedCornerShape(8.dp))
.padding(horizontal = 10.dp, vertical = 8.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(2.dp),
) {
Text(
"Błąd",
color = TppTheme.colors.error,
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold,
style = MaterialTheme.typography.labelMedium,
)
Text(
"miniatury",
color = TppTheme.colors.muted,
fontFamily = FontFamily.Monospace,
style = MaterialTheme.typography.labelSmall,
)
}
}
@Composable
private fun EmptyPhotoState() {
Box(
@@ -65,6 +65,12 @@ fun shouldShowPhotoPreviewLoadingState(hasPhoto: Boolean, isLoading: Boolean, is
fun shouldShowPhotoPreviewErrorState(hasPhoto: Boolean, isError: Boolean): Boolean =
hasPhoto && isError
fun shouldShowPhotoTileLoadingState(hasPhoto: Boolean, isLoading: Boolean, isError: Boolean): Boolean =
hasPhoto && isLoading && !isError
fun shouldShowPhotoTileErrorState(hasPhoto: Boolean, isError: Boolean): Boolean =
hasPhoto && isError
fun authBrandBannerHeightDp(screenHeightDp: Int): Int =
when {
screenHeightDp < 640 -> 118