From a88ac217c2f21accd964703fecf4e6e3f92a8033 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 14 Sep 2023 12:55:47 -0500 Subject: [PATCH 1/4] fix theme switching on web without refresh --- src/lib/ThemeContext.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib/ThemeContext.tsx b/src/lib/ThemeContext.tsx index fe25dde5..a8208852 100644 --- a/src/lib/ThemeContext.tsx +++ b/src/lib/ThemeContext.tsx @@ -1,3 +1,4 @@ +import {isWeb} from 'platform/detection' import React, {ReactNode, createContext, useContext} from 'react' import { AppState, @@ -101,6 +102,10 @@ export const ThemeProvider: React.FC = ({ React.useState(colorSchemeFromRN) React.useEffect(() => { + if (isWeb) { + setNativeColorScheme(colorSchemeFromRN) + } + const subscription = AppState.addEventListener('change', state => { const isActive = state === 'active' From 9a86f0dae4987f0398ff2a166753992a70bfb327 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 14 Sep 2023 13:23:20 -0500 Subject: [PATCH 2/4] simplify logic --- src/lib/ThemeContext.tsx | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/lib/ThemeContext.tsx b/src/lib/ThemeContext.tsx index a8208852..76e70918 100644 --- a/src/lib/ThemeContext.tsx +++ b/src/lib/ThemeContext.tsx @@ -93,37 +93,32 @@ export const ThemeContext = createContext(defaultTheme) export const useTheme = () => useContext(ThemeContext) +const getTheme = (theme: ColorSchemeName) => + theme === 'dark' ? darkTheme : defaultTheme + export const ThemeProvider: React.FC = ({ theme, children, }) => { const colorSchemeFromRN = useColorScheme() - const [nativeColorScheme, setNativeColorScheme] = + const [statefulColorScheme, setStatefulColorScheme] = React.useState(colorSchemeFromRN) + const colorScheme = isWeb ? colorSchemeFromRN : statefulColorScheme + const themeValue = getTheme(theme === 'system' ? colorScheme : theme) React.useEffect(() => { - if (isWeb) { - setNativeColorScheme(colorSchemeFromRN) - } - + if (!isWeb) return const subscription = AppState.addEventListener('change', state => { const isActive = state === 'active' if (!isActive) return - setNativeColorScheme(colorSchemeFromRN) + setStatefulColorScheme(colorSchemeFromRN) }) return () => subscription.remove() }, [colorSchemeFromRN]) - const value = - theme === 'system' - ? nativeColorScheme === 'dark' - ? darkTheme - : defaultTheme - : theme === 'dark' - ? darkTheme - : defaultTheme - - return {children} + return ( + {children} + ) } From 01870883d6062c43d275cad0d5d2012cf643df93 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 14 Sep 2023 18:15:17 -0500 Subject: [PATCH 3/4] clean up into hook --- src/lib/ThemeContext.tsx | 43 ++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/lib/ThemeContext.tsx b/src/lib/ThemeContext.tsx index 76e70918..f77b5515 100644 --- a/src/lib/ThemeContext.tsx +++ b/src/lib/ThemeContext.tsx @@ -3,7 +3,7 @@ import React, {ReactNode, createContext, useContext} from 'react' import { AppState, TextStyle, - useColorScheme, + useColorScheme as useColorScheme_BUGGY, ViewStyle, ColorSchemeName, } from 'react-native' @@ -93,31 +93,36 @@ export const ThemeContext = createContext(defaultTheme) export const useTheme = () => useContext(ThemeContext) -const getTheme = (theme: ColorSchemeName) => - theme === 'dark' ? darkTheme : defaultTheme +function getTheme(theme: ColorSchemeName) { + return theme === 'dark' ? darkTheme : defaultTheme +} + +function useColorScheme_FIXED() { + const colorScheme = useColorScheme_BUGGY() + const [currentColorScheme, setCurrentColorScheme] = + React.useState(colorScheme) + + React.useEffect(() => { + // we don't need to be updating state on web + if (isWeb) return + const subscription = AppState.addEventListener('change', state => { + const isActive = state === 'active' + if (!isActive) return + setCurrentColorScheme(colorScheme) + }) + return () => subscription.remove() + }, [colorScheme]) + + return isWeb ? colorScheme : currentColorScheme +} export const ThemeProvider: React.FC = ({ theme, children, }) => { - const colorSchemeFromRN = useColorScheme() - const [statefulColorScheme, setStatefulColorScheme] = - React.useState(colorSchemeFromRN) - const colorScheme = isWeb ? colorSchemeFromRN : statefulColorScheme + const colorScheme = useColorScheme_FIXED() const themeValue = getTheme(theme === 'system' ? colorScheme : theme) - React.useEffect(() => { - if (!isWeb) return - const subscription = AppState.addEventListener('change', state => { - const isActive = state === 'active' - - if (!isActive) return - - setStatefulColorScheme(colorSchemeFromRN) - }) - return () => subscription.remove() - }, [colorSchemeFromRN]) - return ( {children} ) From 0e8d564555d23bb2161fd8c96c3eef5bb7f04889 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 15 Sep 2023 11:00:06 -0500 Subject: [PATCH 4/4] link out to more context --- src/lib/ThemeContext.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib/ThemeContext.tsx b/src/lib/ThemeContext.tsx index f77b5515..483c50c4 100644 --- a/src/lib/ThemeContext.tsx +++ b/src/lib/ThemeContext.tsx @@ -97,6 +97,13 @@ function getTheme(theme: ColorSchemeName) { return theme === 'dark' ? darkTheme : defaultTheme } +/** + * With RN iOS, we can only "trust" the color scheme reported while the app is + * active. This is a workaround until the bug is fixed upstream. + * + * @see https://github.com/bluesky-social/social-app/pull/1417#issuecomment-1719868504 + * @see https://github.com/facebook/react-native/pull/39439 + */ function useColorScheme_FIXED() { const colorScheme = useColorScheme_BUGGY() const [currentColorScheme, setCurrentColorScheme] =