Loading a GPX on Android failed for every file in the picker. The dialog
plugin fires ACTION_GET_CONTENT, which returns a `content://` URI, and
`load_profile_from_path` handed that straight to `std::fs::read_to_string`
— "no such file or directory" for a file the rider is looking at. Picking
from Nextcloud makes it plainer: a document provider backed by a server
may have no local file at all until the resolver opens the stream, so
there was never a path to find.
So the command now takes a `FilePath` and reads through tauri-plugin-fs,
which opens a path directly and a URI via the resolver. The plugin is
here for `FsExt` alone; nothing in ui/ calls its commands, so the
capabilities are unchanged.
Two things that were derived from the filename can no longer be:
- GPX is detected by content. A document id need not contain a name,
let alone an extension. No YAML profile begins with `<`.
- The route name falls back to the GPX's own <name>. Providers over
real storage encode the filename in the last segment, but an opaque
row id would have made a wretched route name.
save_fit had the same bug on the export side — PathBuf::from on a
save-dialog URI — and now writes down a resolver descriptor when handed
one.
Note for anyone rebuilding locally: gen/android/tauri.settings.gradle is
autogenerated and lists each plugin's Android project, so the new
plugin's Kotlin only reaches the APK after `cargo tauri android init` and
scripts/sync-android-sources.sh. CI already runs both.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
66 lines
2.4 KiB
TOML
66 lines
2.4 KiB
TOML
[package]
|
|
name = "bikecontrol-app"
|
|
version.workspace = true
|
|
edition.workspace = true
|
|
license.workspace = true
|
|
repository.workspace = true
|
|
description = "BikeControl desktop shell: Tauri commands and the event bridge to the UI"
|
|
|
|
[lib]
|
|
# Tauri v2 convention: the app lives in a lib so the same code can be reused by
|
|
# the Android/iOS entry points later (G-4).
|
|
name = "bikecontrol_app_lib"
|
|
crate-type = ["staticlib", "cdylib", "rlib"]
|
|
|
|
[build-dependencies]
|
|
tauri-build = { version = "2", features = [] }
|
|
|
|
[dependencies]
|
|
bikecontrol-core = { workspace = true }
|
|
bikecontrol-ble = { workspace = true }
|
|
bikecontrol-fit = { workspace = true }
|
|
|
|
tauri = { version = "2", features = [] }
|
|
tauri-plugin-dialog = "2"
|
|
# Not for the frontend — nothing in `ui/` calls the fs commands. This is here
|
|
# for `FsExt::read_to_string`, the one API that can read what the *picker*
|
|
# returns on Android: a `content://` URI rather than a path. See
|
|
# `read_picked_file` in commands.rs.
|
|
tauri-plugin-fs = "2"
|
|
|
|
uuid = { workspace = true }
|
|
chrono = { workspace = true }
|
|
serde = { workspace = true }
|
|
serde_json = { workspace = true }
|
|
serde_yaml_ng = { workspace = true }
|
|
roxmltree = { workspace = true }
|
|
tokio = { workspace = true }
|
|
anyhow = { workspace = true }
|
|
thiserror = { workspace = true }
|
|
tracing = { workspace = true }
|
|
tracing-subscriber = { workspace = true }
|
|
|
|
# Desktop-only: the crate is a `compile_error!` on anything that is not
|
|
# Windows/Linux/macOS, and the mobile entry points (G-4) have their own
|
|
# platform APIs for this. `wakelock.rs` degrades to a no-op there. On Android
|
|
# the equivalent is FLAG_KEEP_SCREEN_ON, set in MainActivity.kt.
|
|
[target.'cfg(any(windows, target_os = "linux", target_os = "macos"))'.dependencies]
|
|
keepawake = "0.6.0"
|
|
|
|
# Android-only (G-4). `src/android.rs` is the whole JNI surface: btleplug's Java
|
|
# backend has to be initialised from a Java thread, and `tracing` has to be
|
|
# pointed at logcat.
|
|
#
|
|
# `jni` is pinned to 0.19 because that is what btleplug 0.11 uses, and
|
|
# `platform::init` takes a `&JNIEnv` from *that* version — a 0.21 JNIEnv is a
|
|
# different type and would not compile.
|
|
[target.'cfg(target_os = "android")'.dependencies]
|
|
btleplug = { workspace = true }
|
|
jni = "0.19"
|
|
libc = "0.2"
|
|
# Pinned to the version btleplug 0.11 resolves to, and it must stay that way:
|
|
# the class cache `init` populates is a static *inside this crate*, so a second
|
|
# copy at a different version would be a second, empty cache and `connect`
|
|
# would go back to panicking.
|
|
jni-utils = "0.1.1"
|