From 02d725687f85b6a1a532b8da4e4a3adcc15afb1b Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 2 Apr 2026 04:19:39 +0000 Subject: [PATCH 1/2] Fix mobile dark mode not activating when theme is set to auto The selector fallback derived system appearance from the stored theme value instead of querying the actual device appearance. When theme was AUTO, `theme === Theme.DARK` evaluated to false, always defaulting to light. Additionally, replaced react-native-dynamic's useDarkMode with React Native's built-in useColorScheme for more reliable appearance detection. https://claude.ai/code/session_01UTyTyh99xC4WeohtPJWtVF --- packages/mobile/src/app/ThemeProvider.tsx | 48 +++++++++---------- .../sign-on-screen/screens/SignOnScreen.tsx | 6 +-- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/packages/mobile/src/app/ThemeProvider.tsx b/packages/mobile/src/app/ThemeProvider.tsx index 29190c1b0ba..5acc449e796 100644 --- a/packages/mobile/src/app/ThemeProvider.tsx +++ b/packages/mobile/src/app/ThemeProvider.tsx @@ -11,8 +11,7 @@ import { import { themeActions, themeSelectors } from '@audius/common/store' import type { Nullable } from '@audius/common/utils' import AsyncStorage from '@react-native-async-storage/async-storage' -import { useAppState } from '@react-native-community/hooks' -import { useDarkMode } from 'react-native-dynamic' +import { Appearance, useColorScheme } from 'react-native' import { useDispatch, useSelector } from 'react-redux' import { useAsync } from 'react-use' @@ -82,7 +81,9 @@ const selectHarmonyTheme = (state: AppState): HarmonyThemeName => { : ThemeMode.AUTO) const sysAppearance = systemAppearance ?? - (theme === Theme.DARK ? SystemAppearance.DARK : SystemAppearance.LIGHT) + (Appearance.getColorScheme() === 'dark' + ? SystemAppearance.DARK + : SystemAppearance.LIGHT) return resolveToHarmonyTheme(themePalette, mode, sysAppearance) } @@ -95,22 +96,24 @@ const selectHarmonyTheme = (state: AppState): HarmonyThemeName => { case Theme.MATRIX: return 'matrix' case Theme.AUTO: - default: - switch (systemAppearance) { - case SystemAppearance.DARK: - return 'default-dark' - case SystemAppearance.LIGHT: - default: - return 'default-light' - } + default: { + const resolvedAppearance = + systemAppearance ?? + (Appearance.getColorScheme() === 'dark' + ? SystemAppearance.DARK + : SystemAppearance.LIGHT) + return resolvedAppearance === SystemAppearance.DARK + ? 'default-dark' + : 'default-light' + } } } export const ThemeProvider = (props: ThemeProviderProps) => { const { children } = props - const isDarkMode = useDarkMode() + const colorScheme = useColorScheme() + const isDarkMode = colorScheme === 'dark' const dispatch = useDispatch() - const appState = useAppState() const theme = useSelector(selectHarmonyTheme) useAsync(async () => { @@ -160,17 +163,14 @@ export const ThemeProvider = (props: ThemeProviderProps) => { }, [dispatch]) useEffect(() => { - // react-native-dynamic incorrectly sets dark-mode when in background - if (appState === 'active') { - dispatch( - setSystemAppearance({ - systemAppearance: isDarkMode - ? SystemAppearance.DARK - : SystemAppearance.LIGHT - }) - ) - } - }, [isDarkMode, dispatch, appState]) + dispatch( + setSystemAppearance({ + systemAppearance: isDarkMode + ? SystemAppearance.DARK + : SystemAppearance.LIGHT + }) + ) + }, [isDarkMode, dispatch]) return ( {children} diff --git a/packages/mobile/src/screens/sign-on-screen/screens/SignOnScreen.tsx b/packages/mobile/src/screens/sign-on-screen/screens/SignOnScreen.tsx index ed0229ae8b2..218e06ddd20 100644 --- a/packages/mobile/src/screens/sign-on-screen/screens/SignOnScreen.tsx +++ b/packages/mobile/src/screens/sign-on-screen/screens/SignOnScreen.tsx @@ -8,7 +8,7 @@ import { updateRouteOnCompletion, setValueField } from 'common/store/pages/signon/actions' -import { useDarkMode } from 'react-native-dynamic' +import { useColorScheme } from 'react-native' import { useSafeAreaInsets } from 'react-native-safe-area-context' import { @@ -90,8 +90,8 @@ export const SignOnScreen = (props: SignOnScreenProps) => { setScreen(screenParam) }, [guestEmail, routeOnCompletion, screenParam]) - const isDarkMode = useDarkMode() - const signOnThemeName = isDarkMode ? 'default-dark' : 'default-light' + const colorScheme = useColorScheme() + const signOnThemeName = colorScheme === 'dark' ? 'default-dark' : 'default-light' if (!isSplashScreenDismissed) return null From 0f4763bc1a2bed117c6e8202d265809a9d4a0293 Mon Sep 17 00:00:00 2001 From: Dylan Jeffers Date: Wed, 1 Apr 2026 22:04:54 -0700 Subject: [PATCH 2/2] Fix lint --- .../mobile/src/screens/sign-on-screen/screens/SignOnScreen.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/mobile/src/screens/sign-on-screen/screens/SignOnScreen.tsx b/packages/mobile/src/screens/sign-on-screen/screens/SignOnScreen.tsx index 218e06ddd20..42d6bafb8c8 100644 --- a/packages/mobile/src/screens/sign-on-screen/screens/SignOnScreen.tsx +++ b/packages/mobile/src/screens/sign-on-screen/screens/SignOnScreen.tsx @@ -91,7 +91,8 @@ export const SignOnScreen = (props: SignOnScreenProps) => { }, [guestEmail, routeOnCompletion, screenParam]) const colorScheme = useColorScheme() - const signOnThemeName = colorScheme === 'dark' ? 'default-dark' : 'default-light' + const signOnThemeName = + colorScheme === 'dark' ? 'default-dark' : 'default-light' if (!isSplashScreenDismissed) return null