NavidromeApp/Shared/Storage/PlaybackStateStore.swift
Dallas Groot 9add1e014a quick fix
2026-04-11 16:23:41 -07:00

72 lines
2.6 KiB
Swift

import Foundation
/// Persists the current playback queue and position to UserDefaults so the app
/// can restore them after being terminated by iOS (memory pressure, system kill).
///
/// Restoration is intentionally conservative:
/// - Only offline/downloaded songs are auto-resumed (streams need live URLs)
/// - Playback restarts paused at the saved position the user taps Play
/// - If the saved songs no longer exist in the library the state is discarded
struct PlaybackStateStore {
static let shared = PlaybackStateStore()
private let queueKey = "playback_saved_queue"
private let indexKey = "playback_saved_index"
private let timeKey = "playback_saved_time"
private let songIdKey = "playback_saved_song_id"
// MARK: - Save
/// Call whenever the current song, queue, or playback position changes.
/// Writes are cheap just JSON-encoding Song structs to UserDefaults.
func save(queue: [Song], index: Int, currentTime: TimeInterval, currentSongId: String?) {
guard !queue.isEmpty else { return }
let encoder = JSONEncoder()
if let data = try? encoder.encode(queue) {
UserDefaults.standard.set(data, forKey: queueKey)
}
UserDefaults.standard.set(index, forKey: indexKey)
UserDefaults.standard.set(currentTime, forKey: timeKey)
UserDefaults.standard.set(currentSongId, forKey: songIdKey)
}
// MARK: - Load
struct RestoredState {
let queue: [Song]
let index: Int
let currentTime: TimeInterval
let currentSong: Song
}
/// Returns saved state if valid, nil if nothing was saved or data is stale.
func load() -> RestoredState? {
guard let data = UserDefaults.standard.data(forKey: queueKey),
let queue = try? JSONDecoder().decode([Song].self, from: data),
!queue.isEmpty else { return nil }
let index = UserDefaults.standard.integer(forKey: indexKey)
let time = UserDefaults.standard.double(forKey: timeKey)
guard queue.indices.contains(index) else { return nil }
return RestoredState(
queue: queue,
index: index,
currentTime: time,
currentSong: queue[index]
)
}
// MARK: - Clear
/// Call after the user explicitly stops playback or clears the queue.
func clear() {
UserDefaults.standard.removeObject(forKey: queueKey)
UserDefaults.standard.removeObject(forKey: indexKey)
UserDefaults.standard.removeObject(forKey: timeKey)
UserDefaults.standard.removeObject(forKey: songIdKey)
}
}