feat(player): persist volume across sessions, default to 100%

Store the playback volume in app settings (config.json) whenever it
changes and re-apply the previous session's level at boot, instead of
always starting at the old 70% fallback.

- AppSettings gains volume (default 1 = 100%); both default-settings
  copies and the volume signal default are raised from 0.7 to 1.
- doSetVolume persists via the app store (mirrors playbackSpeed).
- The boot sync awaits the app store's async config load (new
  whenReady()) so a persisted level is applied even when settings load
  finishes after useAudio mounts.
- tests/volume-persistence.test.ts: default, clamp, and cross-session
  reuse (fresh module instance simulates the next launch).
This commit is contained in:
2026-08-11 13:30:01 -04:00
parent 1b55b7117c
commit 8049d02457
5 changed files with 114 additions and 4 deletions

View File

@@ -28,6 +28,7 @@ const defaultSettings: AppSettings = {
theme: "system",
fontSize: 14,
playbackSpeed: 1,
volume: 1,
downloadPath: "",
transparentBackground: false,
showSelectionMarker: false,
@@ -55,12 +56,14 @@ function createAppStore() {
// Start with defaults; async load will update once ready
const [state, setState] = createSignal<AppState>(defaultState);
// Fire-and-forget async initialisation
// Fire-and-forget async initialisation; the promise is exposed via
// whenReady() so boot-time consumers (audio-level restore) can await
// the config read before reading settings.
const init = async () => {
const loaded = await loadAppStateFromFile();
setState(loaded);
};
init();
const appInit = init();
const saveState = (next: AppState) => {
saveAppStateToFile(next);
@@ -119,6 +122,8 @@ function createAppStore() {
return {
state,
/** Resolves once persisted settings are loaded from disk. */
whenReady: () => appInit,
updateSettings,
updatePreferences,
updateCustomTheme,