Popraw obsługę galerii zdjęć kierowcy

This commit is contained in:
admin
2026-07-01 02:37:43 +02:00
parent 060896d12b
commit a08fe31d3d
4 changed files with 83 additions and 8 deletions
@@ -62,6 +62,7 @@ import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.pullrefresh.PullRefreshIndicator
import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
@@ -75,6 +76,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
@@ -1023,7 +1025,10 @@ private fun PhotoGrid(
onDeletePhoto: (RoutePhotoDto) -> Unit,
onRetryUpload: (PhotoUploadEntity) -> Unit,
) {
val items = uploads.map { PhotoGridItem.Upload(it) } + photos.map { PhotoGridItem.Server(it) }
var photoPendingDelete by remember { mutableStateOf<RoutePhotoDto?>(null) }
val items = (uploads.map { PhotoGridItem.Upload(it) } + photos.map { PhotoGridItem.Server(it) })
.sortedByDescending { it.sortEpochMillis }
val visibleAttachmentCount = visiblePhotoAttachmentCount(photos.size, uploads.size)
Card(
colors = CardDefaults.cardColors(containerColor = Color.White),
@@ -1032,7 +1037,7 @@ private fun PhotoGrid(
) {
Column(Modifier.padding(20.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) {
Text(
"Załączone zdjęcia (${photos.size})",
"Załączone zdjęcia ($visibleAttachmentCount)",
color = TppColors.Muted,
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.SemiBold,
@@ -1052,7 +1057,7 @@ private fun PhotoGrid(
imageAuthHeader = imageAuthHeader,
isDeleting = item.photo.id in deletingPhotoIds,
onPhoto = onPhoto,
onDeletePhoto = onDeletePhoto,
onDeletePhoto = { photoPendingDelete = it },
modifier = Modifier.weight(1f),
)
is PhotoGridItem.Upload -> PendingPhotoTile(
@@ -1071,11 +1076,37 @@ private fun PhotoGrid(
}
}
}
photoPendingDelete?.let { photo ->
AlertDialog(
onDismissRequest = { photoPendingDelete = null },
title = { Text("Usunąć zdjęcie?", color = TppColors.Ink, fontWeight = FontWeight.Bold) },
text = { Text("Czy na pewno chcesz usunąć to zdjęcie?", color = TppColors.Muted) },
confirmButton = {
TextButton(
onClick = {
photoPendingDelete = null
onDeletePhoto(photo)
},
) {
Text("Usuń", color = TppColors.Error, fontWeight = FontWeight.Bold)
}
},
dismissButton = {
TextButton(onClick = { photoPendingDelete = null }) {
Text("Anuluj", color = TppColors.Muted)
}
},
)
}
}
private sealed class PhotoGridItem {
data class Server(val photo: RoutePhotoDto) : PhotoGridItem()
data class Upload(val upload: PhotoUploadEntity) : PhotoGridItem()
private sealed class PhotoGridItem(open val sortEpochMillis: Long) {
data class Server(val photo: RoutePhotoDto) : PhotoGridItem(
routePhotoSortEpochMillis(photo.createdAt, photo.takenAt, fallback = 0L),
)
data class Upload(val upload: PhotoUploadEntity) : PhotoGridItem(upload.createdAtEpochMillis)
}
@Composable
@@ -1,9 +1,23 @@
package pl.firmatpp.kierowca.ui
import java.time.LocalDate
import java.time.OffsetDateTime
fun canManageRoutePhotos(selectedDate: String, today: LocalDate = LocalDate.now()): Boolean =
runCatching { LocalDate.parse(selectedDate).isEqual(today) }.getOrDefault(false)
fun inlinePhotoGridRows(photoCount: Int): Int =
if (photoCount <= 0) 0 else (photoCount + 1) / 2
fun visiblePhotoAttachmentCount(serverPhotoCount: Int, localUploadCount: Int): Int =
serverPhotoCount.coerceAtLeast(0) + localUploadCount.coerceAtLeast(0)
fun routePhotoSortEpochMillis(createdAt: String?, takenAt: String?, fallback: Long): Long =
parseIsoOffsetEpochMillis(createdAt)
?: parseIsoOffsetEpochMillis(takenAt)
?: fallback
private fun parseIsoOffsetEpochMillis(value: String?): Long? =
value?.takeIf { it.isNotBlank() }?.let {
runCatching { OffsetDateTime.parse(it).toInstant().toEpochMilli() }.getOrNull()
}
@@ -30,4 +30,34 @@ class DriverUiRulesTest {
assertEquals(2, inlinePhotoGridRows(3))
assertEquals(3, inlinePhotoGridRows(5))
}
@Test
fun countsServerPhotosAndLocalUploadsAsVisibleAttachments() {
assertEquals(0, visiblePhotoAttachmentCount(serverPhotoCount = 0, localUploadCount = 0))
assertEquals(1, visiblePhotoAttachmentCount(serverPhotoCount = 0, localUploadCount = 1))
assertEquals(3, visiblePhotoAttachmentCount(serverPhotoCount = 1, localUploadCount = 2))
}
@Test
fun usesCreatedAtBeforeTakenAtForNewestFirstPhotoSorting() {
val fallback = 100L
assertEquals(
1_782_892_800_000L,
routePhotoSortEpochMillis(
createdAt = "2026-07-01T10:00:00+02:00",
takenAt = "2026-07-01T08:00:00+02:00",
fallback = fallback,
),
)
assertEquals(
1_782_885_600_000L,
routePhotoSortEpochMillis(
createdAt = null,
takenAt = "2026-07-01T08:00:00+02:00",
fallback = fallback,
),
)
assertEquals(fallback, routePhotoSortEpochMillis(createdAt = null, takenAt = null, fallback = fallback))
}
}