diff --git a/src/alf/util/material3/Monet/Palette.ts b/src/alf/util/material3/Monet/Palette.ts index 562a97cdf..44924b3f4 100644 --- a/src/alf/util/material3/Monet/Palette.ts +++ b/src/alf/util/material3/Monet/Palette.ts @@ -29,6 +29,7 @@ export default class Palette { static NEUTRAL1_CHROMA = 4 static NEUTRAL2_CHROMA = 8 static GOOGLE_BLUE = 0xff1b6ef3 + static DEFAULT_SEED = '#EE6300' static getStyle(hue: number, chroma: number): StyleType { return { @@ -204,7 +205,11 @@ export default class Palette { style: GenerationStyle = 'TONAL_SPOT', ): MaterialYouPalette { // Parse the HEX seed color string into an integer - seed = seed.toUpperCase().substring(1, 7) + const normalizedSeed = + typeof seed === 'string' && /^#[0-9a-fA-F]{6}$/.test(seed) + ? seed + : Palette.DEFAULT_SEED + seed = normalizedSeed.toUpperCase().substring(1, 7) const colorInt = parseInt('0xff' + seed, 16) let seedArgb diff --git a/src/state/persisted/__tests__/schema.test.ts b/src/state/persisted/__tests__/schema.test.ts new file mode 100644 index 000000000..7a3b38eca --- /dev/null +++ b/src/state/persisted/__tests__/schema.test.ts @@ -0,0 +1,44 @@ +import {defaults, tryParse, tryStringify} from '../schema' + +describe('persisted schema helpers', () => { + it('applies schema defaults when reading partial data', () => { + const parsed = tryParse( + JSON.stringify({ + colorMode: 'system', + darkTheme: 'dim', + colorScheme: 'material3', + hue: 0, + session: {accounts: []}, + reminders: {}, + languagePrefs: defaults.languagePrefs, + requireAltTextEnabled: true, + invites: {copiedInvites: []}, + onboarding: {step: 'Home'}, + mutedThreads: [], + translationServicePreference: 'google', + postReplacement: { + enabled: false, + postName: 'skeet', + postsName: 'skeets', + }, + }), + ) + + expect(parsed?.material3Accent).toBe('#ee6300') + expect(parsed?.material3Style).toBe('TONAL_SPOT') + }) + + it('writes schema defaults back into storage payloads', () => { + const raw = tryStringify({ + ...defaults, + material3Accent: undefined as never, + material3Style: undefined as never, + }) + + expect(raw).toBeDefined() + + const reparsed = JSON.parse(raw!) + expect(reparsed.material3Accent).toBe('#ee6300') + expect(reparsed.material3Style).toBe('TONAL_SPOT') + }) +}) diff --git a/src/state/persisted/schema.ts b/src/state/persisted/schema.ts index dd50fe8cc..074c8e539 100644 --- a/src/state/persisted/schema.ts +++ b/src/state/persisted/schema.ts @@ -394,7 +394,7 @@ export function tryParse(rawData: string): Schema | undefined { } const parsed = schema.safeParse(objData) if (parsed.success) { - return objData + return parsed.data } else { const errors = parsed.error?.errors?.map(e => ({ @@ -410,8 +410,8 @@ export function tryParse(rawData: string): Schema | undefined { export function tryStringify(value: Schema): string | undefined { try { - schema.parse(value) - return JSON.stringify(value) + const parsed = schema.parse(value) + return JSON.stringify(parsed) } catch (e) { logger.error(`persisted state: failed stringifying root state`, { message: e,