mirror of
https://github.com/moku-project/Moku.git
synced 2026-06-13 09:19:56 -05:00
Implement phase 1
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
import {untrack} from 'svelte';
|
||||
import {DEFAULT_KEYBINDS} from '$lib/core/keybinds/defaultBinds';
|
||||
import {savePersistentState, loadPersistentState} from '$lib/core/persistence/persist';
|
||||
import {applyTheme} from '$lib/core/theme';
|
||||
import {applyZoom} from '$lib/core/ui/zoom';
|
||||
import {DEFAULT_SETTINGS, DEFAULT_MANGA_PREFS, type MangaPrefs, type Settings} from '$lib/types/settings';
|
||||
|
||||
const SETTINGS_STORAGE_KEY = 'settings';
|
||||
const SETTINGS_STORE_VERSION = 1;
|
||||
|
||||
interface PersistedSettings {
|
||||
settings: Partial<Settings> | null;
|
||||
storeVersion: number | null;
|
||||
}
|
||||
|
||||
function mergeSettings(saved: Partial<Settings> | null | undefined): Settings {
|
||||
return {
|
||||
...DEFAULT_SETTINGS,
|
||||
...saved,
|
||||
keybinds: {...DEFAULT_KEYBINDS, ...(saved?.keybinds ?? {})},
|
||||
heroSlots: saved?.heroSlots ?? [null, null, null, null],
|
||||
mangaLinks: saved?.mangaLinks ?? {},
|
||||
mangaPrefs: saved?.mangaPrefs ?? {},
|
||||
customThemes: saved?.customThemes ?? [],
|
||||
hiddenCategoryIds: saved?.hiddenCategoryIds ?? [],
|
||||
nsfwAllowedSourceIds: saved?.nsfwAllowedSourceIds ?? [],
|
||||
nsfwBlockedSourceIds: saved?.nsfwBlockedSourceIds ?? [],
|
||||
libraryTabSort: saved?.libraryTabSort ?? {},
|
||||
libraryTabStatus: saved?.libraryTabStatus ?? {},
|
||||
libraryTabFilters: saved?.libraryTabFilters ?? {},
|
||||
extraScanDirs: saved?.extraScanDirs ?? [],
|
||||
pinnedSourceIds: saved?.pinnedSourceIds ?? [],
|
||||
readerPresets: saved?.readerPresets ?? [],
|
||||
mangaReaderSettings: saved?.mangaReaderSettings ?? {},
|
||||
hiddenLibraryTabs: saved?.hiddenLibraryTabs ?? [],
|
||||
libraryPinnedTabOrder: saved?.libraryPinnedTabOrder ?? [],
|
||||
};
|
||||
}
|
||||
|
||||
export const settingsState = $state<Settings>(mergeSettings(null));
|
||||
|
||||
export const settingsStatus = $state({
|
||||
ready: false,
|
||||
loading: false,
|
||||
error: null as string | null,
|
||||
});
|
||||
|
||||
let initialized = false;
|
||||
let persistQueued = false;
|
||||
|
||||
function persistSettings() {
|
||||
const snapshot = JSON.stringify(settingsState);
|
||||
|
||||
void savePersistentState(SETTINGS_STORAGE_KEY, {
|
||||
settings: JSON.parse(snapshot) as Settings,
|
||||
storeVersion: SETTINGS_STORE_VERSION,
|
||||
} satisfies PersistedSettings);
|
||||
}
|
||||
|
||||
function applySettingsVisuals() {
|
||||
if (!settingsStatus.ready || typeof document === 'undefined') return;
|
||||
|
||||
applyTheme(settingsState.theme, settingsState.customThemes);
|
||||
applyZoom(settingsState.uiZoom);
|
||||
}
|
||||
|
||||
function queueSettingsSync() {
|
||||
applySettingsVisuals();
|
||||
|
||||
if (!settingsStatus.ready || settingsStatus.loading || persistQueued) return;
|
||||
|
||||
persistQueued = true;
|
||||
|
||||
queueMicrotask(() => {
|
||||
persistQueued = false;
|
||||
|
||||
if (!settingsStatus.ready || settingsStatus.loading) return;
|
||||
|
||||
persistSettings();
|
||||
});
|
||||
}
|
||||
|
||||
export async function initSettingsState() {
|
||||
if (initialized || settingsStatus.loading) return;
|
||||
|
||||
settingsStatus.loading = true;
|
||||
|
||||
try {
|
||||
const persisted = await loadPersistentState<PersistedSettings>(SETTINGS_STORAGE_KEY);
|
||||
|
||||
untrack(() => {
|
||||
Object.assign(settingsState, mergeSettings(persisted?.settings));
|
||||
});
|
||||
|
||||
initialized = true;
|
||||
settingsStatus.ready = true;
|
||||
settingsStatus.error = null;
|
||||
applySettingsVisuals();
|
||||
} catch (error) {
|
||||
settingsStatus.ready = true;
|
||||
settingsStatus.error = String(error);
|
||||
} finally {
|
||||
settingsStatus.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
export function updateSettings(patch: Partial<Settings>) {
|
||||
Object.assign(settingsState, patch);
|
||||
queueSettingsSync();
|
||||
}
|
||||
|
||||
export function resetSettings() {
|
||||
Object.assign(settingsState, mergeSettings(null));
|
||||
queueSettingsSync();
|
||||
}
|
||||
|
||||
export function getMangaPrefs(mangaId: number): MangaPrefs {
|
||||
return {
|
||||
...DEFAULT_MANGA_PREFS,
|
||||
...(settingsState.mangaPrefs[mangaId] ?? {}),
|
||||
};
|
||||
}
|
||||
|
||||
export function updateMangaPrefs(mangaId: number, patch: Partial<MangaPrefs>) {
|
||||
settingsState.mangaPrefs = {
|
||||
...settingsState.mangaPrefs,
|
||||
[mangaId]: {
|
||||
...(settingsState.mangaPrefs[mangaId] ?? {}),
|
||||
...patch,
|
||||
},
|
||||
};
|
||||
queueSettingsSync();
|
||||
}
|
||||
|
||||
export function clearMangaPrefs(mangaId: number) {
|
||||
const next = {...settingsState.mangaPrefs};
|
||||
delete next[mangaId];
|
||||
settingsState.mangaPrefs = next;
|
||||
queueSettingsSync();
|
||||
}
|
||||
Reference in New Issue
Block a user