From ced40c7e5cf5b1b707cf96182576d90f36e32737 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Sat, 31 Oct 2026 01:32:29 +0100 Subject: [PATCH] feat: keep list rows plain instead of tinting them by tag by default --- .../__tests__/settings-tint-list-rows.test.ts | 46 +++++++++++++++++++ stores/settings-store.ts | 23 ++++++++-- 2 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 stores/__tests__/settings-tint-list-rows.test.ts diff --git a/stores/__tests__/settings-tint-list-rows.test.ts b/stores/__tests__/settings-tint-list-rows.test.ts new file mode 100644 index 000000000..adc6ca433 --- /dev/null +++ b/stores/__tests__/settings-tint-list-rows.test.ts @@ -0,0 +1,46 @@ +import { beforeEach, describe, it, expect } from 'vitest'; +import { useSettingsStore, migrateSettings } from '../settings-store'; + +// List rows are plain by default; tinting them by the first tag color was +// the default before. + +const migrate = (state: Record, version: number) => + migrateSettings(state, version) as unknown as Record; + +describe('tint list rows by tag default', () => { + beforeEach(() => { + useSettingsStore.getState().resetToDefaults(); + }); + + it('keeps rows plain on a fresh install', () => { + expect(useSettingsStore.getState().tintListRowsByTag).toBe(false); + }); + + it('turns off a tint the user never switched on', () => { + expect(migrate({ tintListRowsByTag: true, explicitSettings: [] }, 10).tintListRowsByTag).toBe(false); + }); + + it('keeps a tint the user switched on', () => { + const out = migrate({ tintListRowsByTag: true, explicitSettings: ['tintListRowsByTag'] }, 10); + expect(out.tintListRowsByTag).toBe(true); + }); + + it('does not take the tint from before explicitSettings existed as chosen', () => { + const out = migrate({ tintListRowsByTag: true }, 7); + expect(out.tintListRowsByTag).toBe(false); + expect(out.explicitSettings).not.toContain('tintListRowsByTag'); + }); + + it('turns the tint off in a server copy or export from an older build', () => { + const store = useSettingsStore.getState(); + expect(store.importSettings(JSON.stringify({ tintListRowsByTag: true, explicitSettings: [] }))).toBe(true); + expect(useSettingsStore.getState().tintListRowsByTag).toBe(false); + + expect(store.importSettings(JSON.stringify({ tintListRowsByTag: true }))).toBe(true); + expect(useSettingsStore.getState().tintListRowsByTag).toBe(false); + expect(useSettingsStore.getState().explicitSettings).not.toContain('tintListRowsByTag'); + + expect(store.importSettings(JSON.stringify({ tintListRowsByTag: true, explicitSettings: ['tintListRowsByTag'] }))).toBe(true); + expect(useSettingsStore.getState().tintListRowsByTag).toBe(true); + }); +}); diff --git a/stores/settings-store.ts b/stores/settings-store.ts index 810d45a85..8c9a9d591 100644 --- a/stores/settings-store.ts +++ b/stores/settings-store.ts @@ -984,7 +984,7 @@ const DEFAULT_SETTINGS = { // Sidebar colorfulSidebarIcons: true, - tintListRowsByTag: true, + tintListRowsByTag: false, tintListRowsByAccount: false, showAccountDot: true, showFolderTotalCount: true, @@ -1496,6 +1496,7 @@ export const useSettingsStore = create()( } migrateAnimationsSetting(settings); migrateNotificationSoundDefault(settings); + migrateTintListRowsDefault(settings); // Apply settings, noting which keys were taken over for the // onSettingsImport hook. @@ -1897,7 +1898,7 @@ export const useSettingsStore = create()( }, { name: 'settings-storage', - version: 10, + version: 11, migrate: migrateSettings, onRehydrateStorage: () => { return (state) => { @@ -1995,9 +1996,11 @@ export function migrateSettings(persisted: unknown, version: number): SettingsSt if (version < 6 || !isPlainRecord(state.preferredIdentityIds)) { state.preferredIdentityIds = {}; } - // Before the v8 step: a beep from before explicitSettings existed was - // the default then, and must not be taken as chosen below. + // Before the v8 step: a beep or a tinted list from before + // explicitSettings existed was the default then, and must not be + // taken as chosen below. migrateNotificationSoundDefault(state); + migrateTintListRowsDefault(state); // v8: admin policy defaults (#1248) skip settings the user chose. // Earlier builds did not record that, so a setting that differs from // the build default is taken as chosen. @@ -2036,6 +2039,18 @@ export function migrateNotificationSoundDefault(state: Record): if (!chosen) state.notificationSoundChoice = 'involved'; } +/** + * v11: list rows no longer take their first tag's color by default. A tint + * the user never switched on was only the old default and goes; one they + * switched on stays. Imports and server copies from older builds still + * carry the tint and go through this too. + */ +export function migrateTintListRowsDefault(state: Record): void { + if (state.tintListRowsByTag !== true) return; + const chosen = Array.isArray(state.explicitSettings) && state.explicitSettings.includes('tintListRowsByTag'); + if (!chosen) state.tintListRowsByTag = false; +} + // Helper functions to apply settings to DOM /** The settings applyAccessibilityTo() writes onto . */