Files
frontend/src/screens/profile/NotificationSettingsScreen.tsx
lan 3968660048 Initial frontend repository commit.
Include app source and update .gitignore to exclude local release artifacts and signing files.

Made-with: Cursor
2026-03-09 21:29:03 +08:00

235 lines
6.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 通知设置页 NotificationSettingsScreen响应式适配
* 胡萝卜BBS - 通知相关设置
* 在宽屏下居中显示
*/
import React, { useState, useEffect } from 'react';
import {
View,
StyleSheet,
Switch,
ScrollView,
} from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { colors, spacing, fontSizes, borderRadius } from '../../theme';
import { Text, ResponsiveContainer } from '../../components/common';
import { setVibrationEnabled } from '../../services/backgroundService';
import { useResponsive } from '../../hooks';
const VIBRATION_ENABLED_KEY = 'vibration_enabled';
interface NotificationSettingItem {
key: string;
title: string;
subtitle?: string;
icon: string;
value: boolean;
onValueChange: (value: boolean) => void;
}
export const NotificationSettingsScreen: React.FC = () => {
const [vibrationEnabled, setVibrationEnabledState] = useState(true);
const [pushEnabled, setPushEnabled] = useState(true);
const [soundEnabled, setSoundEnabled] = useState(true);
const { isWideScreen } = useResponsive();
// 加载设置
useEffect(() => {
const loadSettings = async () => {
try {
const vibrationStored = await AsyncStorage.getItem(VIBRATION_ENABLED_KEY);
if (vibrationStored !== null) {
const enabled = JSON.parse(vibrationStored);
setVibrationEnabledState(enabled);
setVibrationEnabled(enabled);
}
} catch (error) {
console.error('加载震动设置失败:', error);
}
};
loadSettings();
}, []);
// 切换震动
const toggleVibration = async (value: boolean) => {
try {
setVibrationEnabledState(value);
setVibrationEnabled(value);
await AsyncStorage.setItem(VIBRATION_ENABLED_KEY, JSON.stringify(value));
} catch (error) {
console.error('保存震动设置失败:', error);
}
};
const settings: NotificationSettingItem[] = [
{
key: 'push',
title: '接收推送通知',
subtitle: '接收新消息、点赞、评论等推送',
icon: 'bell-outline',
value: pushEnabled,
onValueChange: setPushEnabled,
},
{
key: 'vibration',
title: '消息震动',
subtitle: '收到新消息时震动提醒',
icon: 'vibrate',
value: vibrationEnabled,
onValueChange: toggleVibration,
},
{
key: 'sound',
title: '消息提示音',
subtitle: '收到新消息时播放提示音',
icon: 'volume-high',
value: soundEnabled,
onValueChange: setSoundEnabled,
},
];
// 渲染内容
const renderContent = () => (
<>
{/* 消息通知设置 */}
<View style={styles.section}>
<View style={styles.sectionHeader}>
<MaterialCommunityIcons name="message-text-outline" size={18} color={colors.primary.main} />
<Text variant="caption" color={colors.text.secondary} style={styles.sectionTitle}>
</Text>
</View>
<View style={styles.card}>
{settings.map((item, index) => (
<View key={item.key}>
<View style={styles.settingItem}>
<View style={styles.iconContainer}>
<MaterialCommunityIcons
name={item.icon as any}
size={20}
color={colors.primary.main}
/>
</View>
<View style={styles.settingContent}>
<Text variant="body" color={colors.text.primary}>
{item.title}
</Text>
{item.subtitle && (
<Text variant="caption" color={colors.text.secondary} style={styles.subtitle}>
{item.subtitle}
</Text>
)}
</View>
<Switch
value={item.value}
onValueChange={item.onValueChange}
trackColor={{ false: colors.divider, true: colors.primary.main }}
thumbColor={colors.background.paper}
/>
</View>
{index < settings.length - 1 && <View style={styles.divider} />}
</View>
))}
</View>
</View>
{/* 提示信息 */}
<View style={styles.tipContainer}>
<MaterialCommunityIcons name="information-outline" size={16} color={colors.text.hint} />
<Text variant="caption" color={colors.text.hint} style={styles.tipText}>
</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,
},
section: {
marginBottom: spacing.lg,
},
sectionHeader: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: spacing.lg,
marginBottom: spacing.sm,
gap: spacing.xs,
},
sectionTitle: {
fontWeight: '600',
},
card: {
backgroundColor: colors.background.paper,
marginHorizontal: spacing.lg,
borderRadius: borderRadius.lg,
overflow: 'hidden',
},
settingItem: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: spacing.md,
paddingHorizontal: spacing.md,
},
iconContainer: {
width: 36,
height: 36,
borderRadius: borderRadius.md,
backgroundColor: colors.primary.light + '20',
justifyContent: 'center',
alignItems: 'center',
marginRight: spacing.md,
},
settingContent: {
flex: 1,
},
subtitle: {
marginTop: 2,
},
divider: {
height: 1,
backgroundColor: colors.divider,
marginLeft: 36 + spacing.md + spacing.md,
},
tipContainer: {
flexDirection: 'row',
alignItems: 'flex-start',
marginHorizontal: spacing.lg,
padding: spacing.md,
backgroundColor: colors.background.paper,
borderRadius: borderRadius.lg,
gap: spacing.sm,
},
tipText: {
flex: 1,
lineHeight: 20,
},
});
export default NotificationSettingsScreen;