Files
jellytau/src/lib/stores/sleepTimer.ts
T
dtourolle d01c2aab9f
🏗️ Build and Test JellyTau / Run Tests (pull_request) Successful in 4m39s
Traceability Validation / Check Requirement Traces (pull_request) Failing after 36s
🏗️ Build and Test JellyTau / Build Android APK (pull_request) Failing after 1m57s
Migrate all IPC call sites to typed tauri-specta commands.*
Replace the remaining ~155 untyped invoke() calls across stores, services,
components, and routes with the generated commands.* wrappers from
$lib/api/bindings, so every IPC call is compile-time-checked against the
command signatures.

- Register repository_get_subtitle_url and repository_get_video_download_url
  in specta_builder() and the invoke_handler; regenerate bindings.ts.
- Source duplicated wire types (AutoplaySettings, CacheConfig, Session,
  ConnectivityStatus, audio/video settings, etc.) from bindings.
- Fix two bugs surfaced by the typed wrappers:
  - VideoDownloadButton passed an un-awaited Promise as the stream URL.
  - setAutoplaySettings omitted the required userId argument.
- Update unit tests asserting the old invoke(name, args) shape.
- Remove the five param-naming guard tests; the compiler and codegen now
  enforce what they checked.

svelte-check: 0 errors. vitest: green. cargo test --lib: green.
2026-06-21 08:47:04 +02:00

77 lines
2.0 KiB
TypeScript

/**
* 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<SleepTimerState>(initialState);
return {
subscribe,
set, // Updated by playerEvents.ts when backend emits SleepTimerChanged event
// Methods that invoke the backend API
async setTimeTimer(minutes: number): Promise<void> {
const endTime = Date.now() + minutes * 60 * 1000;
await commands.playerSetSleepTimer({ kind: "time", endTime });
},
async setEndOfTrackTimer(): Promise<void> {
await commands.playerSetSleepTimer({ kind: "endOfTrack" });
},
async setEpisodesTimer(count: number): Promise<void> {
await commands.playerSetSleepTimer({ kind: "episodes", remaining: count });
},
async cancel(): Promise<void> {
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
);