108 lines
2.7 KiB
JavaScript
108 lines
2.7 KiB
JavaScript
/**
|
|
* Central state store with persistence.
|
|
* Keys: user, windows, wallpaper, achievements, connection
|
|
*/
|
|
const STORAGE_KEY = 'meridian:state';
|
|
|
|
const State = (() => {
|
|
const listeners = new Map();
|
|
let _state = loadState();
|
|
|
|
function loadState() {
|
|
try {
|
|
const raw = localStorage.getItem(STORAGE_KEY);
|
|
if (raw) {
|
|
const parsed = JSON.parse(raw);
|
|
// achievements is stored as array, reconstruct as Set
|
|
if (parsed.achievements) {
|
|
parsed._achievementSet = new Set(parsed.achievements);
|
|
}
|
|
return parsed;
|
|
}
|
|
} catch (e) {
|
|
console.warn('State load failed:', e);
|
|
}
|
|
return {
|
|
user: null,
|
|
windows: [],
|
|
wallpaper: 'graphite',
|
|
achievements: [],
|
|
_achievementSet: new Set(),
|
|
connection: navigator.onLine
|
|
};
|
|
}
|
|
|
|
function saveState() {
|
|
try {
|
|
const toSave = {
|
|
user: _state.user,
|
|
windows: _state.windows,
|
|
wallpaper: _state.wallpaper,
|
|
achievements: Array.from(_state._achievementSet || _state.achievements)
|
|
};
|
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(toSave));
|
|
} catch (e) {
|
|
console.warn('State save failed:', e);
|
|
}
|
|
}
|
|
|
|
function set(key, val) {
|
|
_state[key] = val;
|
|
saveState();
|
|
notify(key);
|
|
}
|
|
|
|
function get(key) {
|
|
return _state[key];
|
|
}
|
|
|
|
function subscribe(key, cb) {
|
|
if (!listeners.has(key)) listeners.set(key, new Set());
|
|
listeners.get(key).add(cb);
|
|
// immediate call with current value
|
|
try { cb(_state[key]); } catch (e) { console.error('State subscribe error:', e); }
|
|
return () => off(key, cb);
|
|
}
|
|
|
|
function off(key, cb) {
|
|
const set = listeners.get(key);
|
|
if (set) {
|
|
set.delete(cb);
|
|
if (set.size === 0) listeners.delete(key);
|
|
}
|
|
}
|
|
|
|
function notify(key) {
|
|
const set = listeners.get(key);
|
|
if (set) {
|
|
for (const cb of set) {
|
|
try { cb(_state[key]); } catch (e) { console.error('State notify error:', e); }
|
|
}
|
|
}
|
|
}
|
|
|
|
function addAchievement(id) {
|
|
if (!_state._achievementSet) {
|
|
_state._achievementSet = new Set(_state.achievements || []);
|
|
_state.achievements = Array.from(_state._achievementSet);
|
|
}
|
|
_state._achievementSet.add(id);
|
|
_state.achievements = Array.from(_state._achievementSet);
|
|
saveState();
|
|
notify('achievements');
|
|
}
|
|
|
|
function initConnection() {
|
|
_state.connection = navigator.onLine;
|
|
window.addEventListener('online', () => { _state.connection = true; notify('connection'); saveState(); });
|
|
window.addEventListener('offline', () => { _state.connection = false; notify('connection'); saveState(); });
|
|
}
|
|
|
|
return {
|
|
set, get, subscribe, off, addAchievement, initConnection
|
|
};
|
|
})();
|
|
|
|
export default State;
|
|
export { State };
|