feat(Theme): enhance theming and UI consistency across components
- Updated app.json to set userInterfaceStyle to automatic for improved theme adaptability. - Refactored layout components to utilize useAppColors for dynamic theming, ensuring consistent color usage. - Introduced SystemChrome component to manage system UI background color based on theme. - Enhanced TabsLayout, ProfileStackLayout, and other components to leverage new theming structure. - Improved QRCodeScanner, SearchBar, and CommentItem styles to align with the updated theme system. - Consolidated styles in SystemMessageItem and TabBar for better maintainability and visual coherence.
This commit is contained in:
@@ -44,6 +44,17 @@ export { userManager } from './userManager';
|
||||
export {
|
||||
useHomeTabBarVisibilityStore,
|
||||
} from './homeTabBarVisibilityStore';
|
||||
export {
|
||||
useAppColors,
|
||||
useThemePreference,
|
||||
useResolvedColorScheme,
|
||||
useSetThemePreference,
|
||||
usePaperThemeFromStore,
|
||||
ThemeBootstrap,
|
||||
useThemeStore,
|
||||
type ThemePreference,
|
||||
type ResolvedScheme,
|
||||
} from './themeStore';
|
||||
export {
|
||||
useConversations as useMessageManagerConversations,
|
||||
useMessages,
|
||||
|
||||
133
src/stores/themeStore.ts
Normal file
133
src/stores/themeStore.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { useColorScheme } from 'react-native';
|
||||
import { create } from 'zustand';
|
||||
import { useEffect } from 'react';
|
||||
import { lightColors, darkColors, type AppColors } from '../theme/palettes';
|
||||
import { buildPaperTheme } from '../theme/paperTheme';
|
||||
import type { MD3Theme } from 'react-native-paper';
|
||||
|
||||
const STORAGE_KEY = 'app_theme_preference';
|
||||
|
||||
export type ThemePreference = 'light' | 'dark' | 'system';
|
||||
|
||||
export type ResolvedScheme = 'light' | 'dark';
|
||||
|
||||
function computeResolved(pref: ThemePreference, system: ResolvedScheme): ResolvedScheme {
|
||||
return pref === 'system' ? system : pref;
|
||||
}
|
||||
|
||||
function buildState(
|
||||
preference: ThemePreference,
|
||||
systemScheme: ResolvedScheme
|
||||
): {
|
||||
resolvedScheme: ResolvedScheme;
|
||||
colors: AppColors;
|
||||
paperTheme: MD3Theme;
|
||||
} {
|
||||
const resolvedScheme = computeResolved(preference, systemScheme);
|
||||
const isDark = resolvedScheme === 'dark';
|
||||
const colors = isDark ? darkColors : lightColors;
|
||||
return {
|
||||
resolvedScheme,
|
||||
colors,
|
||||
paperTheme: buildPaperTheme(colors, isDark),
|
||||
};
|
||||
}
|
||||
|
||||
type ThemeState = {
|
||||
preference: ThemePreference;
|
||||
systemScheme: ResolvedScheme;
|
||||
hydrated: boolean;
|
||||
resolvedScheme: ResolvedScheme;
|
||||
colors: AppColors;
|
||||
paperTheme: MD3Theme;
|
||||
setPreference: (p: ThemePreference) => Promise<void>;
|
||||
setSystemScheme: (s: ResolvedScheme) => void;
|
||||
hydrate: () => Promise<void>;
|
||||
};
|
||||
|
||||
const initialSystem: ResolvedScheme = 'light';
|
||||
|
||||
export const useThemeStore = create<ThemeState>((set, get) => ({
|
||||
preference: 'system',
|
||||
systemScheme: initialSystem,
|
||||
hydrated: false,
|
||||
...buildState('system', initialSystem),
|
||||
|
||||
setSystemScheme: (systemScheme) => {
|
||||
const { preference, systemScheme: cur } = get();
|
||||
if (cur === systemScheme) return;
|
||||
set({
|
||||
systemScheme,
|
||||
...buildState(preference, systemScheme),
|
||||
});
|
||||
},
|
||||
|
||||
setPreference: async (preference) => {
|
||||
try {
|
||||
await AsyncStorage.setItem(STORAGE_KEY, preference);
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
const { systemScheme } = get();
|
||||
set({
|
||||
preference,
|
||||
...buildState(preference, systemScheme),
|
||||
});
|
||||
},
|
||||
|
||||
hydrate: async () => {
|
||||
let preference: ThemePreference = 'system';
|
||||
try {
|
||||
const raw = await AsyncStorage.getItem(STORAGE_KEY);
|
||||
if (raw === 'light' || raw === 'dark' || raw === 'system') {
|
||||
preference = raw;
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
const { systemScheme } = get();
|
||||
set({
|
||||
preference,
|
||||
hydrated: true,
|
||||
...buildState(preference, systemScheme),
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
/** 在根布局中同步系统配色并恢复持久化偏好 */
|
||||
export function ThemeBootstrap() {
|
||||
const system = useColorScheme();
|
||||
const setSystemScheme = useThemeStore((s) => s.setSystemScheme);
|
||||
const hydrate = useThemeStore((s) => s.hydrate);
|
||||
|
||||
useEffect(() => {
|
||||
void hydrate();
|
||||
}, [hydrate]);
|
||||
|
||||
useEffect(() => {
|
||||
setSystemScheme(system === 'dark' ? 'dark' : 'light');
|
||||
}, [system, setSystemScheme]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function useAppColors() {
|
||||
return useThemeStore((s) => s.colors);
|
||||
}
|
||||
|
||||
export function useThemePreference() {
|
||||
return useThemeStore((s) => s.preference);
|
||||
}
|
||||
|
||||
export function useResolvedColorScheme() {
|
||||
return useThemeStore((s) => s.resolvedScheme);
|
||||
}
|
||||
|
||||
export function useSetThemePreference() {
|
||||
return useThemeStore((s) => s.setPreference);
|
||||
}
|
||||
|
||||
export function usePaperThemeFromStore() {
|
||||
return useThemeStore((s) => s.paperTheme);
|
||||
}
|
||||
Reference in New Issue
Block a user