diff --git a/app/_layout.tsx b/app/_layout.tsx index 25f4a13..f1ea3c4 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -41,8 +41,8 @@ export const unstable_settings = { }; export default function RootLayout() { - const { isDarkColorScheme } = useColorScheme(); - const [fontsLoaded, setFontsLoaded] = React.useState(false); + const { isDarkColorScheme, setColorScheme } = useColorScheme(); + const [resourcesLoaded, setResourcesLoaded] = React.useState(false); useConnectionChecker(); @@ -53,8 +53,6 @@ export default function RootLayout() { "OpenRunde-Semibold": require("./../assets/fonts/OpenRunde-Semibold.otf"), "OpenRunde-Bold": require("./../assets/fonts/OpenRunde-Bold.otf"), }); - - setFontsLoaded(true); } async function checkBiometricStatus() { @@ -64,19 +62,28 @@ export default function RootLayout() { } } + const loadTheme = React.useCallback((): Promise => { + return new Promise((resolve) => { + const theme = useAppStore.getState().theme; + setColorScheme(theme); + resolve(); + }); + }, [setColorScheme]); + React.useEffect(() => { const init = async () => { try { - await Promise.all([loadFonts(), checkBiometricStatus()]); + await Promise.all([loadTheme(), loadFonts(), checkBiometricStatus()]); } finally { + setResourcesLoaded(true); SplashScreen.hideAsync(); } }; init(); - }, []); + }, [loadTheme]); - if (!fontsLoaded) { + if (!resourcesLoaded) { return null; } diff --git a/lib/state/appStore.ts b/lib/state/appStore.ts index 7284ba2..dfcc173 100644 --- a/lib/state/appStore.ts +++ b/lib/state/appStore.ts @@ -12,7 +12,9 @@ interface AppState { readonly addressBookEntries: AddressBookEntry[]; readonly isSecurityEnabled: boolean; readonly isOnboarded: boolean; + readonly theme: Theme; setUnlocked: (unlocked: boolean) => void; + setTheme: (theme: Theme) => void; setOnboarded: (isOnboarded: boolean) => void; setNWCClient: (nwcClient: NWCClient | undefined) => void; updateCurrentWallet(wallet: Partial): void; @@ -33,9 +35,12 @@ const selectedWalletIdKey = "selectedWalletId"; const fiatCurrencyKey = "fiatCurrency"; const hasOnboardedKey = "hasOnboarded"; const lastAlbyPaymentKey = "lastAlbyPayment"; -export const isSecurityEnabledKey = "isSecurityEnabled"; +const themeKey = "theme"; +const isSecurityEnabledKey = "isSecurityEnabled"; export const lastActiveTimeKey = "lastActiveTime"; +export type Theme = "system" | "light" | "dark"; + type Wallet = { name?: string; nostrWalletConnectUrl?: string; @@ -139,17 +144,20 @@ export const useAppStore = create()((set, get) => { secureStorage.getItem(selectedWalletIdKey) || "0" ); - const iSecurityEnabled = + const isSecurityEnabled = secureStorage.getItem(isSecurityEnabledKey) === "true"; + const theme = (secureStorage.getItem(themeKey) as Theme) || "system"; + const initialWallets = loadWallets(); return { - unlocked: !iSecurityEnabled, + unlocked: !isSecurityEnabled, addressBookEntries: loadAddressBookEntries(), wallets: initialWallets, nwcClient: getNWCClient(initialSelectedWalletId), fiatCurrency: secureStorage.getItem(fiatCurrencyKey) || "", - isSecurityEnabled: iSecurityEnabled, + isSecurityEnabled, + theme, isOnboarded: secureStorage.getItem(hasOnboardedKey) === "true", selectedWalletId: initialSelectedWalletId, updateCurrentWallet, @@ -157,6 +165,10 @@ export const useAppStore = create()((set, get) => { setUnlocked: (unlocked) => { set({ unlocked }); }, + setTheme: (theme) => { + secureStorage.setItem(themeKey, theme); + set({ theme }); + }, setOnboarded: (isOnboarded) => { if (isOnboarded) { secureStorage.setItem(hasOnboardedKey, "true"); diff --git a/lib/useColorScheme.tsx b/lib/useColorScheme.tsx index df75499..a4a7e17 100644 --- a/lib/useColorScheme.tsx +++ b/lib/useColorScheme.tsx @@ -1,11 +1,23 @@ import { useColorScheme as useNativewindColorScheme } from "nativewind"; +import { useAppStore } from "~/lib/state/appStore"; export function useColorScheme() { - const { colorScheme, setColorScheme, toggleColorScheme } = - useNativewindColorScheme(); + const { + colorScheme, + setColorScheme, + toggleColorScheme: _toggleColorScheme, + } = useNativewindColorScheme(); + + const isDarkColorScheme = colorScheme === "dark"; + + const toggleColorScheme = () => { + _toggleColorScheme(); + useAppStore.getState().setTheme(isDarkColorScheme ? "light" : "dark"); + }; + return { colorScheme: colorScheme ?? "dark", - isDarkColorScheme: colorScheme === "dark", + isDarkColorScheme, setColorScheme, toggleColorScheme, };