feat(downloads): WiFi-only network-type-aware download gating

Add a metered/cellular network detector so downloads honour a "WiFi
only" preference. Android reports network type via NetworkTypeMonitor;
Rust exposes it through download/network.rs and holds the queue pump when
on a metered connection, emitting a queue-wide waitingForNetwork event.
The frontend surfaces this via the networkType service and a
waitingForNetwork store flag.

TRACES: UR-053 | DR-074
This commit is contained in:
2026-07-23 20:02:07 +02:00
parent 8f8433eebe
commit e083b53ee8
13 changed files with 944 additions and 3 deletions
+20
View File
@@ -52,6 +52,7 @@ use commands::{
delete_album_downloads,
delete_all_downloads,
delete_download,
delete_downloads_under,
// Device commands
device_get_id,
device_set_id,
@@ -71,6 +72,7 @@ use commands::{
get_download_manager_stats,
get_download_storage_stats,
get_downloads,
get_downloads_allowed,
get_smart_cache_config,
get_smart_cache_stats,
image_get_url,
@@ -179,6 +181,9 @@ use commands::{
repository_get_audio_only_stream_url_for_video,
repository_get_audio_stream_url,
repository_get_channels,
repository_get_download_disk_usage,
repository_get_downloaded_items,
repository_get_downloaded_libraries,
repository_get_genres,
repository_get_image_url,
repository_get_item,
@@ -212,6 +217,7 @@ use commands::{
// Session polling commands
sessions_set_polling_hint,
set_max_concurrent_downloads,
set_network_state,
set_show_server_catalog,
start_download,
// Storage commands
@@ -770,6 +776,7 @@ fn specta_builder() -> Builder<tauri::Wry> {
delete_download,
delete_all_downloads,
delete_album_downloads,
delete_downloads_under,
clear_stale_downloads,
get_download_storage_stats,
mark_download_completed,
@@ -786,6 +793,9 @@ fn specta_builder() -> Builder<tauri::Wry> {
get_smart_cache_stats,
update_smart_cache_config,
get_smart_cache_config,
// WiFi-only download gate (UR-053)
set_network_state,
get_downloads_allowed,
get_album_recommendations,
get_album_affinity_status,
// Pinning commands
@@ -835,6 +845,9 @@ fn specta_builder() -> Builder<tauri::Wry> {
repository_get_libraries,
repository_get_items,
repository_get_item,
repository_get_downloaded_libraries,
repository_get_downloaded_items,
repository_get_download_disk_usage,
repository_jray_actors_at,
repository_get_latest_items,
repository_get_resume_items,
@@ -1196,6 +1209,13 @@ pub fn run() {
let download_manager_wrapper = DownloadManagerWrapper(Mutex::new(download_manager));
app.manage(download_manager_wrapper);
// Current network transport, for the WiFi-only download gate (UR-053).
// Defaults to unmetered ethernet so desktop is never gated; Android
// overwrites it via set_network_state as soon as the UI starts.
app.manage(commands::download::NetworkStateWrapper(
download::network::NetworkStateHandle::new(),
));
// Initialize connectivity monitor
info!("[INIT] Initializing connectivity monitor...");
let http_config = HttpConfig::default();