diff --git a/android/app/src/main/java/com/yarisobd/app/DashcamViewModel.kt b/android/app/src/main/java/com/yarisobd/app/DashcamViewModel.kt index 6c2409e..fb8f9d0 100644 --- a/android/app/src/main/java/com/yarisobd/app/DashcamViewModel.kt +++ b/android/app/src/main/java/com/yarisobd/app/DashcamViewModel.kt @@ -45,6 +45,7 @@ data class ActiveDownload( val filename: String, val progress: Int, val done: Boolean, + val status: String? = null, ) class DashcamViewModel(application: Application) : AndroidViewModel(application) { @@ -317,9 +318,10 @@ class DashcamViewModel(application: Application) : AndroidViewModel(application) wm.getWorkInfoByIdLiveData(uuid).observeForever { info -> if (info == null) return@observeForever val progress = info.progress.getInt("pct", 0) + val status = info.progress.getString("status") val done = info.state == WorkInfo.State.SUCCEEDED || info.state == WorkInfo.State.FAILED - _uploadProgress.value = _uploadProgress.value + (file.name to ActiveDownload(workerId, file.name, progress, done)) + _uploadProgress.value = _uploadProgress.value + (file.name to ActiveDownload(workerId, file.name, progress, done, status)) when (info.state) { WorkInfo.State.SUCCEEDED -> { diff --git a/android/app/src/main/java/com/yarisobd/app/DownloadsScreen.kt b/android/app/src/main/java/com/yarisobd/app/DownloadsScreen.kt index 425f3c7..45f5e38 100644 --- a/android/app/src/main/java/com/yarisobd/app/DownloadsScreen.kt +++ b/android/app/src/main/java/com/yarisobd/app/DownloadsScreen.kt @@ -107,7 +107,7 @@ fun DownloadsScreen( Spacer(Modifier.width(10.dp)) Column { Text("↑ $filename", style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.Medium, maxLines = 1, overflow = TextOverflow.Ellipsis) - Text("${dl.progress}%", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) + Text(uploadLabel(dl), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) } } } @@ -245,6 +245,12 @@ fun DownloadsScreen( } } +private fun uploadLabel(dl: ActiveDownload): String { + val pct = "${dl.progress}%" + val status = dl.status ?: return pct + return if (dl.progress > 0) "$status · $pct" else status +} + private fun formatSize(bytes: Long): String = when { bytes >= 1_000_000_000 -> "%.1f GB".format(bytes / 1_000_000_000.0) bytes >= 1_000_000 -> "%.1f MB".format(bytes / 1_000_000.0) diff --git a/android/app/src/main/java/com/yarisobd/app/UploadWorker.kt b/android/app/src/main/java/com/yarisobd/app/UploadWorker.kt index 6c8caf7..c80f22c 100644 --- a/android/app/src/main/java/com/yarisobd/app/UploadWorker.kt +++ b/android/app/src/main/java/com/yarisobd/app/UploadWorker.kt @@ -53,11 +53,16 @@ class UploadWorker( if (!file.exists()) return@withContext Result.failure(workDataOf("error" to "File not found")) try { + // Promote to foreground immediately so large files aren't killed during hashing + setForeground(DownloadWorker.createForegroundNotification(applicationContext, "Preparing $filename", 0)) + setProgressAsync(workDataOf("pct" to 0, "status" to "Hashing…")) + // Compute SHA256 val sha256 = computeSha256(file) val relativePath = filename // Using filename as relative_path since flat dir // Check status + setProgressAsync(workDataOf("pct" to 0, "status" to "Checking server…")) val statusUrl = "$serverUrl/api/v1/dashcam/upload/status?relative_path=$relativePath&sha256=$sha256" val statusReq = Request.Builder().url(statusUrl) .addHeader("X-Device-Name", deviceName) @@ -77,6 +82,7 @@ class UploadWorker( val totalChunks = ((file.length() + CHUNK_SIZE - 1) / CHUNK_SIZE).toInt() setForeground(DownloadWorker.createForegroundNotification(applicationContext, "Uploading $filename", 0)) + setProgressAsync(workDataOf("pct" to 0, "status" to "Uploading…")) // Upload missing chunks for (i in 0 until totalChunks) { @@ -114,7 +120,7 @@ class UploadWorker( val pct = ((i + 1) * 100) / totalChunks setForeground(DownloadWorker.createForegroundNotification(applicationContext, "Uploading $filename", pct)) - setProgressAsync(workDataOf("pct" to pct)) + setProgressAsync(workDataOf("pct" to pct, "status" to "Uploading…")) } return@withContext Result.success(workDataOf("filename" to filename))