import AsyncStorage from '@react-native-async-storage/async-storage'; import React, { createContext, useCallback, useContext, useEffect, useState, type ReactNode } from 'react'; import { useColorScheme as useSystemColorScheme } from 'react-native'; export type ThemeMode = 'light' | 'dark' | 'system'; export type ResolvedTheme = 'light' | 'dark'; const THEME_STORAGE_KEY = '@wellnuo:theme_preference'; interface ThemeContextType { themeMode: ThemeMode; resolvedTheme: ResolvedTheme; isDark: boolean; setThemeMode: (mode: ThemeMode) => Promise; toggleTheme: () => Promise; } const ThemeContext = createContext(null); export function ThemeProvider({ children }: { children: ReactNode }) { const systemColorScheme = useSystemColorScheme(); const [themeMode, setThemeModeState] = useState('system'); const [isLoaded, setIsLoaded] = useState(false); // Load saved theme preference on mount useEffect(() => { const loadThemePreference = async () => { try { const savedTheme = await AsyncStorage.getItem(THEME_STORAGE_KEY); if (savedTheme && (savedTheme === 'light' || savedTheme === 'dark' || savedTheme === 'system')) { setThemeModeState(savedTheme as ThemeMode); } } catch (error) { console.warn('Failed to load theme preference:', error); } finally { setIsLoaded(true); } }; loadThemePreference(); }, []); // Resolve the actual theme based on mode and system preference const resolvedTheme: ResolvedTheme = themeMode === 'system' ? (systemColorScheme === 'dark' ? 'dark' : 'light') : themeMode; const isDark = resolvedTheme === 'dark'; // Set theme mode and persist to storage const setThemeMode = useCallback(async (mode: ThemeMode) => { try { await AsyncStorage.setItem(THEME_STORAGE_KEY, mode); setThemeModeState(mode); } catch (error) { console.warn('Failed to save theme preference:', error); // Still update state even if storage fails setThemeModeState(mode); } }, []); // Toggle between light and dark (skips system) const toggleTheme = useCallback(async () => { const newMode: ThemeMode = resolvedTheme === 'light' ? 'dark' : 'light'; await setThemeMode(newMode); }, [resolvedTheme, setThemeMode]); // Prevent flash by not rendering until theme is loaded if (!isLoaded) { return null; } return ( {children} ); } export function useTheme() { const context = useContext(ThemeContext); if (!context) { throw new Error('useTheme must be used within a ThemeProvider'); } return context; } // For components that need optional theme access (during initialization) export function useThemeOptional() { return useContext(ThemeContext); }