import { PRIVACY_POLICY_URL, USER_AGREEMENT_URL } from '@/constants/Agree'; import { Colors } from '@/constants/Colors'; import { getTabBarBottomPadding } from '@/constants/TabBar'; import { useAppDispatch, useAppSelector } from '@/hooks/redux'; import { useAuthGuard } from '@/hooks/useAuthGuard'; import { useColorScheme } from '@/hooks/useColorScheme'; import { DEFAULT_MEMBER_NAME, fetchMyProfile } from '@/store/userSlice'; import { Ionicons } from '@expo/vector-icons'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs'; import { useFocusEffect } from '@react-navigation/native'; import { LinearGradient } from 'expo-linear-gradient'; import React, { useMemo, useState } from 'react'; import { Alert, Image, Linking, SafeAreaView, ScrollView, StatusBar, StyleSheet, Switch, Text, TouchableOpacity, View } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; const DEFAULT_AVATAR_URL = 'https://plates-1251306435.cos.ap-guangzhou.myqcloud.com/images/avatar/avatarGirl01.jpeg'; export default function PersonalScreen() { const dispatch = useAppDispatch(); const { confirmLogout, confirmDeleteAccount, isLoggedIn, pushIfAuthedElseLogin } = useAuthGuard(); const insets = useSafeAreaInsets(); const tabBarHeight = useBottomTabBarHeight(); const colorScheme = useColorScheme(); const [notificationEnabled, setNotificationEnabled] = useState(true); // 计算底部间距 const bottomPadding = useMemo(() => { return getTabBarBottomPadding(tabBarHeight) + (insets?.bottom ?? 0); }, [tabBarHeight, insets?.bottom]); // 颜色主题 const colors = Colors[colorScheme ?? 'light']; const theme = (colorScheme ?? 'light') as 'light' | 'dark'; // 直接使用 Redux 中的用户信息,避免重复状态管理 const userProfile = useAppSelector((state) => state.user.profile); // 页面聚焦时获取最新用户信息 useFocusEffect( React.useCallback(() => { dispatch(fetchMyProfile()); }, [dispatch]) ); // 数据格式化函数 const formatHeight = () => { if (userProfile.height == null) return '--'; return `${parseFloat(userProfile.height).toFixed(1)}cm`; }; const formatWeight = () => { if (userProfile.weight == null) return '--'; return `${parseFloat(userProfile.weight).toFixed(1)}kg`; }; const formatAge = () => { if (!userProfile.birthDate) return '--'; const birthDate = new Date(userProfile.birthDate); const today = new Date(); const age = today.getFullYear() - birthDate.getFullYear(); return `${age}岁`; }; // 显示名称 const displayName = (userProfile.name?.trim()) ? userProfile.name : DEFAULT_MEMBER_NAME; // 颜色令牌 const colorTokens = colors; const handleResetOnboarding = () => { Alert.alert( '重置引导', '确定要重置引导流程吗?下次启动应用时将重新显示引导页面。', [ { text: '取消', style: 'cancel', }, { text: '确定', style: 'destructive', onPress: async () => { try { await AsyncStorage.multiRemove(['@onboarding_completed', '@user_personal_info']); Alert.alert('成功', '引导状态已重置,请重启应用查看效果。'); } catch (error) { console.error('重置引导状态失败:', error); Alert.alert('错误', '重置失败,请稍后重试。'); } }, }, ] ); }; const UserInfoSection = () => ( {/* 头像 */} {/* 用户信息 */} {displayName} {/* 编辑按钮 */} pushIfAuthedElseLogin('/profile/edit')}> 编辑 ); const StatsSection = () => ( {formatHeight()} 身高 {formatWeight()} 体重 {formatAge()} 年龄 ); // 菜单项组件 const MenuSection = ({ title, items }: { title: string; items: any[] }) => ( {title} {items.map((item, index) => ( {item.title} {item.type === 'switch' ? ( { if (!isLoggedIn) { pushIfAuthedElseLogin('/profile/notification-settings'); return; } setNotificationEnabled(value); }} trackColor={{ false: '#E5E5E5', true: colors.primary }} thumbColor="#FFFFFF" style={styles.switch} /> ) : ( )} ))} ); // 动态样式 const dynamicStyles = StyleSheet.create({ editButton: { backgroundColor: colors.primary, paddingHorizontal: 20, paddingVertical: 10, borderRadius: 20, }, editButtonText: { color: colors.onPrimary, fontSize: 14, fontWeight: '600', }, statValue: { fontSize: 18, fontWeight: 'bold', color: colors.primary, marginBottom: 4, }, floatingButton: { width: 56, height: 56, borderRadius: 28, backgroundColor: colors.primary, alignItems: 'center', justifyContent: 'center', shadowColor: colors.primary, shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.3, shadowRadius: 8, elevation: 8, }, }); // 菜单项配置 const menuSections = [ { title: '账户', items: [ { icon: 'flag-outline' as const, title: '目标管理', onPress: () => pushIfAuthedElseLogin('/profile/goals'), }, // { // icon: 'stats-chart-outline' as const, // title: '训练进度', // onPress: () => { // // 训练进度页面暂未实现,先显示提示 // if (isLoggedIn) { // Alert.alert('提示', '训练进度功能正在开发中'); // } else { // pushIfAuthedElseLogin('/profile/training-progress'); // } // }, // }, ], }, { title: '通知', items: [ { icon: 'notifications-outline' as const, title: '消息推送', type: 'switch' as const, }, ], }, { title: '其他', items: [ { icon: 'shield-checkmark-outline' as const, title: '隐私政策', onPress: () => Linking.openURL(PRIVACY_POLICY_URL), }, { icon: 'document-text-outline' as const, title: '用户协议', onPress: () => Linking.openURL(USER_AGREEMENT_URL), }, ], }, // 只有登录用户才显示账号与安全菜单 ...(isLoggedIn ? [{ title: '账号与安全', items: [ { icon: 'log-out-outline' as const, title: '退出登录', onPress: confirmLogout, isDanger: false, }, { icon: 'trash-outline' as const, title: '注销帐号', onPress: confirmDeleteAccount, isDanger: true, }, ], }] : []), ]; return ( {menuSections.map((section, index) => ( ))} ); } const styles = StyleSheet.create({ container: { flex: 1, }, gradientBackground: { position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, }, safeArea: { flex: 1, }, scrollView: { flex: 1, paddingHorizontal: 20, }, // 用户信息区域 userInfoCard: { borderRadius: 16, marginBottom: 20, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.08, shadowRadius: 6, elevation: 3, }, userInfoContainer: { flexDirection: 'row', alignItems: 'center', padding: 20, }, avatarContainer: { marginRight: 15, }, avatar: { width: 80, height: 80, borderRadius: 40, alignItems: 'center', justifyContent: 'center', overflow: 'hidden', }, userDetails: { flex: 1, }, userName: { fontSize: 18, fontWeight: 'bold', marginBottom: 4, }, statsContainer: { flexDirection: 'row', justifyContent: 'space-between', borderRadius: 16, padding: 20, marginBottom: 20, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 3, }, statItem: { alignItems: 'center', flex: 1, }, statLabel: { fontSize: 12, }, menuSection: { marginBottom: 20, padding: 16, borderRadius: 16, }, sectionTitle: { fontSize: 20, fontWeight: '800', marginBottom: 12, paddingHorizontal: 4, }, menuItem: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingVertical: 16, paddingHorizontal: 16, borderRadius: 12, marginBottom: 8, }, menuItemLeft: { flexDirection: 'row', alignItems: 'center', flex: 1, }, menuIcon: { width: 36, height: 36, borderRadius: 8, alignItems: 'center', justifyContent: 'center', marginRight: 12, }, menuItemText: { fontSize: 16, flex: 1, fontWeight: '600', }, switch: { transform: [{ scaleX: 0.8 }, { scaleY: 0.8 }], }, // 浮动按钮 floatingButtonContainer: { position: 'absolute', bottom: 30, left: 0, right: 0, alignItems: 'center', pointerEvents: 'box-none', }, });