// Settings > Offline — two explicitly-titled groups (the Tauri tab hid // this boundary; the owner endorsed the split): // // - OFFLINE MODE — the app operating without Qobuz: tri-state status row // (online / no connection / induced) with an honest "Check now" // re-probe, the persisted Enable Offline Mode toggle (#279 stream-first // snapshot handled by the shared engine), and the network-folders // policy toggle (mounted only while induced is on, Tauri parity). // - OFFLINE CACHE — downloads: manager launch + open-folder / clear-all. // The Local-Library rows (show-in-library, repair) arrive with the // Local Library port. // // Same structure as the other settings panels (GroupHeader + SettingRow + // SecondaryButton). Toggle changes bubble through settings-bool; the // status row reads the live OfflineState global; the panel's init // re-seeds the toggle states from the engine store (OfflineModeActions). import { Theme } from "../foundation/semantic-colors.slint"; import { Palette } from "../foundation/palette.slint"; import { Typography } from "../foundation/typography.slint"; import { Radius } from "../foundation/radius.slint"; import { OfflineManagerActions, OfflineModeActions, OfflineState, SettingsState } from "../state.slint"; import { QbzToggle } from "../primitives/QbzToggle.slint"; import { SettingRow } from "SettingRow.slint"; component GroupHeader inherits Text { color: Theme.text-muted; font-size: 11px; letter-spacing: 1.5px; font-weight: Typography.semibold; } component Divider inherits Rectangle { height: 1px; background: Theme.border-subtle; } // Matches AudioSettings/AppearanceSettings' SecondaryButton. component SecondaryButton inherits Rectangle { in property label; in property danger: false; callback clicked(); width: 160px; height: 34px; border-radius: Radius.sm; border-width: 1px; border-color: root.danger ? #e0564f : Theme.border-subtle; background: ta.has-hover ? Theme.surface-hover : Theme.surface-elevated; Text { width: 100%; height: 100%; text: root.label; color: root.danger ? #e0564f : Theme.text-secondary; font-size: Typography.body; font-weight: Typography.medium; horizontal-alignment: center; vertical-alignment: center; } ta := TouchArea { mouse-cursor: pointer; clicked => { root.clicked(); } } } export component OfflineSettings inherits VerticalLayout { callback settings-bool(string, bool); spacing: 4px; // Re-seed the toggle states from the engine store on every mount of // this section (same lazy-load hook LocalLibrarySettings uses). init => { OfflineModeActions.load(); } GroupHeader { text: @tr("OFFLINE MODE"); } SettingRow { label: @tr("Status"); description: OfflineState.captive-portal ? @tr("Captive portal detected — sign in to the network to get online.") : ""; HorizontalLayout { spacing: 16px; VerticalLayout { alignment: center; // Tri-state: online green / real-offline amber / induced accent. Text { text: OfflineState.mode == 2 ? @tr("Offline mode enabled") : OfflineState.mode == 1 ? @tr("No connection") : @tr("Online"); color: OfflineState.mode == 2 ? Theme.accent : OfflineState.mode == 1 ? Palette.warning : #22c55e; font-size: Typography.body; font-weight: Typography.medium; } } SecondaryButton { label: SettingsState.offline-checking ? @tr("Checking...") : @tr("Check now"); clicked => { if (!SettingsState.offline-checking) { OfflineModeActions.check-now(); } } } } } SettingRow { label: @tr("Enable Offline Mode"); description: @tr("Manually switch to offline mode even with internet."); QbzToggle { checked: SettingsState.offline-mode-enabled; toggled(v) => { SettingsState.offline-mode-enabled = v; root.settings-bool("offline-mode-enabled", v); } } } // The network-folders policy only applies while induced offline is on, // so the row only mounts then (Tauri parity; ADR-010 conditional mount). if SettingsState.offline-mode-enabled: SettingRow { label: @tr("Show Network Folder Content"); description: @tr("Display content from network-mounted folders (NAS, Samba, etc.) while in offline mode."); QbzToggle { checked: SettingsState.offline-show-network-folders; toggled(v) => { SettingsState.offline-show-network-folders = v; root.settings-bool("offline-show-network-folders", v); } } } Rectangle { height: 12px; } Divider { } Rectangle { height: 12px; } GroupHeader { text: @tr("OFFLINE CACHE"); } SettingRow { label: @tr("Manage offline cache"); description: @tr("Browse and manage your downloaded tracks and albums."); SecondaryButton { label: @tr("Open manager"); clicked => { OfflineManagerActions.open(); } } } SettingRow { label: @tr("Cache folder"); description: @tr("Open the folder where offline tracks are stored on disk."); SecondaryButton { label: @tr("Open folder"); clicked => { OfflineManagerActions.open-folder(); } } } SettingRow { label: @tr("Clear offline cache"); description: @tr("Remove every downloaded track. This cannot be undone."); SecondaryButton { label: @tr("Clear all"); danger: true; clicked => { OfflineManagerActions.clear-all(); } } } }