Initial frontend repository commit.
Include app source and update .gitignore to exclude local release artifacts and signing files. Made-with: Cursor
This commit is contained in:
234
src/screens/profile/NotificationSettingsScreen.tsx
Normal file
234
src/screens/profile/NotificationSettingsScreen.tsx
Normal file
@@ -0,0 +1,234 @@
|
||||
/**
|
||||
* 通知设置页 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;
|
||||
Reference in New Issue
Block a user