Files
frontend/src/screens/profile/SettingsScreen.tsx

311 lines
8.5 KiB
TypeScript
Raw Normal View History

/**
* SettingsScreen
* BBS -
*
*/
import React from 'react';
import {
View,
StyleSheet,
TouchableOpacity,
Alert,
ScrollView,
} from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useNavigation } from '@react-navigation/native';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import Constants from 'expo-constants';
import { colors, spacing, fontSizes, borderRadius } from '../../theme';
import { useAuthStore } from '../../stores';
import { Text, ResponsiveContainer } from '../../components/common';
import { useResponsive } from '../../hooks';
interface SettingsItem {
key: string;
title: string;
icon: string;
onPress?: () => void;
showArrow?: boolean;
danger?: boolean;
subtitle?: string;
}
// 获取应用版本号
const APP_VERSION = Constants.expoConfig?.version || '1.0.0';
// 设置分组配置
const SETTINGS_GROUPS = [
{
title: '账号与安全',
icon: 'shield-check-outline',
items: [
{ key: 'edit_profile', title: '编辑资料', icon: 'account-edit-outline', showArrow: true },
{ key: 'privacy', title: '隐私设置', icon: 'shield-account-outline', showArrow: true },
{ key: 'security', title: '账号安全', icon: 'lock-outline', showArrow: true },
{ key: 'blocked_users', title: '黑名单', icon: 'account-off-outline', showArrow: true },
],
},
{
title: '通知与通用',
icon: 'bell-outline',
items: [
{ key: 'notification_settings', title: '通知设置', icon: 'bell-cog-outline', showArrow: true, subtitle: '推送、震动、提示音' },
],
},
{
title: '关于与帮助',
icon: 'information-outline',
items: [
{ key: 'about', title: '关于我们', icon: 'information-outline', showArrow: true, subtitle: `版本 ${APP_VERSION}` },
{ key: 'help', title: '帮助与反馈', icon: 'help-circle-outline', showArrow: true },
],
},
];
export const SettingsScreen: React.FC = () => {
const navigation = useNavigation();
const { logout } = useAuthStore();
const { isWideScreen } = useResponsive();
// 处理设置项点击
const handleItemPress = (key: string) => {
switch (key) {
case 'edit_profile':
navigation.navigate('EditProfile' as never);
break;
case 'notification_settings':
navigation.navigate('NotificationSettings' as never);
break;
case 'blocked_users':
navigation.navigate('BlockedUsers' as never);
break;
case 'security':
navigation.navigate('AccountSecurity' as never);
break;
case 'logout':
Alert.alert(
'退出登录',
'确定要退出登录吗?',
[
{ text: '取消', style: 'cancel' },
{
text: '确定',
style: 'destructive',
onPress: () => {
logout();
}
},
]
);
break;
default:
break;
}
};
// 渲染单个设置项
const renderSettingItem = (item: SettingsItem, index: number, total: number) => (
<TouchableOpacity
key={item.key}
style={[
styles.settingItem,
index === 0 && styles.settingItemFirst,
index === total - 1 && styles.settingItemLast,
]}
onPress={() => item.onPress ? item.onPress() : handleItemPress(item.key)}
activeOpacity={0.7}
>
<View style={styles.settingItemLeft}>
<View style={[
styles.iconContainer,
item.danger && styles.dangerIconContainer
]}>
<MaterialCommunityIcons
name={item.icon as any}
size={20}
color={item.danger ? colors.error.main : colors.primary.main}
/>
</View>
<View style={styles.settingContent}>
<Text
variant="body"
color={item.danger ? colors.error.main : colors.text.primary}
>
{item.title}
</Text>
{item.subtitle && (
<Text variant="caption" color={colors.text.secondary} style={styles.subtitle}>
{item.subtitle}
</Text>
)}
</View>
</View>
{item.showArrow && (
<MaterialCommunityIcons name="chevron-right" size={20} color={colors.text.hint} />
)}
</TouchableOpacity>
);
// 渲染分组
const renderGroup = (group: typeof SETTINGS_GROUPS[0], groupIndex: number) => (
<View key={group.title} style={styles.groupContainer}>
<View style={styles.groupHeader}>
<MaterialCommunityIcons name={group.icon as any} size={16} color={colors.primary.main} />
<Text variant="caption" color={colors.text.secondary} style={styles.groupTitle}>
{group.title}
</Text>
</View>
<View style={styles.card}>
{group.items.map((item, index) =>
renderSettingItem(item, index, group.items.length)
)}
</View>
</View>
);
// 退出登录按钮
const renderLogoutButton = () => (
<TouchableOpacity
style={styles.logoutButton}
onPress={() => handleItemPress('logout')}
activeOpacity={0.7}
>
<MaterialCommunityIcons name="logout-variant" size={20} color={colors.error.main} />
<Text variant="body" color={colors.error.main} style={styles.logoutText}>
退
</Text>
</TouchableOpacity>
);
// 渲染内容
const renderContent = () => (
<>
{SETTINGS_GROUPS.map((group, index) => renderGroup(group, index))}
{renderLogoutButton()}
{/* 底部版权信息 */}
<View style={styles.footer}>
<Text variant="caption" color={colors.text.hint}>
v{APP_VERSION}
</Text>
<Text variant="caption" color={colors.text.hint} style={styles.copyright}>
© 2024 Carrot BBS. All rights reserved.
</Text>
</View>
</>
);
return (
<SafeAreaView style={styles.container} edges={['bottom']}>
{isWideScreen ? (
<ResponsiveContainer maxWidth={800}>
<ScrollView contentContainerStyle={styles.scrollContent}>
{renderContent()}
</ScrollView>
</ResponsiveContainer>
) : (
<ScrollView contentContainerStyle={styles.scrollContent}>
{renderContent()}
</ScrollView>
)}
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.background.default,
},
scrollContent: {
paddingVertical: spacing.md,
},
groupContainer: {
marginBottom: spacing.lg,
},
groupHeader: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: spacing.lg,
marginBottom: spacing.sm,
gap: spacing.xs,
},
groupTitle: {
fontWeight: '600',
fontSize: fontSizes.sm,
},
card: {
backgroundColor: colors.background.paper,
marginHorizontal: spacing.lg,
borderRadius: borderRadius.lg,
overflow: 'hidden',
},
settingItem: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingVertical: spacing.md,
paddingHorizontal: spacing.md,
borderBottomWidth: 1,
borderBottomColor: colors.divider,
},
settingItemFirst: {
borderTopLeftRadius: borderRadius.lg,
borderTopRightRadius: borderRadius.lg,
},
settingItemLast: {
borderBottomLeftRadius: borderRadius.lg,
borderBottomRightRadius: borderRadius.lg,
borderBottomWidth: 0,
},
settingItemLeft: {
flexDirection: 'row',
alignItems: 'center',
flex: 1,
},
iconContainer: {
width: 36,
height: 36,
borderRadius: borderRadius.md,
backgroundColor: colors.primary.light + '20',
justifyContent: 'center',
alignItems: 'center',
marginRight: spacing.md,
},
dangerIconContainer: {
backgroundColor: colors.error.light + '20',
},
settingContent: {
flex: 1,
},
subtitle: {
marginTop: 2,
},
logoutButton: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: colors.background.paper,
marginHorizontal: spacing.lg,
marginTop: spacing.sm,
marginBottom: spacing.lg,
paddingVertical: spacing.md,
borderRadius: borderRadius.lg,
gap: spacing.sm,
},
logoutText: {
fontWeight: '500',
},
footer: {
alignItems: 'center',
marginTop: spacing.xl,
paddingBottom: spacing.xl,
},
copyright: {
marginTop: spacing.xs,
},
});
export default SettingsScreen;