import AsyncStorage from '@/utils/kvStore'; import { logger } from '@/utils/logger'; import { createSelector, createSlice, PayloadAction } from '@reduxjs/toolkit'; import type { RootState } from './index'; // Tab 配置接口 export interface TabConfig { id: string; // tab 标识符 icon: string; // SF Symbol 图标名 titleKey: string; // i18n 翻译 key enabled: boolean; // 是否启用 canBeDisabled: boolean; // 是否可以被禁用 order: number; // 显示顺序 } // State 接口 interface TabBarConfigState { configs: TabConfig[]; isInitialized: boolean; } // 默认配置 export const DEFAULT_TAB_CONFIGS: TabConfig[] = [ { id: 'statistics', icon: 'chart.pie.fill', titleKey: 'statistics.tabs.health', enabled: true, canBeDisabled: false, order: 1, }, { id: 'medications', icon: 'pills.fill', titleKey: 'statistics.tabs.medications', enabled: true, canBeDisabled: false, order: 2, }, { id: 'fasting', icon: 'timer', titleKey: 'statistics.tabs.fasting', enabled: true, canBeDisabled: true, // 只有断食可以被关闭 order: 3, }, { id: 'challenges', icon: 'trophy.fill', titleKey: 'statistics.tabs.challenges', enabled: true, canBeDisabled: false, order: 4, }, { id: 'personal', icon: 'person.fill', titleKey: 'statistics.tabs.personal', enabled: true, canBeDisabled: false, order: 5, }, ]; // AsyncStorage key const STORAGE_KEY = 'tab_bar_config'; // 初始状态 const initialState: TabBarConfigState = { configs: DEFAULT_TAB_CONFIGS, isInitialized: false, }; const tabBarConfigSlice = createSlice({ name: 'tabBarConfig', initialState, reducers: { // 设置配置(用于从 AsyncStorage 恢复) setConfigs: (state, action: PayloadAction) => { state.configs = action.payload; state.isInitialized = true; }, // 切换 tab 启用状态 toggleTabEnabled: (state, action: PayloadAction) => { const tabId = action.payload; const config = state.configs.find(c => c.id === tabId); if (config && config.canBeDisabled) { config.enabled = !config.enabled; // 自动持久化到 AsyncStorage saveConfigsToStorage(state.configs); } }, // 更新 tab 顺序(拖拽后) reorderTabs: (state, action: PayloadAction) => { // 更新顺序,同时保持其他属性不变 const newConfigs = action.payload.map((config, index) => ({ ...config, order: index + 1, })); state.configs = newConfigs; // 自动持久化到 AsyncStorage saveConfigsToStorage(newConfigs); }, // 恢复默认配置 resetToDefault: (state) => { state.configs = DEFAULT_TAB_CONFIGS; // 持久化到 AsyncStorage saveConfigsToStorage(DEFAULT_TAB_CONFIGS); }, // 标记已初始化 markInitialized: (state) => { state.isInitialized = true; }, }, }); // 持久化配置到 AsyncStorage const saveConfigsToStorage = async (configs: TabConfig[]) => { try { await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(configs)); logger.info('底部栏配置已保存'); } catch (error) { logger.error('保存底部栏配置失败:', error); } }; // 从 AsyncStorage 加载配置 export const loadTabBarConfigs = () => async (dispatch: any) => { try { const stored = await AsyncStorage.getItem(STORAGE_KEY); if (stored) { const configs = JSON.parse(stored) as TabConfig[]; // 验证配置有效性 if (Array.isArray(configs) && configs.length > 0) { // 合并默认配置,确保新增的 tab 也能显示 const mergedConfigs = mergeWithDefaults(configs); dispatch(setConfigs(mergedConfigs)); logger.info('底部栏配置已加载'); return; } } // 如果没有存储或无效,使用默认配置 dispatch(setConfigs(DEFAULT_TAB_CONFIGS)); dispatch(markInitialized()); } catch (error) { logger.error('加载底部栏配置失败:', error); // 出错时使用默认配置 dispatch(setConfigs(DEFAULT_TAB_CONFIGS)); dispatch(markInitialized()); } }; // 合并存储的配置和默认配置 const mergeWithDefaults = (storedConfigs: TabConfig[]): TabConfig[] => { const merged = [...storedConfigs]; // 检查是否有新增的默认 tab DEFAULT_TAB_CONFIGS.forEach(defaultConfig => { const exists = merged.find(c => c.id === defaultConfig.id); if (!exists) { // 新增的 tab,添加到末尾 merged.push({ ...defaultConfig, order: merged.length + 1, }); } }); // 按 order 排序 return merged.sort((a, b) => a.order - b.order); }; // Actions export const { setConfigs, toggleTabEnabled, reorderTabs, resetToDefault, markInitialized, } = tabBarConfigSlice.actions; // Selectors export const selectTabBarConfigs = (state: RootState) => state.tabBarConfig.configs; // ✅ 使用 createSelector 进行记忆化,避免不必要的重渲染 export const selectEnabledTabs = createSelector( [selectTabBarConfigs], (configs) => configs .filter(config => config.enabled) .sort((a, b) => a.order - b.order) ); export const selectIsInitialized = (state: RootState) => state.tabBarConfig.isInitialized; // 按 id 获取配置 export const selectTabConfigById = (tabId: string) => (state: RootState) => state.tabBarConfig.configs.find(config => config.id === tabId); export default tabBarConfigSlice.reducer;