android: the handoff — the pending rounds, the pipeline, and what is unverified
Everything written this session that has not been through the device: rounds 43 to 48 (each patch adversarially verified, 43's transient-notice expectation fixed), a partial round 49, the pipeline scripts, the Android Auto design and the icon comparison mock. Also the two harness changes that were never A/B'd — adaptive waits, which may only shorten a declared wait and never lengthen it, and a ship that runs the mock walk and the deploy at the same time. The A/B and its 255-step baseline are in handoff/tools; main stays at what the phone has actually walked.
This commit is contained in:
1 parent
867fd42972
commit
9f0601027c
400 files changed
+26401
-3
No files matched your search
@@ -0,0 +1,110 @@
|
||||
//! The downloads notice on the phone.
|
||||
//!
|
||||
//! The Transfers screen only exists inside the app: the desktop says what a
|
||||
//! Save is doing with its title-bar ring, the phone with a badge on the nav,
|
||||
//! and neither is visible once the app is in the background — which is
|
||||
//! exactly when a Save is left to run on its own. So a running Save says so
|
||||
//! where the phone says things, in the shade: how many files are left, the
|
||||
//! one it is on, a progress bar, Stop all and Open.
|
||||
//!
|
||||
//! Its own channel, low importance, so it can be silenced without silencing
|
||||
//! the player's card. Its own foreground service (`TransferService`,
|
||||
//! `dataSync`) rather than the media one, because a download is not
|
||||
//! playback: `MediaService` stops itself the moment the bar empties, and a
|
||||
//! `mediaPlayback` service with no session is a policy violation. That
|
||||
//! service is also what keeps the process alive for a Save with nothing
|
||||
//! playing — the way the first real Save died, four tracks in.
|
||||
//!
|
||||
//! Two commands, both fed by the phone UI (src/mobile/xfernote.svelte.js):
|
||||
//! `update` with what is still in flight, `clear` when the queue empties.
|
||||
//! The notice's buttons arrive as the plugin event `action`
|
||||
//! (`addPluginListener("transfer-notice", "action", …)`): `cancel` stops
|
||||
//! everything still going, `open` brings the app forward on Transfers.
|
||||
//!
|
||||
//! On the desktop the plugin is registered too, so the permission set
|
||||
//! resolves on every platform, but its commands answer "not here".
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::{
|
||||
plugin::{Builder, TauriPlugin},
|
||||
Runtime,
|
||||
};
|
||||
|
||||
/// What the notice says: how many files are still in flight, the one it is
|
||||
/// on, and how far the burst has come. `indeterminate` is a queue whose
|
||||
/// sizes no peer has stated yet — a bar with no end to walk towards.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TransferNotice {
|
||||
#[serde(default)]
|
||||
pub count: u32,
|
||||
pub title: Option<String>,
|
||||
pub line: Option<String>,
|
||||
#[serde(default)]
|
||||
pub percent: i32,
|
||||
#[serde(default)]
|
||||
pub indeterminate: bool,
|
||||
}
|
||||
|
||||
#[cfg(mobile)]
|
||||
pub struct TransferNoticePlugin<R: Runtime>(tauri::plugin::PluginHandle<R>);
|
||||
|
||||
#[tauri::command]
|
||||
fn update<R: Runtime>(app: tauri::AppHandle<R>, state: TransferNotice) -> Result<(), String> {
|
||||
#[cfg(mobile)]
|
||||
{
|
||||
use tauri::Manager;
|
||||
let notice = app.state::<TransferNoticePlugin<R>>();
|
||||
notice
|
||||
.0
|
||||
.run_mobile_plugin::<serde_json::Value>("update", state)
|
||||
.map(|_| ())
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
#[cfg(not(mobile))]
|
||||
{
|
||||
let _ = (app, state);
|
||||
Err("the downloads notice is a phone feature".into())
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn clear<R: Runtime>(app: tauri::AppHandle<R>) -> Result<(), String> {
|
||||
#[cfg(mobile)]
|
||||
{
|
||||
use tauri::Manager;
|
||||
let notice = app.state::<TransferNoticePlugin<R>>();
|
||||
notice
|
||||
.0
|
||||
.run_mobile_plugin::<serde_json::Value>("clear", ())
|
||||
.map(|_| ())
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
#[cfg(not(mobile))]
|
||||
{
|
||||
let _ = app;
|
||||
Err("the downloads notice is a phone feature".into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
Builder::new("transfer-notice")
|
||||
.invoke_handler(tauri::generate_handler![update, clear])
|
||||
.setup(|app, api| {
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
use tauri::Manager;
|
||||
let handle = api.register_android_plugin(
|
||||
"com.soulstream.transfernotice",
|
||||
"TransferNoticePlugin",
|
||||
)?;
|
||||
app.manage(TransferNoticePlugin(handle));
|
||||
}
|
||||
#[cfg(not(target_os = "android"))]
|
||||
{
|
||||
let _ = (app, api);
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.build()
|
||||
}
|
||||
Reference in new issue
Block a user