Coverage Summary for Class: BackupPickerLauncher (com.georgeci.moneysurfer.feature.settings.backup)

Class Method, % Branch, % Line, % Instruction, %
BackupPickerLauncher 0% (0/1) 0% (0/1) 0% (0/1)
BackupPickerLauncher$DefaultImpls 0% (0/1) 0% (0/1) 0% (0/3)
Total 0% (0/2) 0% (0/2) 0% (0/4)


 package com.georgeci.moneysurfer.feature.settings.backup
 
 import androidx.compose.runtime.Composable
 import okio.BufferedSink
 import okio.BufferedSource
 
 /**
  * Hides the platform-specific file picker behind a Composable factory.
  *
  * Backed per platform by:
  *  - **Android**: `ActivityResultContracts.CreateDocument` / `OpenDocument`
  *    via `rememberLauncherForActivityResult`.
  *  - **JVM**: `java.awt.FileDialog`.
  *  - **iOS**: `UIDocumentPickerViewController`, staging through a temp file in
  *    both directions (see `BackupPickerLauncher.ios.kt`).
  *
  * Completion (or cancellation) calls [onSavePicked] / [onOpenPicked] with the
  * chosen sink/source, or `null` when the user cancelled.
  */
 @Composable
 expect fun rememberBackupPickerLauncher(
     format: BackupPickerFormat,
     onSavePicked: (BufferedSink?) -> Unit,
     onOpenPicked: (BufferedSource?) -> Unit,
 ): BackupPickerLauncher
 
 interface BackupPickerLauncher {
     fun launchSave(suggestedName: String)
     fun launchOpen()
 
     /**
      * Reports how the write into the last [launchSave] sink ended.
      *
      * **Every screen that calls [launchSave] must call this exactly once per
      * export**, as soon as it knows the outcome — on iOS the archive is staged
      * in a temp file and the "where do I put it" picker only appears from here.
      * Closing the sink cannot stand in for it: an aborted export closes its sink
      * too, and acting on that would offer the user a truncated archive.
      *
      * No-op on Android and JVM, where the picker already chose the destination
      * before a single byte was written.
      */
     fun onSaveCompleted(succeeded: Boolean) = Unit
 }
 
 /**
  * File format the picker is launched for. Android consumes the MIME types
  * directly (SAF document contracts) and iOS resolves them to uniform type
  * identifiers; JVM's `FileDialog` ignores them. `application/octet-stream`
  * stays in the open list because some providers report generic types for
  * perfectly valid files.
  */
 enum class BackupPickerFormat(
     val saveMimeType: String,
     val openMimeTypes: List<String>,
 ) {
     Zip(
         saveMimeType = "application/zip",
         openMimeTypes = listOf("application/zip", "application/octet-stream"),
     ),
     Csv(
         saveMimeType = "text/csv",
         openMimeTypes = listOf(
             "text/csv",
             "text/comma-separated-values",
             "text/plain",
             "application/octet-stream",
         ),
     ),
 }