feat: cancel button on active downloads
- ActiveDownload now carries workerId (UUID string) for cancellation - cancelDownload() calls WorkManager.cancelWorkById() - Downloads tab shows ✕ button on in-progress download cards
This commit is contained in:
@@ -23,6 +23,7 @@ import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
|
||||
data class DownloadProgress(
|
||||
val path: String,
|
||||
@@ -37,8 +38,9 @@ data class DownloadedFile(
|
||||
)
|
||||
|
||||
data class ActiveDownload(
|
||||
val workerId: String, // UUID string to cancel
|
||||
val filename: String,
|
||||
val progress: Int, // 0-100
|
||||
val progress: Int,
|
||||
val done: Boolean,
|
||||
)
|
||||
|
||||
@@ -140,19 +142,19 @@ class DashcamViewModel(application: Application) : AndroidViewModel(application)
|
||||
.build()
|
||||
|
||||
val wm = WorkManager.getInstance(getApplication())
|
||||
val uuid = request.id
|
||||
val workerId = uuid.toString()
|
||||
wm.enqueue(request)
|
||||
|
||||
// Observe progress
|
||||
val workerId = request.id
|
||||
_activeDownloads.value = _activeDownloads.value + (filename to ActiveDownload(filename, 0, false))
|
||||
_activeDownloads.value = _activeDownloads.value + (filename to ActiveDownload(workerId, filename, 0, false))
|
||||
|
||||
wm.getWorkInfoByIdLiveData(workerId).observeForever { info ->
|
||||
wm.getWorkInfoByIdLiveData(uuid).observeForever { info ->
|
||||
if (info == null) return@observeForever
|
||||
|
||||
val progress = info.progress.getInt("pct", 0)
|
||||
val done = info.state == WorkInfo.State.SUCCEEDED || info.state == WorkInfo.State.FAILED
|
||||
|
||||
_activeDownloads.value = _activeDownloads.value + (filename to ActiveDownload(filename, progress, done))
|
||||
_activeDownloads.value = _activeDownloads.value + (filename to ActiveDownload(workerId, filename, progress, done))
|
||||
|
||||
when (info.state) {
|
||||
WorkInfo.State.SUCCEEDED -> {
|
||||
@@ -169,7 +171,7 @@ class DashcamViewModel(application: Application) : AndroidViewModel(application)
|
||||
}
|
||||
_activeDownloads.value = _activeDownloads.value - filename
|
||||
}
|
||||
else -> {} // running / enqueued
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,6 +199,17 @@ class DashcamViewModel(application: Application) : AndroidViewModel(application)
|
||||
}
|
||||
}
|
||||
|
||||
fun cancelDownload(dl: ActiveDownload) {
|
||||
try {
|
||||
val uuid = java.util.UUID.fromString(dl.workerId)
|
||||
WorkManager.getInstance(getApplication()).cancelWorkById(uuid)
|
||||
_activeDownloads.value = _activeDownloads.value - dl.filename
|
||||
viewModelScope.launch {
|
||||
_downloadEvents.emit("✕ Cancelled: ${dl.filename}")
|
||||
}
|
||||
} catch (_: Exception) {}
|
||||
}
|
||||
|
||||
fun deleteVideo(video: VideoFile) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
|
||||
@@ -37,6 +37,7 @@ fun DownloadsScreen(
|
||||
files: List<DownloadedFile>,
|
||||
activeDownloads: Map<String, ActiveDownload>,
|
||||
onDelete: (DownloadedFile) -> Unit,
|
||||
onCancel: (ActiveDownload) -> Unit,
|
||||
onRefresh: () -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
@@ -80,11 +81,29 @@ fun DownloadsScreen(
|
||||
)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(12.dp)) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = if (dl.done) "✓ $filename" else "⏳ $filename",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
if (!dl.done) {
|
||||
Button(
|
||||
onClick = { onCancel(dl) },
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = MaterialTheme.colorScheme.error
|
||||
),
|
||||
modifier = Modifier.height(32.dp)
|
||||
) {
|
||||
Text("✕", style = MaterialTheme.typography.bodySmall)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!dl.done) {
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
LinearProgressIndicator(
|
||||
|
||||
@@ -105,9 +105,10 @@ fun YarisMainScreen(client: OkHttpClient) {
|
||||
onDelete = { dashcamVm.deleteVideo(it) },
|
||||
)
|
||||
1 -> DownloadsScreen(
|
||||
activeDownloads = activeDownloads,
|
||||
files = downloadedFiles,
|
||||
activeDownloads = activeDownloads,
|
||||
onDelete = { dashcamVm.deleteDownloaded(it) },
|
||||
onCancel = { dashcamVm.cancelDownload(it) },
|
||||
onRefresh = { dashcamVm.scanDownloads() },
|
||||
)
|
||||
2 -> DualNetworkTestScreen(
|
||||
|
||||
Reference in New Issue
Block a user