From 92d4b23bedb936f909fde74c126520dec3ad67da Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sat, 26 Sep 2026 13:17:20 -0400 Subject: [PATCH] Give an album a folder on the tablet, through Android's folder picker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Android's only export destination was the library on the server (ExportTarget::available), because writing to the device goes through the Storage Access Framework and nothing did. An album's folder on the tablet is now chosen in the system's tree picker — which has its own "Create new folder" — and exports are written into it with DocumentsContract. The picker answers through onActivityResult, and the main activity is NativeActivity, whose result is not ours. FolderPicker is a translucent activity that only asks: it starts ACTION_OPEN_DOCUMENT_TREE, takes a persistable grant (a folder is chosen once and exported to for months), leaves the URI in a static, and finishes. Rust polls it from a Slint timer — one static call, rather than a registered native method and a thread to deliver on. Two things the first build on the tablet got wrong, recorded where they are fixed: - Our classes must be loaded through Context.getClassLoader(). The class of what ndk_context holds is a framework class from the boot loader, which reports every class in the APK as not found. - What ndk_context holds is the application context, not the activity, and starting an activity from it throws without FLAG_ACTIVITY_NEW_TASK. Saf.write creates the document (or, under Overwrite, reopens the one of that name with "wt" so a shorter file does not keep the old tail) and returns the name the provider actually gave it, since SAF renames on a collision by itself; the album records that name. A tree URI reads in the sidebar as its folder ("Pictures/Web"), not as a content:// string. --- .../android/AndroidManifest.xml | 12 + .../paris/tourolle/darkroom/FolderPicker.java | 117 ++++++++++ .../java/paris/tourolle/darkroom/Saf.java | 114 ++++++++++ ui/dr-ui/src/albums_ui.rs | 8 + ui/dr-ui/src/export.rs | 43 ++++ ui/dr-ui/src/lib.rs | 2 + ui/dr-ui/src/saf.rs | 206 ++++++++++++++++++ 7 files changed, 502 insertions(+) create mode 100644 apps/darkroom-android/android/java/paris/tourolle/darkroom/FolderPicker.java create mode 100644 apps/darkroom-android/android/java/paris/tourolle/darkroom/Saf.java create mode 100644 ui/dr-ui/src/saf.rs diff --git a/apps/darkroom-android/android/AndroidManifest.xml b/apps/darkroom-android/android/AndroidManifest.xml index be3a53b..6df6aba 100644 --- a/apps/darkroom-android/android/AndroidManifest.xml +++ b/apps/darkroom-android/android/AndroidManifest.xml @@ -158,6 +158,18 @@ android:theme="@style/ManualTheme" android:configChanges="orientation|keyboardHidden|screenSize|screenLayout|uiMode" /> + + +