feat: allow users to override color scheme (closes #138)

This commit is contained in:
Lei Nelissen
2023-04-28 21:01:21 +02:00
parent 24b25d9f4f
commit 130b18bc2e
20 changed files with 249 additions and 66 deletions

View File

@@ -1,18 +1,18 @@
import React, { useEffect } from 'react';
import React, { PropsWithChildren, useEffect } from 'react';
import { Provider } from 'react-redux';
import TrackPlayer, { Capability } from 'react-native-track-player';
import { PersistGate } from 'redux-persist/integration/react';
import Routes from '../screens';
import store, { persistedStore } from 'store';
import store, { persistedStore, useTypedSelector } from 'store';
import {
NavigationContainer,
DefaultTheme,
DarkTheme as BaseDarkTheme,
} from '@react-navigation/native';
import { useColorScheme } from 'react-native';
import { ColorSchemeContext, themes } from './Colors';
import { ColorSchemeProvider, themes } from './Colors';
import DownloadManager from './DownloadManager';
// import ErrorReportingAlert from 'utility/ErrorReportingAlert';
import { useColorScheme } from 'react-native';
import { ColorScheme } from 'store/settings/types';
const LightTheme = {
...DefaultTheme,
@@ -30,14 +30,29 @@ const DarkTheme = {
}
};
/**
* This is a convenience wrapper for NavigationContainer that ensures that the
* right theme is selected based on OS color scheme settings along with user preferences.
*/
function ThemedNavigationContainer({ children }: PropsWithChildren<{}>) {
const systemScheme = useColorScheme();
const userScheme = useTypedSelector((state) => state.settings.colorScheme);
const scheme = userScheme === ColorScheme.System ? systemScheme : userScheme;
return (
<NavigationContainer
theme={scheme === 'dark' ? DarkTheme : LightTheme}
>
{children}
</NavigationContainer>
);
}
// Track whether the player has already been setup, so that we don't
// accidentally do it twice.
let hasSetupPlayer = false;
export default function App(): JSX.Element {
const colorScheme = useColorScheme();
const theme = themes[colorScheme || 'light'];
useEffect(() => {
async function setupTrackPlayer() {
await TrackPlayer.setupPlayer();
@@ -63,14 +78,12 @@ export default function App(): JSX.Element {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistedStore}>
<ColorSchemeContext.Provider value={theme}>
<NavigationContainer
theme={colorScheme === 'dark' ? DarkTheme : LightTheme}
>
<ColorSchemeProvider>
<ThemedNavigationContainer>
<Routes />
<DownloadManager />
</NavigationContainer>
</ColorSchemeContext.Provider>
</ThemedNavigationContainer>
</ColorSchemeProvider>
</PersistGate>
</Provider>
);

View File

@@ -3,6 +3,8 @@ import { THEME_COLOR } from 'CONSTANTS';
import React, { PropsWithChildren } from 'react';
import { useContext } from 'react';
import { ColorSchemeName, Platform, StyleSheet, View, useColorScheme } from 'react-native';
import { useTypedSelector } from 'store';
import { ColorScheme } from 'store/settings/types';
const majorPlatformVersion = typeof Platform.Version === 'string' ? parseInt(Platform.Version, 10) : Platform.Version;
@@ -77,6 +79,22 @@ export const themes: Record<'dark' | 'light', ReturnType<typeof generateStyles>>
// Create context for supplying the theming information
export const ColorSchemeContext = React.createContext(themes.dark);
/**
* This provider contains the logic for settings the right theme on the ColorSchemeContext.
*/
export function ColorSchemeProvider({ children }: PropsWithChildren<{}>) {
const systemScheme = useColorScheme();
const userScheme = useTypedSelector((state) => state.settings.colorScheme);
const scheme = userScheme === ColorScheme.System ? systemScheme : userScheme;
const theme = themes[scheme || 'light'];
return (
<ColorSchemeContext.Provider value={theme}>
{children}
</ColorSchemeContext.Provider>
);
}
/**
* Retrieves the default styles object in hook form
*/
@@ -98,13 +116,15 @@ export function DefaultStylesProvider(props: DefaultStylesProviderProps) {
}
export function ColoredBlurView(props: PropsWithChildren<BlurViewProps>) {
const scheme = useColorScheme();
const systemScheme = useColorScheme();
const userScheme = useTypedSelector((state) => state.settings.colorScheme);
const scheme = userScheme === ColorScheme.System ? systemScheme : userScheme;
return Platform.OS === 'ios' ? (
<BlurView
{...props}
blurType={Platform.OS === 'ios' && majorPlatformVersion >= 13
? 'material'
? scheme === 'dark' ? 'materialDark' : 'materialLight'
: scheme === 'dark' ? 'extraDark' : 'xlight'
} />
) : (