refactor(v2): inline offline status, settings, and pending playlist delegates

Inlines bodies of get_offline_status, get_offline_settings,
set_manual_offline, check_network, and get_pending_playlists from
offline::commands directly into the v2 wrappers in commands_v2/library.rs.

Deletes the entire offline::commands submodule (the inlined commands and
the additional dead Tauri command shims that lived alongside them — none
were registered with Tauri or referenced outside the submodule). Prunes
the now-unused tauri AppHandle/Emitter imports from offline/mod.rs.

Step 8 of legacy cleanup, group H.

cc
This commit is contained in:
vicrodh committed 2026-04-26 20:30:38 -06:00
1 parent d98d35796e
commit c647cd0373
2 files changed
+153 -372

No files matched your search

+153 -5
View File
@@ -1296,14 +1296,56 @@ pub fn v2_set_show_network_folders_in_manual_offline(
pub async fn v2_get_offline_status(
state: State<'_, OfflineState>,
) -> Result<crate::offline::OfflineStatus, String> {
crate::offline::commands::get_offline_status(state).await
let settings = {
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
store.get_settings()?
};
// If manual offline mode is enabled, return immediately
if settings.manual_offline_mode {
return Ok(crate::offline::OfflineStatus {
is_offline: true,
reason: Some(crate::offline::OfflineReason::ManualOverride),
manual_mode_enabled: true,
});
}
// Check network connectivity
let has_network = crate::offline::check_network_connectivity().await;
if !has_network {
return Ok(crate::offline::OfflineStatus {
is_offline: true,
reason: Some(crate::offline::OfflineReason::NoNetwork),
manual_mode_enabled: false,
});
}
Ok(crate::offline::OfflineStatus {
is_offline: false,
reason: None,
manual_mode_enabled: false,
})
}
#[tauri::command]
pub fn v2_get_offline_settings(
state: State<'_, OfflineState>,
) -> Result<crate::offline::OfflineSettings, String> {
crate::offline::commands::get_offline_settings(state)
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
store.get_settings()
}
#[tauri::command]
@@ -1313,12 +1355,111 @@ pub async fn v2_set_manual_offline(
audio_state: State<'_, crate::config::audio_settings::AudioSettingsState>,
app_handle: tauri::AppHandle,
) -> Result<crate::offline::OfflineStatus, String> {
crate::offline::commands::set_manual_offline(enabled, state, audio_state, app_handle).await
use tauri::Emitter;
// 1) Persist the manual offline flag first so any concurrent reads
// see the new mode immediately.
let (was_offline, stream_first_before): (bool, Option<bool>) = {
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
let prev = store
.get_settings()
.map(|s| s.manual_offline_mode)
.unwrap_or(false);
let snapshot = store
.get_pre_offline_stream_first_track()
.unwrap_or(None);
store.set_manual_offline_mode(enabled)?;
(prev, snapshot)
};
// 2) Coordinate the stream_first_track snapshot/restore. This is best-
// effort — if the audio store isn't initialized yet (pre-login), we
// just skip; the offline flag itself has been persisted.
if enabled && !was_offline {
// Entering offline mode: stash current value and force to false.
let current = {
let guard = audio_state
.store
.lock()
.map_err(|e| format!("Audio settings lock error: {}", e))?;
guard
.as_ref()
.and_then(|s| s.get_settings().ok())
.map(|s| s.stream_first_track)
};
if let Some(current_value) = current {
{
let guard = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
if let Some(store) = guard.as_ref() {
let _ = store.set_pre_offline_stream_first_track(Some(current_value));
}
}
if current_value {
let guard = audio_state
.store
.lock()
.map_err(|e| format!("Audio settings lock error: {}", e))?;
if let Some(store) = guard.as_ref() {
let _ = store.set_stream_first_track(false);
log::info!(
"[Offline] stream_first_track snapshot={}; forced to false while offline",
current_value
);
}
}
}
} else if !enabled && was_offline {
// Exiting offline mode: restore snapshot if we have one.
if let Some(snapshot_value) = stream_first_before {
{
let guard = audio_state
.store
.lock()
.map_err(|e| format!("Audio settings lock error: {}", e))?;
if let Some(store) = guard.as_ref() {
let _ = store.set_stream_first_track(snapshot_value);
log::info!(
"[Offline] restored stream_first_track to {}",
snapshot_value
);
}
}
{
let guard = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
if let Some(store) = guard.as_ref() {
let _ = store.set_pre_offline_stream_first_track(None);
}
}
}
}
// 3) Get updated status
let status = v2_get_offline_status(state).await?;
// 4) Emit events. offline-status-changed for the offline store;
// audio-settings-changed so the SettingsView reloads its local
// state of stream_first_track (we may have just mutated it).
let _ = app_handle.emit("offline-status-changed", &status);
let _ = app_handle.emit("audio-settings-changed", ());
Ok(status)
}
#[tauri::command]
pub async fn v2_check_network() -> bool {
crate::offline::commands::check_network().await
crate::offline::check_network_connectivity().await
}
#[tauri::command]
@@ -1391,7 +1532,14 @@ pub fn v2_mark_scrobbles_sent(ids: Vec<i64>, state: State<'_, OfflineState>) ->
pub fn v2_get_pending_playlists(
state: State<'_, OfflineState>,
) -> Result<Vec<crate::offline::PendingPlaylist>, String> {
crate::offline::commands::get_pending_playlists(state)
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
store.get_pending_playlists()
}
#[tauri::command]
-367
View File
@@ -11,7 +11,6 @@ use rusqlite::{params, Connection};
use serde::{Deserialize, Serialize};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use tauri::{AppHandle, Emitter};
/// Reason why the app is in offline mode
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
@@ -670,369 +669,3 @@ pub async fn check_network_connectivity() -> bool {
log::info!("Network connectivity check failed after all attempts");
false
}
// Tauri commands
pub mod commands {
use super::*;
use tauri::State;
/// Get current offline status
/// Note: Login state is not checked here because the frontend already handles
/// showing LoginView when not logged in. This prevents race conditions on startup.
#[tauri::command]
pub async fn get_offline_status(
offline_state: State<'_, OfflineState>,
) -> Result<OfflineStatus, String> {
let settings = {
let guard__ = offline_state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
store.get_settings()?
};
// If manual offline mode is enabled, return immediately
if settings.manual_offline_mode {
return Ok(OfflineStatus {
is_offline: true,
reason: Some(OfflineReason::ManualOverride),
manual_mode_enabled: true,
});
}
// Check network connectivity
let has_network = check_network_connectivity().await;
if !has_network {
return Ok(OfflineStatus {
is_offline: true,
reason: Some(OfflineReason::NoNetwork),
manual_mode_enabled: false,
});
}
Ok(OfflineStatus {
is_offline: false,
reason: None,
manual_mode_enabled: false,
})
}
/// Get offline settings
#[tauri::command]
pub fn get_offline_settings(state: State<'_, OfflineState>) -> Result<OfflineSettings, String> {
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
store.get_settings()
}
/// Enable or disable manual offline mode.
///
/// When entering offline mode, snapshots the user's current
/// `stream_first_track` audio setting and forces it to `false` so the
/// player won't attempt a network pre-buffer. When exiting, restores the
/// snapshot. This makes "offline mode" mean what it says — issue #279.
#[tauri::command]
pub async fn set_manual_offline(
enabled: bool,
state: State<'_, OfflineState>,
audio_state: State<'_, crate::config::audio_settings::AudioSettingsState>,
app_handle: AppHandle,
) -> Result<OfflineStatus, String> {
// 1) Persist the manual offline flag first so any concurrent reads
// see the new mode immediately.
let (was_offline, stream_first_before): (bool, Option<bool>) = {
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
let prev = store
.get_settings()
.map(|s| s.manual_offline_mode)
.unwrap_or(false);
let snapshot = store
.get_pre_offline_stream_first_track()
.unwrap_or(None);
store.set_manual_offline_mode(enabled)?;
(prev, snapshot)
};
// 2) Coordinate the stream_first_track snapshot/restore. This is best-
// effort — if the audio store isn't initialized yet (pre-login), we
// just skip; the offline flag itself has been persisted.
if enabled && !was_offline {
// Entering offline mode: stash current value and force to false.
let current = {
let guard = audio_state
.store
.lock()
.map_err(|e| format!("Audio settings lock error: {}", e))?;
guard
.as_ref()
.and_then(|s| s.get_settings().ok())
.map(|s| s.stream_first_track)
};
if let Some(current_value) = current {
{
let guard = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
if let Some(store) = guard.as_ref() {
let _ = store.set_pre_offline_stream_first_track(Some(current_value));
}
}
if current_value {
let guard = audio_state
.store
.lock()
.map_err(|e| format!("Audio settings lock error: {}", e))?;
if let Some(store) = guard.as_ref() {
let _ = store.set_stream_first_track(false);
log::info!(
"[Offline] stream_first_track snapshot={}; forced to false while offline",
current_value
);
}
}
}
} else if !enabled && was_offline {
// Exiting offline mode: restore snapshot if we have one.
if let Some(snapshot_value) = stream_first_before {
{
let guard = audio_state
.store
.lock()
.map_err(|e| format!("Audio settings lock error: {}", e))?;
if let Some(store) = guard.as_ref() {
let _ = store.set_stream_first_track(snapshot_value);
log::info!(
"[Offline] restored stream_first_track to {}",
snapshot_value
);
}
}
{
let guard = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
if let Some(store) = guard.as_ref() {
let _ = store.set_pre_offline_stream_first_track(None);
}
}
}
}
// 3) Get updated status
let status = get_offline_status(state).await?;
// 4) Emit events. offline-status-changed for the offline store;
// audio-settings-changed so the SettingsView reloads its local
// state of stream_first_track (we may have just mutated it).
let _ = app_handle.emit("offline-status-changed", &status);
let _ = app_handle.emit("audio-settings-changed", ());
Ok(status)
}
/// Set whether to show playlists with partial local content in offline mode
#[tauri::command]
pub fn set_show_partial_playlists(
enabled: bool,
state: State<'_, OfflineState>,
) -> Result<(), String> {
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
store.set_show_partial_playlists(enabled)
}
/// Set whether to allow Chromecast while in manual offline mode
#[tauri::command]
pub fn set_allow_cast_while_offline(
enabled: bool,
state: State<'_, OfflineState>,
) -> Result<(), String> {
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
store.set_allow_cast_while_offline(enabled)
}
/// Set whether to allow immediate scrobbling to Last.fm in manual offline mode
#[tauri::command]
pub fn set_allow_immediate_scrobbling(
enabled: bool,
state: State<'_, OfflineState>,
) -> Result<(), String> {
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
store.set_allow_immediate_scrobbling(enabled)
}
/// Set whether to queue scrobbles for later submission when back online
#[tauri::command]
pub fn set_allow_accumulated_scrobbling(
enabled: bool,
state: State<'_, OfflineState>,
) -> Result<(), String> {
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
store.set_allow_accumulated_scrobbling(enabled)
}
/// Set whether to show network folder content in manual offline mode
#[tauri::command]
pub fn set_show_network_folders_in_manual_offline(
enabled: bool,
state: State<'_, OfflineState>,
) -> Result<(), String> {
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
store.set_show_network_folders_in_manual_offline(enabled)
}
/// Check if network connectivity is available
#[tauri::command]
pub async fn check_network() -> bool {
super::check_network_connectivity().await
}
// === Pending Playlist Sync Commands ===
/// Get all playlists pending sync
#[tauri::command]
pub fn get_pending_playlists(
state: State<'_, OfflineState>,
) -> Result<Vec<PendingPlaylist>, String> {
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
store.get_pending_playlists()
}
/// Add tracks to a pending playlist
#[tauri::command]
pub fn add_tracks_to_pending_playlist(
pending_id: i64,
qobuz_track_ids: Vec<u64>,
local_track_paths: Vec<String>,
state: State<'_, OfflineState>,
) -> Result<(), String> {
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
store.add_tracks_to_pending_playlist(pending_id, &qobuz_track_ids, &local_track_paths)
}
/// Update Qobuz playlist ID without marking as synced (for partial sync recovery)
#[tauri::command]
pub fn update_pending_playlist_qobuz_id(
pending_id: i64,
qobuz_playlist_id: u64,
state: State<'_, OfflineState>,
) -> Result<(), String> {
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
store.update_qobuz_playlist_id(pending_id, qobuz_playlist_id)
}
/// Mark a pending playlist as synced after successful Qobuz creation
#[tauri::command]
pub fn mark_pending_playlist_synced(
pending_id: i64,
qobuz_playlist_id: u64,
state: State<'_, OfflineState>,
) -> Result<(), String> {
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
store.mark_playlist_synced(pending_id, qobuz_playlist_id)
}
/// Delete a pending playlist
#[tauri::command]
pub fn delete_pending_playlist(
pending_id: i64,
state: State<'_, OfflineState>,
) -> Result<(), String> {
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
store.delete_pending_playlist(pending_id)
}
// === Scrobble Queue Commands ===
/// Mark scrobbles as sent after successful Last.fm submission
#[tauri::command]
pub fn mark_scrobbles_sent(
ids: Vec<i64>,
state: State<'_, OfflineState>,
) -> Result<(), String> {
let guard__ = state
.store
.lock()
.map_err(|e| format!("Lock error: {}", e))?;
let store = guard__
.as_ref()
.ok_or("No active session - please log in")?;
store.mark_scrobbles_sent(&ids)
}
}