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 okhttp3.OkHttpClient
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
data class DownloadProgress(
|
data class DownloadProgress(
|
||||||
val path: String,
|
val path: String,
|
||||||
@@ -37,8 +38,9 @@ data class DownloadedFile(
|
|||||||
)
|
)
|
||||||
|
|
||||||
data class ActiveDownload(
|
data class ActiveDownload(
|
||||||
|
val workerId: String, // UUID string to cancel
|
||||||
val filename: String,
|
val filename: String,
|
||||||
val progress: Int, // 0-100
|
val progress: Int,
|
||||||
val done: Boolean,
|
val done: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -140,19 +142,19 @@ class DashcamViewModel(application: Application) : AndroidViewModel(application)
|
|||||||
.build()
|
.build()
|
||||||
|
|
||||||
val wm = WorkManager.getInstance(getApplication())
|
val wm = WorkManager.getInstance(getApplication())
|
||||||
|
val uuid = request.id
|
||||||
|
val workerId = uuid.toString()
|
||||||
wm.enqueue(request)
|
wm.enqueue(request)
|
||||||
|
|
||||||
// Observe progress
|
_activeDownloads.value = _activeDownloads.value + (filename to ActiveDownload(workerId, filename, 0, false))
|
||||||
val workerId = request.id
|
|
||||||
_activeDownloads.value = _activeDownloads.value + (filename to ActiveDownload(filename, 0, false))
|
|
||||||
|
|
||||||
wm.getWorkInfoByIdLiveData(workerId).observeForever { info ->
|
wm.getWorkInfoByIdLiveData(uuid).observeForever { info ->
|
||||||
if (info == null) return@observeForever
|
if (info == null) return@observeForever
|
||||||
|
|
||||||
val progress = info.progress.getInt("pct", 0)
|
val progress = info.progress.getInt("pct", 0)
|
||||||
val done = info.state == WorkInfo.State.SUCCEEDED || info.state == WorkInfo.State.FAILED
|
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) {
|
when (info.state) {
|
||||||
WorkInfo.State.SUCCEEDED -> {
|
WorkInfo.State.SUCCEEDED -> {
|
||||||
@@ -169,7 +171,7 @@ class DashcamViewModel(application: Application) : AndroidViewModel(application)
|
|||||||
}
|
}
|
||||||
_activeDownloads.value = _activeDownloads.value - filename
|
_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) {
|
fun deleteVideo(video: VideoFile) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ fun DownloadsScreen(
|
|||||||
files: List<DownloadedFile>,
|
files: List<DownloadedFile>,
|
||||||
activeDownloads: Map<String, ActiveDownload>,
|
activeDownloads: Map<String, ActiveDownload>,
|
||||||
onDelete: (DownloadedFile) -> Unit,
|
onDelete: (DownloadedFile) -> Unit,
|
||||||
|
onCancel: (ActiveDownload) -> Unit,
|
||||||
onRefresh: () -> Unit,
|
onRefresh: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
@@ -80,11 +81,29 @@ fun DownloadsScreen(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
Column(modifier = Modifier.padding(12.dp)) {
|
Column(modifier = Modifier.padding(12.dp)) {
|
||||||
Text(
|
Row(
|
||||||
text = if (dl.done) "✓ $filename" else "⏳ $filename",
|
modifier = Modifier.fillMaxWidth(),
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
color = MaterialTheme.colorScheme.onSurface
|
verticalAlignment = Alignment.CenterVertically
|
||||||
)
|
) {
|
||||||
|
Text(
|
||||||
|
text = if (dl.done) "✓ $filename" else "⏳ $filename",
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
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) {
|
if (!dl.done) {
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
LinearProgressIndicator(
|
LinearProgressIndicator(
|
||||||
|
|||||||
@@ -105,9 +105,10 @@ fun YarisMainScreen(client: OkHttpClient) {
|
|||||||
onDelete = { dashcamVm.deleteVideo(it) },
|
onDelete = { dashcamVm.deleteVideo(it) },
|
||||||
)
|
)
|
||||||
1 -> DownloadsScreen(
|
1 -> DownloadsScreen(
|
||||||
activeDownloads = activeDownloads,
|
|
||||||
files = downloadedFiles,
|
files = downloadedFiles,
|
||||||
|
activeDownloads = activeDownloads,
|
||||||
onDelete = { dashcamVm.deleteDownloaded(it) },
|
onDelete = { dashcamVm.deleteDownloaded(it) },
|
||||||
|
onCancel = { dashcamVm.cancelDownload(it) },
|
||||||
onRefresh = { dashcamVm.scanDownloads() },
|
onRefresh = { dashcamVm.scanDownloads() },
|
||||||
)
|
)
|
||||||
2 -> DualNetworkTestScreen(
|
2 -> DualNetworkTestScreen(
|
||||||
|
|||||||
Reference in New Issue
Block a user