feat(snap): add snap sandbox detection and welcome modal wiring

Detect when QBZ runs inside a Snap sandbox (via SNAP env var) and show
a one-time welcome modal with required plug connection commands. Adds a
Snap Sandbox section in Settings with copyable commands, mirroring the
existing Flatpak pattern.

Backend: snap.rs module, DB table snap_welcome_shown, V2 commands.
Frontend: updatesService, +page.svelte modal queue, SettingsView section.
This commit is contained in:
vicrodh committed 2026-03-02 11:10:50 -06:00
1 parent 8529477778
commit 00675de6b8
11 files changed
+182 -15

No files matched your search

+12
View File
@@ -10449,6 +10449,18 @@ pub fn v2_is_running_in_flatpak() -> bool {
crate::flatpak::is_running_in_flatpak()
}
#[tauri::command]
pub fn v2_is_running_in_snap() -> bool {
crate::snap::is_running_in_snap()
}
#[tauri::command]
pub fn v2_mark_snap_welcome_shown(
state: State<'_, crate::updates::UpdatesState>,
) -> Result<(), String> {
crate::updates::mark_snap_welcome_shown(state)
}
#[tauri::command]
pub async fn v2_detect_legacy_cached_files(
cache_state: State<'_, OfflineCacheState>,
+4
View File
@@ -26,6 +26,7 @@ pub mod config;
pub mod credentials;
pub mod discogs;
pub mod flatpak;
pub mod snap;
pub mod lastfm;
pub mod library;
pub mod listenbrainz;
@@ -1183,6 +1184,7 @@ pub fn run() {
flatpak::get_flatpak_help_text,
config::legal_settings::get_qobuz_tos_accepted,
updates::has_flatpak_welcome_been_shown,
updates::has_snap_welcome_been_shown,
lyrics::commands::lyrics_get,
config::favorites_cache::is_track_favorite,
commands_v2::v2_set_api_locale,
@@ -1356,6 +1358,8 @@ pub fn run() {
commands_v2::v2_remote_control_regenerate_token,
commands_v2::v2_remote_control_get_pairing_qr,
commands_v2::v2_is_running_in_flatpak,
commands_v2::v2_is_running_in_snap,
commands_v2::v2_mark_snap_welcome_shown,
commands_v2::v2_detect_legacy_cached_files,
commands_v2::v2_reco_log_event,
commands_v2::v2_reco_train_scores,
+16
View File
@@ -0,0 +1,16 @@
//! Snap runtime detection and utilities
//!
//! Detects when QBZ is running inside a Snap sandbox
//! and provides sandbox-specific guidance.
use std::env;
/// Check if QBZ is running inside a Snap sandbox
pub fn is_snap() -> bool {
env::var("SNAP").is_ok()
}
#[tauri::command]
pub fn is_running_in_snap() -> bool {
is_snap()
}
+35
View File
@@ -143,6 +143,11 @@ impl UpdatesStore {
CREATE TABLE IF NOT EXISTS flatpak_welcome_shown (
id INTEGER PRIMARY KEY CHECK (id = 1),
shown_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS snap_welcome_shown (
id INTEGER PRIMARY KEY CHECK (id = 1),
shown_at INTEGER NOT NULL
);",
)
.map_err(|e| format!("Failed to create updates tables: {}", e))?;
@@ -273,6 +278,26 @@ impl UpdatesStore {
.map_err(|e| format!("Failed to mark flatpak_welcome_shown: {}", e))?;
Ok(())
}
pub fn has_snap_welcome_been_shown(&self) -> bool {
self.conn
.query_row(
"SELECT 1 FROM snap_welcome_shown WHERE id = 1 LIMIT 1",
[],
|_row| Ok(()),
)
.is_ok()
}
pub fn mark_snap_welcome_shown(&self) -> Result<(), String> {
self.conn
.execute(
"INSERT OR REPLACE INTO snap_welcome_shown (id, shown_at) VALUES (1, ?1)",
params![now_epoch_seconds()],
)
.map_err(|e| format!("Failed to mark snap_welcome_shown: {}", e))?;
Ok(())
}
}
/// Thread-safe state wrapper
@@ -543,6 +568,16 @@ pub fn mark_flatpak_welcome_shown(state: tauri::State<UpdatesState>) -> Result<(
state.with_store(|store| store.mark_flatpak_welcome_shown())?
}
#[tauri::command]
pub fn has_snap_welcome_been_shown(state: tauri::State<UpdatesState>) -> Result<bool, String> {
state.with_store(|store| store.has_snap_welcome_been_shown())
}
#[tauri::command]
pub fn mark_snap_welcome_shown(state: tauri::State<UpdatesState>) -> Result<(), String> {
state.with_store(|store| store.mark_snap_welcome_shown())?
}
#[tauri::command]
pub fn get_current_version(state: tauri::State<UpdatesState>) -> String {
state.current_version()