From 204731408da7ccf216981265c84606a6d89c53a8 Mon Sep 17 00:00:00 2001 From: darken Date: Mon, 4 Mar 2024 15:00:22 +0100 Subject: [PATCH] Refactor reparser UI and logic into extra class --- .../eu/darken/pgc/importer/core/Reparser.kt | 22 +++++ .../darken/pgc/importer/core/UriImporter.kt | 74 +++++++++++++++ .../pgc/importer/ui/ImporterFragmentVM.kt | 91 ++++--------------- .../pgc/importer/ui/items/ManualCardVH.kt | 14 ++- 4 files changed, 124 insertions(+), 77 deletions(-) create mode 100644 app/src/main/java/eu/darken/pgc/importer/core/Reparser.kt create mode 100644 app/src/main/java/eu/darken/pgc/importer/core/UriImporter.kt diff --git a/app/src/main/java/eu/darken/pgc/importer/core/Reparser.kt b/app/src/main/java/eu/darken/pgc/importer/core/Reparser.kt new file mode 100644 index 0000000..9d0fedf --- /dev/null +++ b/app/src/main/java/eu/darken/pgc/importer/core/Reparser.kt @@ -0,0 +1,22 @@ +package eu.darken.pgc.importer.core + +import eu.darken.pgc.common.ca.CaString +import eu.darken.pgc.common.debug.logging.logTag +import javax.inject.Inject + +class Reparser @Inject constructor( + private val ingester: Ingester, +) { + + suspend fun reparse(onProgress: (Int, Int, CaString) -> Unit): Int { + var current = 0 + val max = ingester.flightCount() + return ingester.reingest { progress -> + onProgress(current++, max, progress) + } + } + + companion object { + internal val TAG = logTag("Importer", "Reparser") + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/darken/pgc/importer/core/UriImporter.kt b/app/src/main/java/eu/darken/pgc/importer/core/UriImporter.kt new file mode 100644 index 0000000..544f4ee --- /dev/null +++ b/app/src/main/java/eu/darken/pgc/importer/core/UriImporter.kt @@ -0,0 +1,74 @@ +package eu.darken.pgc.importer.core + +import android.content.ContentResolver +import android.net.Uri +import android.webkit.MimeTypeMap +import eu.darken.pgc.common.ca.CaString +import eu.darken.pgc.common.ca.toCaString +import eu.darken.pgc.common.debug.logging.log +import eu.darken.pgc.common.debug.logging.logTag +import okhttp3.internal.closeQuietly +import okio.source +import java.io.InputStream +import javax.inject.Inject + +class UriImporter @Inject constructor( + private val contentResolver: ContentResolver, + private val ingester: Ingester, +) { + + suspend fun import(uris: Collection, onProgress: (Int, Int, CaString) -> Unit): Result { + + val success = mutableListOf() + val skipped = mutableListOf() + val failed = mutableListOf>() + + val validUris = uris + .filter { MimeTypeMap.getFileExtensionFromUrl(it.path!!) == "igc" } + var current = 0 + validUris.forEach { uri -> + log(TAG) { "import(...): $uri" } + onProgress(current++, validUris.size, (uri.path ?: uri.toString()).toCaString()) + + val dangles = mutableSetOf() + + try { + val added = ingester.ingest( + IngestIGCPayload( + sourceProvider = { + contentResolver.openInputStream(uri)!!.also { dangles.add(it) }.source() + }, + originalSource = uri.toString(), + sourceType = when { + uri.authority?.contains("org.xcontest.XCTrack") == true -> IngestIGCPayload.SourceType.XCTRACK + else -> IngestIGCPayload.SourceType.UNKNOWN + }, + ) + ) + + if (added) success.add(uri) else skipped.add(uri) + } catch (e: Exception) { + failed.add(uri to e) + } finally { + dangles.forEach { it.closeQuietly() } + } + } + + (uris - (success + skipped).toSet()).forEach { + failed.add(it to IllegalArgumentException("Unknown data type")) + } + + return Result(success, skipped, failed) + } + + data class Result( + val success: List, + val skipped: List, + val failed: List>, + ) + + + companion object { + internal val TAG = logTag("Importer", "Uri") + } +} \ No newline at end of file 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 2089493..6b0c4aa 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 @@ -1,15 +1,11 @@ package eu.darken.pgc.importer.ui -import android.content.ContentResolver -import android.content.Context import android.content.Intent import android.hardware.usb.UsbDevice import android.hardware.usb.UsbManager import android.net.Uri -import android.webkit.MimeTypeMap import androidx.lifecycle.SavedStateHandle import dagger.hilt.android.lifecycle.HiltViewModel -import dagger.hilt.android.qualifiers.ApplicationContext import eu.darken.pgc.R import eu.darken.pgc.common.ca.toCaString import eu.darken.pgc.common.coroutine.DispatcherProvider @@ -18,8 +14,8 @@ import eu.darken.pgc.common.debug.logging.log import eu.darken.pgc.common.debug.logging.logTag import eu.darken.pgc.common.livedata.SingleLiveEvent import eu.darken.pgc.common.uix.ViewModel3 -import eu.darken.pgc.importer.core.IngestIGCPayload -import eu.darken.pgc.importer.core.Ingester +import eu.darken.pgc.importer.core.Reparser +import eu.darken.pgc.importer.core.UriImporter import eu.darken.pgc.importer.core.UsbDevicesProvider import eu.darken.pgc.importer.core.UsbImporter import eu.darken.pgc.importer.ui.items.ManualCardVH @@ -32,21 +28,17 @@ import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine -import okhttp3.internal.closeQuietly -import okio.source -import java.io.InputStream import javax.inject.Inject @HiltViewModel class ImporterFragmentVM @Inject constructor( handle: SavedStateHandle, dispatcherProvider: DispatcherProvider, - private val ingester: Ingester, - private val contentResolver: ContentResolver, - @ApplicationContext private val context: Context, private val usbManager: UsbManager, private val usbDevicesProvider: UsbDevicesProvider, private val usbImporter: UsbImporter, + private val uriImporter: UriImporter, + private val reparser: Reparser, ) : ViewModel3(dispatcherProvider = dispatcherProvider) { val events = SingleLiveEvent() @@ -96,18 +88,12 @@ class ImporterFragmentVM @Inject constructor( fun reparse() = launch { log(TAG) { "reparse()" } - reparserState.value = ReparserState.Progress( - max = ingester.flightCount(), - progressMsg = R.string.general_progress_loading.toCaString() - ) - - val changed = ingester.reingest { progress -> - reparserState.value = (reparserState.value as ReparserState.Progress).let { - it.copy( - progressMsg = progress, - current = it.current + 1 - ) - } + val changed = reparser.reparse { current, max, info -> + reparserState.value = ReparserState.Progress( + current = current, + max = max, + progressMsg = info + ) } reparserState.value = ReparserState.Result( @@ -123,57 +109,16 @@ class ImporterFragmentVM @Inject constructor( progressMsg = R.string.general_progress_loading.toCaString() ) - val success = mutableListOf() - val skipped = mutableListOf() - val failed = mutableListOf>() - - uris - .filter { MimeTypeMap.getFileExtensionFromUrl(it.path!!) == "igc" } - .forEach { uri -> - log(TAG) { "importManual(...): $uri" } - manualImportState.value = - (manualImportState.value as ManualImportState.Progress).copy( - progressMsg = (uri.lastPathSegment ?: uri.toString()).toCaString() - ) - - val dangles = mutableSetOf() - - try { - val added = ingester.ingest( - IngestIGCPayload( - sourceProvider = { - contentResolver.openInputStream(uri)!!.also { dangles.add(it) }.source() - }, - originalSource = uri.toString(), - sourceType = when { - uri.authority?.contains("org.xcontest.XCTrack") == true -> IngestIGCPayload.SourceType.XCTRACK - else -> IngestIGCPayload.SourceType.UNKNOWN - }, - ) - ) - - if (added) success.add(uri) else skipped.add(uri) - } catch (e: Exception) { - failed.add(uri to e) - } finally { - dangles.forEach { it.closeQuietly() } - } - - manualImportState.value = - (manualImportState.value as ManualImportState.Progress).let { - it.copy(current = it.current + 1) - } - } - - (uris - (success + skipped).toSet()).forEach { - failed.add(it to IllegalArgumentException("Unknown data type")) + val result = uriImporter.import(uris) { current, max, info -> + manualImportState.value = (manualImportState.value as ManualImportState.Progress).copy( + current = current, + max = max, + progressMsg = info + ) } - manualImportState.value = ManualImportState.Result( - success = success, - skipped = skipped, - failed = failed - ) + + manualImportState.value = ManualImportState.Result(result) }.also { manualImportJob = it } private var usbImportJob: Job? = null diff --git a/app/src/main/java/eu/darken/pgc/importer/ui/items/ManualCardVH.kt b/app/src/main/java/eu/darken/pgc/importer/ui/items/ManualCardVH.kt index 7b40cd6..2f0aa02 100644 --- a/app/src/main/java/eu/darken/pgc/importer/ui/items/ManualCardVH.kt +++ b/app/src/main/java/eu/darken/pgc/importer/ui/items/ManualCardVH.kt @@ -7,6 +7,7 @@ import eu.darken.pgc.R import eu.darken.pgc.common.ca.CaString import eu.darken.pgc.common.lists.binding import eu.darken.pgc.databinding.ImporterManualItemBinding +import eu.darken.pgc.importer.core.UriImporter import eu.darken.pgc.importer.ui.ImporterAdapter import kotlin.math.roundToInt @@ -89,10 +90,15 @@ class ManualCardVH(parent: ViewGroup) : ) : ManualImportState data class Result( - val success: List, - val skipped: List, - val failed: List>, - ) : ManualImportState + val result: UriImporter.Result + ) : ManualImportState { + val success: List + get() = result.success + val skipped: List + get() = result.skipped + val failed: List> + get() = result.failed + } } }