/** * 设置页 SettingsScreen - Twitter/X 风格 * 威友 - 应用设置 * 采用扁平化设计,全宽布局,简洁分割线 */ import React, { useMemo, useState } from 'react'; import { View, StyleSheet, TouchableOpacity, Alert, ScrollView, } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { StatusBar } from 'expo-status-bar'; import { useRouter } from 'expo-router'; import { MaterialCommunityIcons } from '@expo/vector-icons'; import Constants from 'expo-constants'; import { useAppColors, spacing, fontSizes, borderRadius, useThemePreference, useSetThemePreference, type AppColors, } from '../../theme'; import { useAuthStore } from '../../stores'; import { Text, SimpleHeader } from '../../components/common'; import { useResponsive, useResponsiveSpacing } from '../../hooks'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import * as hrefs from '../../navigation/hrefs'; const APP_VERSION = Constants.expoConfig?.version || '1.0.0'; const THEME_OPTIONS: { value: 'system' | 'light' | 'dark'; label: string }[] = [ { value: 'system', label: '跟随系统' }, { value: 'light', label: '浅色' }, { value: 'dark', label: '深色' }, ]; interface SettingsItem { key: string; title: string; icon: string; onPress?: () => void; showArrow?: boolean; danger?: boolean; subtitle?: string; isThemePicker?: boolean; } const SETTINGS_GROUPS_BASE = [ { title: '账号与安全', items: [ { key: 'edit_profile', title: '编辑资料', icon: 'account-edit-outline', showArrow: true }, { key: 'verification', title: '身份认证', icon: 'check-decagram', showArrow: true, subtitle: '获得认证标识,解锁更多功能' }, { key: 'privacy', title: '隐私设置', icon: 'shield-account-outline', showArrow: true }, { key: 'security', title: '账号安全', icon: 'lock-outline', showArrow: true }, ], }, { title: '通知与通用', items: [ { key: 'notification_settings', title: '通知设置', icon: 'bell-cog-outline', showArrow: true, subtitle: '推送、震动、提示音' }, { key: 'data_storage', title: '数据与存储', icon: 'database-outline', showArrow: true }, ], }, { title: '关于与帮助', items: [ { key: 'about', title: '关于我们', icon: 'information-outline', showArrow: true, subtitle: `版本 ${APP_VERSION}` }, { key: 'help', title: '帮助与反馈', icon: 'help-circle-outline', showArrow: true }, ], }, ]; function createSettingsStyles(colors: AppColors) { return StyleSheet.create({ container: { flex: 1, backgroundColor: colors.background.default, }, scrollContent: { paddingVertical: spacing.sm, }, groupContainer: { marginBottom: spacing.xl, backgroundColor: colors.background.paper, borderTopWidth: StyleSheet.hairlineWidth, borderBottomWidth: StyleSheet.hairlineWidth, borderColor: colors.divider, overflow: 'visible', zIndex: 1, }, groupHeader: { paddingHorizontal: spacing.lg, paddingVertical: spacing.sm, backgroundColor: colors.background.default, }, groupTitle: { fontWeight: '600', fontSize: fontSizes.sm, color: colors.text.secondary, }, settingItem: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingVertical: 14, paddingHorizontal: spacing.lg, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: colors.divider, backgroundColor: colors.background.paper, }, settingItemLast: { borderBottomWidth: 0, }, settingItemLeft: { flexDirection: 'row', alignItems: 'center', flex: 1, }, iconContainer: { width: 32, height: 32, borderRadius: borderRadius.md, backgroundColor: colors.background.default, justifyContent: 'center', alignItems: 'center', marginRight: spacing.md, }, dangerIconContainer: { backgroundColor: colors.error.light + '20', }, settingContent: { flex: 1, }, subtitle: { marginTop: 2, }, // 无背景色的选择框,紧贴右侧 selectBox: { flexDirection: 'row', alignItems: 'center', paddingVertical: spacing.xs, }, selectBoxText: { fontSize: fontSizes.sm, color: colors.text.secondary, marginRight: spacing.xs, }, // 原位展开的下拉菜单 dropdownMenu: { position: 'absolute', right: 0, top: '100%', marginTop: 4, backgroundColor: colors.background.paper, borderRadius: borderRadius.md, borderWidth: StyleSheet.hairlineWidth, borderColor: colors.divider, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 4, zIndex: 100, minWidth: 120, overflow: 'hidden', }, dropdownOption: { paddingHorizontal: spacing.md, paddingVertical: spacing.sm, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: colors.divider, }, dropdownOptionLast: { borderBottomWidth: 0, }, dropdownOptionText: { fontSize: fontSizes.sm, color: colors.text.primary, }, dropdownOptionTextActive: { color: colors.primary.main, fontWeight: '600', }, logoutButton: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', marginTop: spacing.lg, marginBottom: spacing.xl, paddingVertical: 14, marginHorizontal: spacing.lg, borderRadius: borderRadius.full, gap: spacing.sm, backgroundColor: colors.background.paper, borderWidth: 1, borderColor: colors.divider, }, logoutText: { fontWeight: '700', }, footer: { alignItems: 'center', marginTop: spacing.md, paddingBottom: spacing.xl, }, copyright: { marginTop: spacing.xs, }, }); } export const SettingsScreen: React.FC = () => { const router = useRouter(); const logout = useAuthStore((s) => s.logout); const insets = useSafeAreaInsets(); const { isMobile } = useResponsive(); const responsivePadding = useResponsiveSpacing({ xs: 0, sm: 0, md: 0, lg: 24, xl: 32 }); const colors = useAppColors(); const styles = useMemo(() => createSettingsStyles(colors), [colors]); const themePreference = useThemePreference(); const setThemePreference = useSetThemePreference(); const [openPicker, setOpenPicker] = useState(null); const scrollBottomInset = isMobile ? 64 + 24 + insets.bottom + spacing.md : spacing.md; const settingsGroups = useMemo(() => { return [ { title: '个性化', items: [ { key: 'chat_settings', title: '聊天设置', icon: 'message-text-outline', showArrow: true, subtitle: '字号、主题、壁纸', }, { key: 'theme', title: '主题模式', icon: 'theme-light-dark', isThemePicker: true, }, ], }, ...SETTINGS_GROUPS_BASE, ]; }, [themePreference]); const handleItemPress = (key: string) => { switch (key) { case 'chat_settings': router.push(hrefs.hrefProfileChatSettings()); break; case 'theme': { setOpenPicker(openPicker === 'theme' ? null : 'theme'); break; } case 'data_storage': router.push(hrefs.hrefProfileDataStorage()); break; case 'about': router.push(hrefs.hrefProfileAbout()); break; case 'help': router.push(hrefs.hrefProfileHelp()); break; case 'edit_profile': router.push(hrefs.hrefProfileEdit()); break; case 'verification': router.push(hrefs.hrefProfileVerification()); break; case 'notification_settings': router.push(hrefs.hrefProfileNotifications()); break; case 'blocked_users': router.push(hrefs.hrefProfileBlocked()); break; case 'security': router.push(hrefs.hrefProfileSecurity()); break; case 'privacy': router.push(hrefs.hrefProfilePrivacySettings()); break; case 'account_deletion': router.push(hrefs.hrefProfileDeletion()); break; case 'logout': Alert.alert( '退出登录', '确定要退出登录吗?', [ { text: '取消', style: 'cancel' }, { text: '确定', style: 'destructive', onPress: async () => { await logout(); router.replace(hrefs.hrefAuthLogin()); }, }, ] ); break; default: break; } }; const getThemeLabel = (value: string) => THEME_OPTIONS.find((o) => o.value === value)?.label ?? '跟随系统'; const renderSettingItem = (item: SettingsItem, index: number, total: number) => { const isThemeOpen = item.isThemePicker && openPicker === 'theme'; const themeLabel = item.isThemePicker ? getThemeLabel(themePreference) : undefined; return ( (item.onPress ? item.onPress() : handleItemPress(item.key))} activeOpacity={0.7} > {item.title} {item.subtitle && ( {item.subtitle} )} {item.isThemePicker ? ( {themeLabel} {isThemeOpen && ( {THEME_OPTIONS.map((option, optIndex) => { const isActive = themePreference === option.value; return ( { void setThemePreference(option.value); setOpenPicker(null); }} activeOpacity={0.7} > {option.label} ); })} )} ) : ( item.showArrow && ( ) )} ); }; const renderGroup = (group: (typeof settingsGroups)[0], groupIndex: number) => ( 'isThemePicker' in i && i.isThemePicker && openPicker === 'theme') ? 10 : groupIndex }, ]} > {group.title} {group.items.map((item, index) => renderSettingItem(item, index, group.items.length))} ); const renderLogoutButton = () => ( handleItemPress('logout')} activeOpacity={0.8} > 退出登录 ); const renderContent = () => ( <> {settingsGroups.map((group, index) => renderGroup(group, index))} {renderLogoutButton()} 威友 v{APP_VERSION} © 2026 青春之旅电子信息科技(威海)有限公司 ); return ( router.back()} /> {renderContent()} ); }; export default SettingsScreen;