diff --git a/app/src/main/java/eu/darken/pgc/common/uix/ViewModel2.kt b/app/src/main/java/eu/darken/pgc/common/uix/ViewModel2.kt
index 75a2794..de6ab5d 100644
--- a/app/src/main/java/eu/darken/pgc/common/uix/ViewModel2.kt
+++ b/app/src/main/java/eu/darken/pgc/common/uix/ViewModel2.kt
@@ -12,6 +12,7 @@ import eu.darken.pgc.common.flow.DynamicStateFlow
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.launch
@@ -54,11 +55,12 @@ abstract class ViewModel2(
scope: CoroutineScope = viewModelScope,
context: CoroutineContext = getVMContext(),
block: suspend CoroutineScope.() -> Unit
- ) {
- try {
+ ): Job? {
+ return try {
scope.launch(context = context, block = block)
} catch (e: CancellationException) {
log(TAG, WARN) { "launch()ed coroutine was canceled (scope=$scope): ${e.asLog()}" }
+ null
}
}
diff --git a/app/src/main/java/eu/darken/pgc/importer/ui/ImporterFragment.kt b/app/src/main/java/eu/darken/pgc/importer/ui/ImporterFragment.kt
index bce89a4..2dc9a98 100644
--- a/app/src/main/java/eu/darken/pgc/importer/ui/ImporterFragment.kt
+++ b/app/src/main/java/eu/darken/pgc/importer/ui/ImporterFragment.kt
@@ -185,7 +185,7 @@ class ImporterFragment : Fragment3(R.layout.importer_fragment) {
usbImportAction.isEnabled = selectedUsbDevice != null
}
}
-
+ usbCancelAction.isVisible = false
usbImportAction.setOnClickListener { vm.importUsb(selectedUsbDevice!!) }
}
@@ -203,6 +203,10 @@ class ImporterFragment : Fragment3(R.layout.importer_fragment) {
"${((usb.current.toDouble() / usb.max.toDouble()) * 100).roundToInt()}%"
usbImportAction.isVisible = false
usbImportDeviceGroup.isVisible = false
+ usbCancelAction.apply {
+ isVisible = true
+ setOnClickListener { vm.cancelImportUsb() }
+ }
}
is ImporterFragmentVM.UsbImportstate.Result -> {
@@ -221,6 +225,7 @@ class ImporterFragment : Fragment3(R.layout.importer_fragment) {
isVisible = true
setOnClickListener { vm.importUsb(null) }
}
+ usbCancelAction.isVisible = false
usbImportDeviceGroup.isVisible = false
}
}
diff --git a/app/src/main/java/eu/darken/pgc/importer/ui/ImporterFragmentVM.kt b/app/src/main/java/eu/darken/pgc/importer/ui/ImporterFragmentVM.kt
index 2581b76..31afe5b 100644
--- a/app/src/main/java/eu/darken/pgc/importer/ui/ImporterFragmentVM.kt
+++ b/app/src/main/java/eu/darken/pgc/importer/ui/ImporterFragmentVM.kt
@@ -23,10 +23,13 @@ import eu.darken.pgc.importer.core.IngestIGCPayload
import eu.darken.pgc.importer.core.Ingester
import eu.darken.pgc.importer.core.MassStorageCrawler
import eu.darken.pgc.importer.core.UsbDevicesProvider
+import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.toList
+import kotlinx.coroutines.isActive
import me.jahnen.libaums.core.fs.UsbFile
import me.jahnen.libaums.core.fs.UsbFileInputStream
import okhttp3.internal.closeQuietly
@@ -157,6 +160,7 @@ class ImporterFragmentVM @Inject constructor(
)
}
+ private var usbImportJob: Job? = null
fun importUsb(device: UsbDevice?) = launch {
log(TAG) { "importUsb($device)" }
if (device == null) {
@@ -189,6 +193,10 @@ class ImporterFragmentVM @Inject constructor(
)
igcFiles.forEach { file ->
+ if (!isActive) {
+ usbImportState.value = UsbImportstate.Start()
+ throw CancellationException()
+ }
log(TAG) { "importUsb(...): Ingesting $file" }
usbImportState.value = (usbImportState.value as UsbImportstate.Progress).copy(
progressMsg = file.absolutePath.toCaString()
@@ -227,6 +235,10 @@ class ImporterFragmentVM @Inject constructor(
skipped = skipped,
failed = failed
)
+ }.also { usbImportJob = it }
+
+ fun cancelImportUsb() {
+ usbImportJob?.cancel()
}
data class ImporterState(
diff --git a/app/src/main/res/layout/importer_fragment.xml b/app/src/main/res/layout/importer_fragment.xml
index ed02b08..f5bc82b 100644
--- a/app/src/main/res/layout/importer_fragment.xml
+++ b/app/src/main/res/layout/importer_fragment.xml
@@ -279,9 +279,8 @@
android:id="@+id/usb_import_device_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginVertical="16dp"
+ android:layout_marginTop="16dp"
android:orientation="vertical"
- app:layout_constraintBottom_toTopOf="@id/usb_import_action"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/usb_import_secondary">
@@ -293,10 +292,27 @@
+
+