feat: ThemeContext

This commit is contained in:
Jakob Stornig 2023-12-17 19:24:33 +01:00
parent 4226bd515f
commit b5613c6e18
4 changed files with 134 additions and 2 deletions

View file

@ -1,7 +1,8 @@
import { Slot } from 'expo-router';
import React, { useEffect } from 'react';
import { initDatabase } from '../services/database';
import { addCategory, initDatabase } from '../services/database';
import { AuthProvider } from './contexts/AuthContext';
import { ThemeProvider } from './contexts/ThemeContext';
export default function _layout() {
@ -12,7 +13,9 @@ export default function _layout() {
console.log("layout called")
return (
<AuthProvider>
<Slot />
<ThemeProvider>
<Slot />
</ThemeProvider>
</AuthProvider>
)
}

View file

@ -0,0 +1,97 @@
import {useContext, createContext, useState, useEffect} from "react"
import AsyncStorage from "@react-native-async-storage/async-storage"
import { useColorScheme } from "react-native";
import themeColors from "../../constants/colors";
interface ThemeProps {
isSystemTheme?: boolean
theme: "light" | "dark";
colors: typeof themeColors.light & typeof themeColors.dark;
applySystemTheme?: () => void;
applyTheme?: (theme: "light" | "dark") => void;
}
const THEME_KEY = "THEME"
const SYSTEM_THEME_KEY = "SYSTEM_THEME"
const ThemeContext = createContext<ThemeProps>({theme: "light", colors: themeColors.light})
export const useTheme = () => {
return useContext(ThemeContext)
}
export const ThemeProvider = ({children} : any) => {
const currentSystemTheme = useColorScheme()
const [isSystemTheme, setIsSystemTheme] = useState<boolean>(true);
const [theme, setTheme] = useState<"light" | "dark">("light");
const [colors, setColors] = useState<typeof themeColors.light & typeof themeColors.dark>(themeColors.light)
useEffect(() => {
console.log("effect called")
const loadTheme = async () => {
try {
const is_system_theme = await AsyncStorage.getItem(SYSTEM_THEME_KEY)
const saved_theme = await AsyncStorage.getItem(THEME_KEY);
if(is_system_theme !== "false"){//We will use !== false bacause system theme should be used if unspecified
applySystemTheme();
return;
}
if(saved_theme === "light" || saved_theme === "dark"){
applyTheme(saved_theme);
}
} catch (error) {
console.error(error)
}
}
loadTheme();
}, [currentSystemTheme])
const applySystemTheme = () => {
const storeSystemTheme = async () => {
console.log("applySystemTheme")
await AsyncStorage.setItem(SYSTEM_THEME_KEY, "true")
}
storeSystemTheme();
setIsSystemTheme(true)
applyThemeInternal(currentSystemTheme ?? "light")
}
const applyThemeInternal = (theme: "light" | "dark") => {
const storeTheme = async (theme: "light" | "dark") => {
await AsyncStorage.setItem(THEME_KEY, theme)
}
setTheme(theme);
storeTheme(theme);
setColors(themeColors[theme])
}
const applyTheme = (theme: "light" | "dark") => {
const unsetSytemTheme = async () => {
AsyncStorage.setItem(SYSTEM_THEME_KEY, "false");
}
unsetSytemTheme()
setIsSystemTheme(false);
applyThemeInternal(theme);
}
const value = {
isSystemTheme: isSystemTheme,
applyTheme: applyTheme,
applySystemTheme: applySystemTheme,
theme: theme,
colors: colors,
}
return (
<ThemeContext.Provider value={value}>
{children}
</ThemeContext.Provider>
)
}

31
package-lock.json generated
View file

@ -9,6 +9,7 @@
"version": "1.0.0",
"dependencies": {
"@expo/vector-icons": "^13.0.0",
"@react-native-async-storage/async-storage": "1.18.2",
"@react-navigation/native": "^6.0.2",
"expo": "~49.0.15",
"expo-font": "~11.4.0",
@ -4277,6 +4278,17 @@
"react": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@react-native-async-storage/async-storage": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.18.2.tgz",
"integrity": "sha512-dM8AfdoeIxlh+zqgr0o5+vCTPQ0Ru1mrPzONZMsr7ufp5h+6WgNxQNza7t0r5qQ6b04AJqTlBNixTWZxqP649Q==",
"dependencies": {
"merge-options": "^3.0.4"
},
"peerDependencies": {
"react-native": "^0.0.0-0 || 0.60 - 0.72 || 1000.0.0"
}
},
"node_modules/@react-native-community/cli": {
"version": "11.3.7",
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-11.3.7.tgz",
@ -13452,6 +13464,25 @@
"resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz",
"integrity": "sha512-OcjA+jzjOYzKmKS6IQVALHLVz+rNTMPoJvCztFaZxwG14wtAW7VRZjwTQu06vKCYOxh4jVnik7ya0SXTB0W+xA=="
},
"node_modules/merge-options": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz",
"integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
"dependencies": {
"is-plain-obj": "^2.1.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/merge-options/node_modules/is-plain-obj": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
"engines": {
"node": ">=8"
}
},
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",

View file

@ -19,6 +19,7 @@
},
"dependencies": {
"@expo/vector-icons": "^13.0.0",
"@react-native-async-storage/async-storage": "1.18.2",
"@react-navigation/native": "^6.0.2",
"expo": "~49.0.15",
"expo-font": "~11.4.0",