Files
frontend/src/stores/themeStore.ts
lafay 405cd271db
Some checks failed
Frontend CI / build-and-push-web (push) Failing after 1m54s
Frontend CI / ota-android (push) Failing after 5m36s
Frontend CI / build-android-apk (push) Failing after 9m3s
feat(Comment): enhance like functionality for comments and replies
- Updated CommentItem component to accept the comment object in the onLike callback, allowing for more detailed like handling.
- Added a like button for replies, improving user interaction with nested comments.
- Refactored handleLikeComment function in PostDetailScreen for optimized state management and error handling during like operations.
- Enhanced SettingsScreen to provide debug information for theme preferences, improving user experience in theme selection.
- Updated themeStore to dynamically manage system theme changes and improve overall theme handling.
2026-03-26 01:25:42 +08:00

168 lines
4.4 KiB
TypeScript

import AsyncStorage from '@react-native-async-storage/async-storage';
import { Appearance, AppState, AppStateStatus } from 'react-native';
import { create } from 'zustand';
import { useEffect, useRef } 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>;
};
/** 获取系统主题 */
function getSystemScheme(): ResolvedScheme {
const scheme = Appearance.getColorScheme();
return scheme === 'dark' ? 'dark' : 'light';
}
const initialSystemScheme = getSystemScheme();
export const useThemeStore = create<ThemeState>((set, get) => ({
preference: 'system',
systemScheme: initialSystemScheme,
hydrated: false,
...buildState('system', initialSystemScheme),
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 = getSystemScheme();
set({
preference,
hydrated: true,
systemScheme,
...buildState(preference, systemScheme),
});
},
}));
/** 在根布局中同步系统配色并恢复持久化偏好 */
export function ThemeBootstrap() {
const setSystemScheme = useThemeStore((s) => s.setSystemScheme);
const hydrate = useThemeStore((s) => s.hydrate);
const appState = useRef<AppStateStatus>(AppState.currentState);
useEffect(() => {
void hydrate();
}, [hydrate]);
// 监听系统主题变化
useEffect(() => {
const subscription = Appearance.addChangeListener(({ colorScheme }) => {
const newScheme = colorScheme === 'dark' ? 'dark' : 'light';
setSystemScheme(newScheme);
});
return () => {
subscription.remove();
};
}, [setSystemScheme]);
// 监听应用状态变化,从后台恢复时重新检测系统主题
useEffect(() => {
const subscription = AppState.addEventListener('change', (nextAppState) => {
if (
appState.current.match(/inactive|background/) &&
nextAppState === 'active'
) {
setSystemScheme(getSystemScheme());
}
appState.current = nextAppState;
});
return () => {
subscription.remove();
};
}, [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);
}
// 导出调试函数
export { getSystemScheme };