mirror of
https://github.com/fluxerapp/fluxer.git
synced 2026-09-03 05:10:25 +03:00
fix(app): repair theme CSS sync persistence and data loss (#2067)
This commit is contained in:
@@ -254,7 +254,7 @@ function normalizeStoredSyncedPreferences(raw: string | null | undefined): strin
|
||||
try {
|
||||
decodeSyncedPreferences(raw);
|
||||
} catch {
|
||||
return '';
|
||||
return raw;
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ export const ZOOM_LEVEL_MARKERS = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0] as cons
|
||||
export const ACCESSIBILITY_STORE_STORAGE_KEY = 'Accessibility';
|
||||
export const ACCESSIBILITY_ZOOM_STORAGE_KEY = 'Accessibility:zoomLevel';
|
||||
export const ACCESSIBILITY_CUSTOM_THEME_STORAGE_KEY = 'Accessibility:customThemeCss';
|
||||
const ACCESSIBILITY_CUSTOM_THEME_SYNC_STORAGE_KEY = 'Accessibility:customThemeCssSyncAcrossDevices';
|
||||
export const ACCESSIBILITY_MOTION_STORAGE_KEY = 'Accessibility:motion';
|
||||
export const ACCESSIBILITY_SHOW_NEKO_STORAGE_KEY = 'Accessibility:showNeko';
|
||||
export const ACCESSIBILITY_KEEP_NEKO_STILL_STORAGE_KEY = 'Accessibility:keepNekoStill';
|
||||
@@ -492,6 +493,21 @@ function persistLocalCustomThemeCss(css: string | null): void {
|
||||
} catch {}
|
||||
}
|
||||
|
||||
function persistLocalCustomThemeCssSyncAcrossDevices(value: boolean): void {
|
||||
try {
|
||||
AppStorage.setItem(ACCESSIBILITY_CUSTOM_THEME_SYNC_STORAGE_KEY, JSON.stringify(value));
|
||||
} catch {}
|
||||
}
|
||||
|
||||
function readLocalCustomThemeCssSyncAcrossDevices(): boolean {
|
||||
try {
|
||||
const raw = AppStorage.getItem(ACCESSIBILITY_CUSTOM_THEME_SYNC_STORAGE_KEY);
|
||||
return raw === null ? false : JSON.parse(raw) === true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeCustomThemeCss(css: string | null | undefined): string | null {
|
||||
if (typeof css !== 'string') {
|
||||
return null;
|
||||
@@ -728,6 +744,7 @@ class Accessibility {
|
||||
if (this.customThemeCss !== null) {
|
||||
persistLocalCustomThemeCss(this.customThemeCss);
|
||||
}
|
||||
this.customThemeCssSyncAcrossDevices = readLocalCustomThemeCssSyncAcrossDevices();
|
||||
this.showNeko = readAndMigrateLocalShowNeko();
|
||||
this.keepNekoStill = readAndMigrateLocalKeepNekoStill();
|
||||
this.showVideoSeekPreviewThumbnails = readLocalVideoSeekPreviewThumbnails();
|
||||
@@ -851,7 +868,11 @@ class Accessibility {
|
||||
showStickersInAutocomplete: s.showStickersInExpressionAutocomplete,
|
||||
showMemesInAutocomplete: s.showMemesInExpressionAutocomplete,
|
||||
voiceChannelJoinRequiresDoubleClick: s.voiceChannelJoinRequiresDoubleClick,
|
||||
customThemeCss: s.customThemeCssSyncAcrossDevices ? (s.customThemeCss ?? '') : (s.serverCustomThemeCss ?? ''),
|
||||
customThemeCss: ((): string | undefined => {
|
||||
const local = s.customThemeCss;
|
||||
const server = s.serverCustomThemeCss;
|
||||
return (s.customThemeCssSyncAcrossDevices ? local : server) ?? undefined;
|
||||
})(),
|
||||
showFavorites: s.showFavorites,
|
||||
dmMessagePreviewMode: DM_PREVIEW_TO_PROTO[s.dmMessagePreviewMode],
|
||||
enableTtsCommand: s.enableTTSCommand,
|
||||
@@ -1396,6 +1417,7 @@ class Accessibility {
|
||||
persistLocalCustomThemeCss(this.customThemeCss);
|
||||
}
|
||||
this.customThemeCssSyncAcrossDevices = syncAcrossDevices;
|
||||
persistLocalCustomThemeCssSyncAcrossDevices(syncAcrossDevices);
|
||||
}
|
||||
|
||||
subscribe(callback: () => void): () => void {
|
||||
|
||||
@@ -125,6 +125,7 @@ class ThemeLibrary {
|
||||
localFiles: Array<ThemeLibraryLocalFileReference> = [];
|
||||
enabledThemeIds: Array<string> = [];
|
||||
isHydrated = false;
|
||||
loadFailed = false;
|
||||
isBusy = false;
|
||||
revision = 0;
|
||||
private initPromise: Promise<void> | null = null;
|
||||
@@ -173,12 +174,13 @@ class ThemeLibrary {
|
||||
this.localFiles = localFiles.sort((a, b) => a.name.localeCompare(b.name));
|
||||
this.enabledThemeIds = enabledThemeIds.filter((id) => themes.some((theme) => theme.id === id));
|
||||
this.isHydrated = true;
|
||||
this.loadFailed = false;
|
||||
this.revision += 1;
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Failed to hydrate theme library', error);
|
||||
runInAction(() => {
|
||||
this.isHydrated = true;
|
||||
this.loadFailed = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ function getDatabase(): Promise<IDBDatabase> {
|
||||
if (openPromise) {
|
||||
return openPromise;
|
||||
}
|
||||
openPromise = new Promise((resolve, reject) => {
|
||||
const promise = new Promise<IDBDatabase>((resolve, reject) => {
|
||||
if (!browserIndexedDB) {
|
||||
reject(new Error('IndexedDB unavailable'));
|
||||
return;
|
||||
@@ -126,7 +126,13 @@ function getDatabase(): Promise<IDBDatabase> {
|
||||
request.onerror = () => reject(request.error ?? new Error('Failed to open theme library database'));
|
||||
request.onblocked = () => reject(new Error('Theme library database upgrade is blocked by another window'));
|
||||
});
|
||||
return openPromise;
|
||||
promise.catch(() => {
|
||||
if (openPromise === promise) {
|
||||
openPromise = null;
|
||||
}
|
||||
});
|
||||
openPromise = promise;
|
||||
return promise;
|
||||
}
|
||||
|
||||
async function withReadonlyDb<T>(
|
||||
|
||||
Reference in New Issue
Block a user