/** * Sleep Timer Store (Backend-First Architecture) * * This store reflects sleep timer state from the backend. * All logic is in the Rust backend (PlayerController). * * The backend emits SleepTimerChanged events to update this store. * Components call store methods which invoke the backend API. * * TRACES: UR-026 | DR-029 */ import { writable, derived } from "svelte/store"; import { commands } from "$lib/api/bindings"; export type SleepTimerMode = | { kind: "off" } | { kind: "time"; endTime: number } | { kind: "endOfTrack" } | { kind: "episodes"; remaining: number }; interface SleepTimerState { mode: SleepTimerMode; remainingSeconds: number; } function createSleepTimerStore() { const initialState: SleepTimerState = { mode: { kind: "off" }, remainingSeconds: 0, }; const { subscribe, set } = writable(initialState); return { subscribe, set, // Updated by playerEvents.ts when backend emits SleepTimerChanged event // Methods that invoke the backend API async setTimeTimer(minutes: number): Promise { const endTime = Date.now() + minutes * 60 * 1000; await commands.playerSetSleepTimer({ kind: "time", endTime }); }, async setEndOfTrackTimer(): Promise { await commands.playerSetSleepTimer({ kind: "endOfTrack" }); }, async setEpisodesTimer(count: number): Promise { await commands.playerSetSleepTimer({ kind: "episodes", remaining: count }); }, async cancel(): Promise { await commands.playerCancelSleepTimer(); }, }; } export const sleepTimer = createSleepTimerStore(); // Derived stores for convenient access export const sleepTimerMode = derived(sleepTimer, ($s) => $s.mode); export const sleepTimerActive = derived( sleepTimer, ($s) => $s.mode.kind !== "off" ); export const sleepTimerRemainingSeconds = derived( sleepTimer, ($s) => $s.remainingSeconds ); export const sleepTimerRemainingEpisodes = derived(sleepTimer, ($s) => $s.mode.kind === "episodes" ? $s.mode.remaining : 0 );