feat(telegram): sync client display prefs via CloudStorage
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 56s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m20s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 56s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m20s
Theme, reduce-motion and board labels lived only in local IndexedDB/localStorage, so they did not follow the user across devices and could be lost when the Telegram WebView cleared storage. Mirror these three device-independent prefs to Telegram CloudStorage (Bot API 6.9) from the single local-persist point (persistPrefs), and reconcile them from CloudStorage in the background on launch (reconcileCloudPrefs) so a change made on another device follows the user here. The local store stays the instant-render cache; the interface language is intentionally excluded (it syncs via the durable account). Pure encode/decode extracted to cloudprefs.ts with unit tests; the CloudStorage transport wrappers are added to telegram.ts. No-op outside Telegram or on a client predating CloudStorage.
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
// Telegram CloudStorage sync for the device-independent client display preferences — theme,
|
||||
// reduce-motion and board labels — so they follow the user across their Telegram devices. The
|
||||
// interface language is intentionally excluded: it has its own server-side sync
|
||||
// (Profile.preferredLanguage) plus an on-launch reconciler, and mixing it in here would fight that.
|
||||
// The pure encode/decode is kept free of the SDK and the DOM so it unit-tests in the node
|
||||
// environment; the CloudStorage transport wrappers live in telegram.ts and the wiring (mirror on
|
||||
// save, reconcile on launch) in app.svelte.ts.
|
||||
|
||||
import type { ThemePref } from './theme';
|
||||
import type { BoardLabelMode } from './boardlabels';
|
||||
|
||||
/** ClientPrefs is the subset of preferences synced across devices via Telegram CloudStorage. */
|
||||
export interface ClientPrefs {
|
||||
theme: ThemePref;
|
||||
reduceMotion: boolean;
|
||||
boardLabels: BoardLabelMode;
|
||||
}
|
||||
|
||||
/** CLOUD_PREFS_KEY is the Telegram CloudStorage key holding the JSON-encoded ClientPrefs. */
|
||||
export const CLOUD_PREFS_KEY = 'prefs';
|
||||
|
||||
/** encodeClientPrefs serialises the synced client prefs (and only those — never the locale). */
|
||||
export function encodeClientPrefs(p: ClientPrefs): string {
|
||||
return JSON.stringify({ theme: p.theme, reduceMotion: p.reduceMotion, boardLabels: p.boardLabels });
|
||||
}
|
||||
|
||||
/**
|
||||
* decodeClientPrefs parses a CloudStorage payload into a partial ClientPrefs, keeping only valid
|
||||
* fields and dropping anything unknown, mistyped or malformed — so a value written by a newer or
|
||||
* older build, or a corrupt entry, never throws and never applies a bad setting. A missing field
|
||||
* stays absent, so the caller leaves the corresponding local value untouched.
|
||||
*/
|
||||
export function decodeClientPrefs(raw: string | null | undefined): Partial<ClientPrefs> {
|
||||
if (!raw) return {};
|
||||
let o: Record<string, unknown>;
|
||||
try {
|
||||
o = JSON.parse(raw) as Record<string, unknown>;
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
if (!o || typeof o !== 'object') return {};
|
||||
const out: Partial<ClientPrefs> = {};
|
||||
if (o.theme === 'auto' || o.theme === 'light' || o.theme === 'dark') out.theme = o.theme;
|
||||
if (typeof o.reduceMotion === 'boolean') out.reduceMotion = o.reduceMotion;
|
||||
if (o.boardLabels === 'beginner' || o.boardLabels === 'classic' || o.boardLabels === 'none') {
|
||||
out.boardLabels = o.boardLabels;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
Reference in New Issue
Block a user