From 2e520137acf1530a6cb721af4d744900d3eedb78 Mon Sep 17 00:00:00 2001 From: Davide Scaini Date: Sat, 25 Apr 2026 15:45:27 +0200 Subject: [PATCH] fix: palette changes now propagate immediately via ThemeContext Replace useSetting()-based useTheme() with a React context (ThemeProvider + useTheme/usePaletteControl). The context holds palette key in state so pressing a palette button in Settings re-renders all screens instantly. Persists to SQLite and reloads the stored value on mount. --- mobile/ThemeContext.tsx | 51 ++++++++++++++++++++++++++++++++++ mobile/app/(tabs)/settings.tsx | 11 +++----- mobile/app/_layout.tsx | 7 +++-- mobile/theme.ts | 7 ----- 4 files changed, 60 insertions(+), 16 deletions(-) create mode 100644 mobile/ThemeContext.tsx diff --git a/mobile/ThemeContext.tsx b/mobile/ThemeContext.tsx new file mode 100644 index 0000000..51f05b6 --- /dev/null +++ b/mobile/ThemeContext.tsx @@ -0,0 +1,51 @@ +import { createContext, useContext, useEffect, useState } from 'react'; +import { useSQLiteContext } from 'expo-sqlite'; +import { getSetting, setSetting } from '@/db/queries'; +import { autoKey, PALETTES, type PaletteKey, type Theme } from '@/theme'; + +type ThemeCtx = { + theme: Theme; + paletteKey: PaletteKey; + setPaletteOverride: (key: PaletteKey) => void; +}; + +const ThemeContext = createContext({ + theme: PALETTES.default, + paletteKey: 'auto', + setPaletteOverride: () => {}, +}); + +export function ThemeProvider({ children }: { children: React.ReactNode }) { + const db = useSQLiteContext(); + const [paletteKey, setPaletteKey] = useState('auto'); + + useEffect(() => { + getSetting(db, 'palette_override').then(val => { + if (val) setPaletteKey(val as PaletteKey); + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + function setPaletteOverride(key: PaletteKey) { + setPaletteKey(key); + setSetting(db, 'palette_override', key); + } + + const resolved = paletteKey === 'auto' ? autoKey() : paletteKey; + const theme = PALETTES[resolved as keyof typeof PALETTES] ?? PALETTES.default; + + return ( + + {children} + + ); +} + +export function useTheme(): Theme { + return useContext(ThemeContext).theme; +} + +export function usePaletteControl(): Pick { + const { paletteKey, setPaletteOverride } = useContext(ThemeContext); + return { paletteKey, setPaletteOverride }; +} diff --git a/mobile/app/(tabs)/settings.tsx b/mobile/app/(tabs)/settings.tsx index 7432553..f265b20 100644 --- a/mobile/app/(tabs)/settings.tsx +++ b/mobile/app/(tabs)/settings.tsx @@ -5,7 +5,8 @@ import { Text, TextInput, View, } from 'react-native'; import { deleteRemoteActivities, getSetting, setSetting, useSetting } from '@/db/queries'; -import { PALETTES, type PaletteKey, useTheme } from '@/theme'; +import { PALETTES, type PaletteKey } from '@/theme'; +import { useTheme, usePaletteControl } from '@/ThemeContext'; export default function SettingsScreen() { const db = useSQLiteContext(); @@ -24,8 +25,7 @@ export default function SettingsScreen() { const [syncUpload, setSyncUpload] = useState(storedSyncUpload); const [saved, setSaved] = useState(false); const theme = useTheme(); - const storedPalette = (useSetting('palette_override') ?? 'auto') as PaletteKey; - const [palette, setPalette] = useState(storedPalette); + const { paletteKey: palette, setPaletteOverride } = usePaletteControl(); const [password, setPassword] = useState(''); const [connecting, setConnecting] = useState(false); @@ -225,10 +225,7 @@ export default function SettingsScreen() { active={palette === key} accent={keyAccent} dim={keyDim} - onPress={() => { - setPalette(key); - setSetting(db, 'palette_override', key); - }} + onPress={() => setPaletteOverride(key)} /> ); })} diff --git a/mobile/app/_layout.tsx b/mobile/app/_layout.tsx index a2c9de5..a129049 100644 --- a/mobile/app/_layout.tsx +++ b/mobile/app/_layout.tsx @@ -2,12 +2,15 @@ import { Stack } from 'expo-router'; import { SQLiteProvider } from 'expo-sqlite'; import { StatusBar } from 'expo-status-bar'; import { migrateDb } from '@/db'; +import { ThemeProvider } from '@/ThemeContext'; export default function RootLayout() { return ( - - + + + + ); } diff --git a/mobile/theme.ts b/mobile/theme.ts index 3516a73..a0963ab 100644 --- a/mobile/theme.ts +++ b/mobile/theme.ts @@ -1,5 +1,3 @@ -import { useSetting } from '@/db/queries'; - export type PaletteKey = 'auto' | 'default' | 'giro' | 'tour' | 'vuelta'; export const PALETTES = { @@ -29,8 +27,3 @@ export function autoKey(): Exclude { return 'default'; } -export function useTheme(): Theme { - const override = (useSetting('palette_override') ?? 'auto') as PaletteKey; - const key = override === 'auto' ? autoKey() : override; - return PALETTES[key as keyof typeof PALETTES] ?? PALETTES.default; -}