Add photo upload retry controls

This commit is contained in:
admin
2026-07-01 22:39:47 +02:00
parent ee9d8cdbaf
commit fa98451533
4 changed files with 54 additions and 15 deletions
+5 -2
View File
@@ -33,8 +33,8 @@ android {
applicationId = "pl.firmatpp.kierowca"
minSdk = 26
targetSdk = 35
versionCode = 26
versionName = "1.0.25"
versionCode = 28
versionName = "1.0.27"
setProperty("archivesBaseName", "pl.firmatpp.kierowca")
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@@ -68,6 +68,9 @@ android {
release {
signingConfig = signingConfigs.getByName("release")
isMinifyEnabled = false
ndk {
debugSymbolLevel = "SYMBOL_TABLE"
}
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
@@ -61,6 +61,7 @@ import androidx.compose.material.icons.outlined.LocalShipping
import androidx.compose.material.icons.outlined.Navigation
import androidx.compose.material.icons.outlined.Person
import androidx.compose.material.icons.outlined.Phone
import androidx.compose.material.icons.outlined.Refresh
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.pullrefresh.PullRefreshIndicator
import androidx.compose.material.pullrefresh.pullRefresh
@@ -645,9 +646,21 @@ private fun PhotoQueueItem(upload: PhotoUploadEntity, onRetryUpload: (PhotoUploa
)
}
}
if (status == PhotoUploadStatus.FailedRetryable) {
TextButton(onClick = { onRetryUpload(upload) }) {
Text("Ponów", color = TppColors.Forest, fontWeight = FontWeight.Bold)
if (canRetryPhotoUpload(upload.status)) {
Button(
onClick = { onRetryUpload(upload) },
colors = ButtonDefaults.buttonColors(containerColor = TppColors.Forest),
shape = RoundedCornerShape(4.dp),
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 8.dp),
) {
Icon(
Icons.Outlined.Refresh,
contentDescription = null,
tint = Color.White,
modifier = Modifier.size(18.dp),
)
Spacer(Modifier.width(6.dp))
Text("Ponów", color = Color.White, fontWeight = FontWeight.Bold)
}
}
}
@@ -1573,6 +1586,25 @@ private fun PendingPhotoTile(
)
}
}
if (canRetryPhotoUpload(upload.status)) {
IconButton(
onClick = { onRetry(upload) },
enabled = !isDeleting,
modifier = Modifier
.align(Alignment.TopEnd)
.padding(8.dp)
.size(40.dp)
.background(TppColors.Surface.copy(alpha = 0.96f), RoundedCornerShape(20.dp))
.border(1.dp, TppColors.Forest.copy(alpha = 0.35f), RoundedCornerShape(20.dp)),
) {
Icon(
Icons.Outlined.Refresh,
contentDescription = "Ponów wysłanie zdjęcia",
tint = TppColors.Forest,
modifier = Modifier.size(20.dp),
)
}
}
Column(
Modifier.align(Alignment.BottomStart).fillMaxWidth().background(Color.White.copy(alpha = 0.94f)).padding(10.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
@@ -1592,16 +1624,6 @@ private fun PendingPhotoTile(
trackColor = TppColors.Outline.copy(alpha = 0.4f),
)
}
if (status == PhotoUploadStatus.FailedRetryable) {
Button(
onClick = { onRetry(upload) },
modifier = Modifier.fillMaxWidth().height(40.dp),
colors = ButtonDefaults.buttonColors(containerColor = TppColors.Forest),
shape = RoundedCornerShape(4.dp),
) {
Text("Ponów", color = Color.White, fontWeight = FontWeight.Bold)
}
}
}
}
}
@@ -35,6 +35,9 @@ fun routePhotoSortEpochMillis(createdAt: String?, takenAt: String?, fallback: Lo
fun confirmedUploadServerPhotoId(status: String, serverPhotoId: String?): String? =
serverPhotoId?.takeIf { status == "CONFIRMED" && it.isNotBlank() }
fun canRetryPhotoUpload(status: String): Boolean =
status == "FAILED_RETRYABLE"
fun localUploadPreviewPhoto(upload: PhotoUploadEntity): RoutePhotoDto? {
if (upload.localPath.isBlank()) return null
@@ -100,6 +100,17 @@ class DriverUiRulesTest {
assertEquals(null, confirmedUploadServerPhotoId("FAILED_RETRYABLE", "42"))
}
@Test
fun allowsRetryActionOnlyForRetryableFailedUploads() {
assertTrue(canRetryPhotoUpload("FAILED_RETRYABLE"))
assertFalse(canRetryPhotoUpload("PENDING"))
assertFalse(canRetryPhotoUpload("UPLOADING"))
assertFalse(canRetryPhotoUpload("VERIFYING"))
assertFalse(canRetryPhotoUpload("CONFIRMED"))
assertFalse(canRetryPhotoUpload("FAILED_PERMANENT"))
assertFalse(canRetryPhotoUpload("CANCELLED"))
}
@Test
fun createsFullScreenPreviewForLocalUploadBeforeRouteRefresh() {
val photo = localUploadPreviewPhoto(upload(status = "CONFIRMED", serverPhotoId = "55"))