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 @@ + +