Android: write and read picked files through content URIs
On Android the file dialogs return content:// URIs, not paths. Exports wrote them with std::fs, which failed after the system had already created the document, leaving a 0 B file; deck, library-card and library backup exports now write through tauri-plugin-fs, and a failed deck export shows an error instead of failing silently. Library-file and card-database imports read the pick through the fs plugin too. A library file is told apart by its SQLite header rather than its extension, and SQLite opens a local copy. The library-import picker drops its filters on Android, where they hid .db and backup files. Deck import suggests the file's display name rather than the URI's opaque id, and the backup's "Saved to" message shows the file name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,11 +3,14 @@ package com.garrettmills.mtgc
|
||||
import android.app.Activity
|
||||
import android.content.ClipData
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import androidx.core.content.FileProvider
|
||||
import app.tauri.annotation.Command
|
||||
import app.tauri.annotation.InvokeArg
|
||||
import app.tauri.annotation.TauriPlugin
|
||||
import app.tauri.plugin.Invoke
|
||||
import app.tauri.plugin.JSObject
|
||||
import app.tauri.plugin.Plugin
|
||||
import java.io.File
|
||||
|
||||
@@ -18,9 +21,16 @@ class ShareImageArgs {
|
||||
var title: String? = null
|
||||
}
|
||||
|
||||
@InvokeArg
|
||||
class DisplayNameArgs {
|
||||
/** A content:// URI the system file picker returned. */
|
||||
lateinit var uri: String
|
||||
}
|
||||
|
||||
/**
|
||||
* The Android half of the app's `share` plugin (src-tauri/src/share.rs):
|
||||
* opens the system share sheet for a card image the Rust side has saved.
|
||||
* opens the system share sheet for a card image the Rust side has saved, and
|
||||
* looks up the names of documents the system file picker returns.
|
||||
*/
|
||||
@TauriPlugin
|
||||
class SharePlugin(private val activity: Activity) : Plugin(activity) {
|
||||
@@ -48,4 +58,18 @@ class SharePlugin(private val activity: Activity) : Plugin(activity) {
|
||||
invoke.reject(ex.message)
|
||||
}
|
||||
}
|
||||
|
||||
/** The file name the picker showed for `uri`, e.g. "Atraxa.txt". */
|
||||
@Command
|
||||
fun displayName(invoke: Invoke) {
|
||||
try {
|
||||
val args = invoke.parseArgs(DisplayNameArgs::class.java)
|
||||
val name = activity.contentResolver
|
||||
.query(Uri.parse(args.uri), arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null)
|
||||
?.use { if (it.moveToFirst()) it.getString(0) else null }
|
||||
invoke.resolve(JSObject().apply { put("name", name) })
|
||||
} catch (ex: Exception) {
|
||||
invoke.reject(ex.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user