import * as SecureStore from "expo-secure-store"; import { create } from "zustand"; /** * Theme, language, keep-awake, and the overlay-permission flag are the only * non-secret app preferences. SecureStore is used (not AsyncStorage) because * AsyncStorage isn't actually installed in this project and SecureStore already * backs the session — one small JSON blob stays well under its 2 KB value cap. */ const SETTINGS_KEY = "waseel_settings"; export type ThemeMode = "light" | "dark" | "system"; export type Lang = "en" | "ar" | "fr"; type PersistedSettings = Pick< SettingsState, "mode" | "lang" | "keepAwake" | "overlayRequested" >; type SettingsState = { /** False until hydrate() has merged SecureStore values into the store. */ hydrated: boolean; mode: ThemeMode; lang: Lang; keepAwake: boolean; /** * Only records that we sent the user to the system screen — SYSTEM_ALERT_WINDOW * can't be queried from JS, so this is not a granted/denied signal. */ overlayRequested: boolean; setMode: (mode: ThemeMode) => void; setLang: (lang: Lang) => void; setKeepAwake: (value: boolean) => void; setOverlayRequested: (value: boolean) => void; hydrate: () => Promise; }; const write = async (state: SettingsState) => { const blob: PersistedSettings = { mode: state.mode, lang: state.lang, keepAwake: state.keepAwake, overlayRequested: state.overlayRequested, }; await SecureStore.setItemAsync(SETTINGS_KEY, JSON.stringify(blob)); }; export const useSettingsStore = create((set, get) => ({ hydrated: false, mode: "system", lang: "en", keepAwake: false, overlayRequested: false, setMode: (mode) => { set({ mode }); void write(get()); }, setLang: (lang) => { set({ lang }); void write(get()); }, setKeepAwake: (value) => { set({ keepAwake: value }); void write(get()); }, setOverlayRequested: (value) => { set({ overlayRequested: value }); void write(get()); }, hydrate: async () => { try { const stored = await SecureStore.getItemAsync(SETTINGS_KEY); if (stored) { const parsed = JSON.parse(stored) as Partial; set({ mode: parsed.mode ?? "system", lang: parsed.lang ?? "en", keepAwake: parsed.keepAwake ?? false, overlayRequested: parsed.overlayRequested ?? false, hydrated: true, }); return; } } catch (error) { console.warn("[SETTINGS hydrate]: ", error); } set({ hydrated: true }); }, }));