import React, { createContext, useContext, useState, useEffect, useMemo } from 'react'; import { useColorScheme } from 'react-native'; import { getTheme } from '../constants/theme'; import type { Theme, ThemeVariant } from '../constants/theme'; export type ColorMode = 'system' | 'light' | 'dark'; export type ContrastLevel = 1 | 2 | 3 | 4 | 5; type ColorType = 'text' | 'primary' | 'background'; // Hilfsfunktion zum Konvertieren von Hex zu RGB const hexToRgb = (hex: string) => { const h = hex.replace('#', ''); return { r: parseInt(h.substr(0, 2), 16), g: parseInt(h.substr(2, 2), 16), b: parseInt(h.substr(4, 2), 16), }; }; // Hilfsfunktion zum Konvertieren von RGB zu Hex mit Alpha const rgbaToHex = (r: number, g: number, b: number, a = 1) => { const alpha = Math.round(a * 255); return ( '#' + [r, g, b, alpha] .map((x) => { const hex = Math.round(Math.max(0, Math.min(255, x))).toString(16); return hex.length === 1 ? '0' + hex : hex; }) .join('') ); }; // Funktion zum Anpassen des Kontrasts const adjustContrast = ( color: string, level: ContrastLevel, type: ColorType, isDark: boolean ): string => { if (level === 3) return color; const { r, g, b } = hexToRgb(color); if (level < 3) { // Niedrigerer Kontrast: Nur Text-Opacity wird reduziert if (type === 'text') { const opacity = 0.5 + (level - 1) * 0.25; // 0.5 für Level 1, 0.75 für Level 2 return rgbaToHex(r, g, b, opacity); } return color; } else { // Höherer Kontrast: Nur Hintergründe werden angepasst if (type === 'background') { const factor = (level - 3) * 0.45; // 0.45 für Level 4, 0.9 für Level 5 if (isDark) { // Im Dark Mode: Hintergründe werden schwärzer return rgbaToHex( Math.round(r * (1 - factor)), Math.round(g * (1 - factor)), Math.round(b * (1 - factor)) ); } else { // Im Light Mode: Hintergründe werden weißer return rgbaToHex( Math.round(r + (255 - r) * factor), Math.round(g + (255 - g) * factor), Math.round(b + (255 - b) * factor) ); } } return color; } }; const adjustThemeContrast = (theme: Theme, level: ContrastLevel, isDark: boolean): Theme => { if (level === 3) return theme; const adjustedColors = Object.entries(theme.colors).reduce( (acc, [key, value]) => { if (typeof value === 'string' && value.startsWith('#')) { let colorType: ColorType = 'background'; if (key.toLowerCase().includes('text')) { colorType = 'text'; } else if (key.toLowerCase().includes('primary')) { colorType = 'primary'; } acc[key] = adjustContrast(value, level, colorType, isDark); } else { acc[key] = value; } return acc; }, {} as Record ); return { ...theme, colors: adjustedColors, }; }; type ThemeContextType = { theme: Theme; isDark: boolean; colorMode: ColorMode; setColorMode: (mode: ColorMode) => void; themeVariant: ThemeVariant; setThemeVariant: (variant: ThemeVariant) => void; contrastLevel: ContrastLevel; setContrastLevel: (level: ContrastLevel) => void; }; const ThemeContext = createContext({ theme: getTheme('light'), isDark: false, colorMode: 'system', setColorMode: () => {}, themeVariant: 'default', setThemeVariant: () => {}, contrastLevel: 3, setContrastLevel: () => {}, }); export const useTheme = () => useContext(ThemeContext); export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const systemColorScheme = useColorScheme(); const [colorMode, setColorMode] = useState('system'); const [themeVariant, setThemeVariant] = useState('default'); const [contrastLevel, setContrastLevel] = useState(3); const isDark = useMemo(() => { if (colorMode === 'system') { return systemColorScheme === 'dark'; } return colorMode === 'dark'; }, [colorMode, systemColorScheme]); const theme = useMemo(() => { const baseTheme = getTheme(isDark ? 'dark' : 'light', themeVariant); return adjustThemeContrast(baseTheme, contrastLevel, isDark); }, [isDark, themeVariant, contrastLevel]); const contextValue = useMemo( () => ({ theme, isDark, colorMode, setColorMode, themeVariant, setThemeVariant, contrastLevel, setContrastLevel, }), [theme, isDark, colorMode, themeVariant, contrastLevel] ); return {children}; };