105 lines
3.3 KiB
TypeScript
105 lines
3.3 KiB
TypeScript
import { makeAutoObservable, reaction, runInAction } from 'mobx';
|
|
import { getSetting, listSettings } from '@/shared/api';
|
|
import { themeStore, type BrandColors } from '@/shared/config';
|
|
import { appEvents, storage } from '@/shared/lib';
|
|
import { loadRemoteSetting } from '../api/kioskSettingsApi';
|
|
import type { AppSettings } from './types';
|
|
|
|
const STORAGE_KEY = 'app_settings';
|
|
const SETTINGS_INTERVAL = 60_000;
|
|
const HEADER_INTERVAL = 4_000;
|
|
const CITY_INTERVAL = 120_000;
|
|
|
|
const defaultSettings: AppSettings = {
|
|
scheduleDeviationSource: 'real',
|
|
notifVolume: 70,
|
|
brightness: 80,
|
|
wifi: true,
|
|
bluetooth: false,
|
|
language: 'ru',
|
|
};
|
|
|
|
function storedSettings(): AppSettings {
|
|
const stored = storage.getJson<AppSettings>(STORAGE_KEY);
|
|
return stored ? { ...defaultSettings, ...stored } : { ...defaultSettings };
|
|
}
|
|
|
|
class SettingsStore {
|
|
settings: AppSettings = storedSettings();
|
|
|
|
private timers: ReturnType<typeof setInterval>[] = [];
|
|
private lastHeader = '';
|
|
|
|
constructor() {
|
|
makeAutoObservable(this, {}, { autoBind: true });
|
|
reaction(
|
|
() => this.settings.brandColorsTablet as BrandColors | undefined,
|
|
(brand) => themeStore.setBrand(brand ?? null),
|
|
{ fireImmediately: true },
|
|
);
|
|
}
|
|
|
|
start(): void {
|
|
if (this.timers.length > 0) return;
|
|
void this.pullSettings();
|
|
void this.pullHeader();
|
|
void this.pullCity();
|
|
this.timers = [
|
|
setInterval(() => void this.pullSettings(), SETTINGS_INTERVAL),
|
|
setInterval(() => void this.pullHeader(), HEADER_INTERVAL),
|
|
setInterval(() => void this.pullCity(), CITY_INTERVAL),
|
|
];
|
|
appEvents.on('app-settings:force-pull', this.forcePull);
|
|
}
|
|
|
|
stop(): void {
|
|
for (const timer of this.timers) clearInterval(timer);
|
|
this.timers = [];
|
|
appEvents.off('app-settings:force-pull', this.forcePull);
|
|
}
|
|
|
|
update(patch: Partial<AppSettings>): void {
|
|
this.settings = { ...this.settings, ...patch };
|
|
storage.setJson(STORAGE_KEY, this.settings);
|
|
}
|
|
|
|
reset(): void {
|
|
this.settings = { ...defaultSettings };
|
|
storage.remove(STORAGE_KEY);
|
|
}
|
|
|
|
private forcePull(): void {
|
|
this.lastHeader = '';
|
|
void this.pullSettings();
|
|
void this.pullHeader();
|
|
}
|
|
|
|
private async pullSettings(): Promise<void> {
|
|
const all = await listSettings();
|
|
const patch: Record<string, unknown> = {};
|
|
for (const [key, value] of Object.entries(all)) {
|
|
if (key.startsWith('ui.') && value != null) patch[key.slice(3)] = value;
|
|
}
|
|
if (Object.keys(patch).length === 0) return;
|
|
runInAction(() => this.update(patch as Partial<AppSettings>));
|
|
}
|
|
|
|
private async pullHeader(): Promise<void> {
|
|
const value = await getSetting<AppSettings['tabletHeader']>('ui.tabletHeader');
|
|
if (value == null) return;
|
|
const serialized = JSON.stringify(value);
|
|
if (serialized === this.lastHeader) return;
|
|
this.lastHeader = serialized;
|
|
runInAction(() => this.update({ tabletHeader: value }));
|
|
}
|
|
|
|
private async pullCity(): Promise<void> {
|
|
const value = await loadRemoteSetting<{ city?: string; customCityName?: string }>('global_city', {});
|
|
if (!value.city) return;
|
|
if (this.settings.city === value.city && this.settings.customCityName === value.customCityName) return;
|
|
runInAction(() => this.update({ city: value.city, customCityName: value.customCityName }));
|
|
}
|
|
}
|
|
|
|
export const settingsStore = new SettingsStore();
|