Files
ChatApp/apps/desktop/src/lib/pttSettings.ts
T
2026-04-18 23:11:35 +02:00

84 lines
2.3 KiB
TypeScript

// Local-only user preferences for push-to-talk. Stored in localStorage because
// the server is zero-knowledge and doesn't need to know input-device details.
const STORAGE_KEY = 'chatapp.ptt';
export interface PttSettings {
enabled: boolean;
// KeyboardEvent.code of the hold-to-talk key (e.g. 'Space', 'KeyV').
key: string;
// Human-readable label derived from the key — kept in settings so we don't
// re-derive it on every render. Updated together with `key`.
keyLabel: string;
}
const DEFAULTS: PttSettings = {
enabled: false,
key: 'Space',
keyLabel: 'Space',
};
type Listener = (s: PttSettings) => void;
const listeners = new Set<Listener>();
let cached: PttSettings | null = null;
function read(): PttSettings {
if (cached) return cached;
try {
const raw = window.localStorage.getItem(STORAGE_KEY);
if (!raw) {
cached = DEFAULTS;
return cached;
}
const parsed = JSON.parse(raw) as Partial<PttSettings>;
cached = {
enabled: typeof parsed.enabled === 'boolean' ? parsed.enabled : DEFAULTS.enabled,
key: typeof parsed.key === 'string' && parsed.key ? parsed.key : DEFAULTS.key,
keyLabel:
typeof parsed.keyLabel === 'string' && parsed.keyLabel
? parsed.keyLabel
: DEFAULTS.keyLabel,
};
return cached;
} catch {
cached = DEFAULTS;
return cached;
}
}
function write(s: PttSettings): void {
cached = s;
try {
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(s));
} catch {
/* quota / private mode */
}
for (const l of listeners) l(s);
}
export function getPttSettings(): PttSettings {
return read();
}
export function updatePttSettings(patch: Partial<PttSettings>): PttSettings {
const next = { ...read(), ...patch };
write(next);
return next;
}
export function subscribePttSettings(listener: Listener): () => void {
listeners.add(listener);
return () => listeners.delete(listener);
}
// Turns a KeyboardEvent.code into a short human label (best-effort).
export function keyCodeToLabel(code: string): string {
if (code === 'Space') return 'Space';
if (code.startsWith('Key')) return code.slice(3);
if (code.startsWith('Digit')) return code.slice(5);
if (code.startsWith('Numpad')) return 'Num' + code.slice(6);
if (code.startsWith('Arrow')) return code.slice(5) + ' Arrow';
return code;
}