feat: 实现目标通知功能及相关组件

- 新增目标通知功能,支持根据用户创建目标时选择的频率和开始时间自动创建本地定时推送通知
- 实现每日、每周和每月的重复类型,用户可自定义选择提醒时间和重复规则
- 集成目标通知测试组件,方便开发者测试不同类型的通知
- 更新相关文档,详细描述目标通知功能的实现和使用方法
- 优化目标页面,确保用户体验和界面一致性
This commit is contained in:
2025-08-23 17:13:04 +08:00
parent 4382fb804f
commit 20a244e375
15 changed files with 957 additions and 156 deletions

View File

@@ -0,0 +1,195 @@
import { GoalNotificationHelpers } from '@/utils/notificationHelpers';
import React, { useState } from 'react';
import {
ScrollView,
StyleSheet,
TouchableOpacity,
View,
} from 'react-native';
import { ThemedText } from './ThemedText';
import { ThemedView } from './ThemedView';
export const GoalNotificationTest: React.FC = () => {
const [testResults, setTestResults] = useState<string[]>([]);
const addResult = (result: string) => {
setTestResults(prev => [...prev, `${new Date().toLocaleTimeString()}: ${result}`]);
};
const testDailyGoalNotification = async () => {
try {
const notificationIds = await GoalNotificationHelpers.scheduleGoalNotifications(
{
title: '每日运动目标',
repeatType: 'daily',
frequency: 1,
hasReminder: true,
reminderTime: '09:00',
},
'测试用户'
);
addResult(`每日目标通知创建成功ID: ${notificationIds.join(', ')}`);
} catch (error) {
addResult(`每日目标通知创建失败: ${error}`);
}
};
const testWeeklyGoalNotification = async () => {
try {
const notificationIds = await GoalNotificationHelpers.scheduleGoalNotifications(
{
title: '每周运动目标',
repeatType: 'weekly',
frequency: 1,
hasReminder: true,
reminderTime: '10:00',
customRepeatRule: {
weekdays: [1, 3, 5], // 周一、三、五
},
},
'测试用户'
);
addResult(`每周目标通知创建成功ID: ${notificationIds.join(', ')}`);
} catch (error) {
addResult(`每周目标通知创建失败: ${error}`);
}
};
const testMonthlyGoalNotification = async () => {
try {
const notificationIds = await GoalNotificationHelpers.scheduleGoalNotifications(
{
title: '每月运动目标',
repeatType: 'monthly',
frequency: 1,
hasReminder: true,
reminderTime: '11:00',
customRepeatRule: {
dayOfMonth: [1, 15], // 每月1号和15号
},
},
'测试用户'
);
addResult(`每月目标通知创建成功ID: ${notificationIds.join(', ')}`);
} catch (error) {
addResult(`每月目标通知创建失败: ${error}`);
}
};
const testGoalAchievementNotification = async () => {
try {
await GoalNotificationHelpers.sendGoalAchievementNotification('测试用户', '每日运动目标');
addResult('目标达成通知发送成功');
} catch (error) {
addResult(`目标达成通知发送失败: ${error}`);
}
};
const testCancelGoalNotifications = async () => {
try {
await GoalNotificationHelpers.cancelGoalNotifications('每日运动目标');
addResult('目标通知取消成功');
} catch (error) {
addResult(`目标通知取消失败: ${error}`);
}
};
const clearResults = () => {
setTestResults([]);
};
return (
<ThemedView style={styles.container}>
<ScrollView style={styles.scrollView}>
<ThemedText style={styles.title}></ThemedText>
<View style={styles.buttonContainer}>
<TouchableOpacity style={styles.button} onPress={testDailyGoalNotification}>
<ThemedText style={styles.buttonText}></ThemedText>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={testWeeklyGoalNotification}>
<ThemedText style={styles.buttonText}></ThemedText>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={testMonthlyGoalNotification}>
<ThemedText style={styles.buttonText}></ThemedText>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={testGoalAchievementNotification}>
<ThemedText style={styles.buttonText}></ThemedText>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={testCancelGoalNotifications}>
<ThemedText style={styles.buttonText}></ThemedText>
</TouchableOpacity>
<TouchableOpacity style={styles.clearButton} onPress={clearResults}>
<ThemedText style={styles.buttonText}></ThemedText>
</TouchableOpacity>
</View>
<View style={styles.resultsContainer}>
<ThemedText style={styles.resultsTitle}>:</ThemedText>
{testResults.map((result, index) => (
<ThemedText key={index} style={styles.resultText}>
{result}
</ThemedText>
))}
</View>
</ScrollView>
</ThemedView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
scrollView: {
flex: 1,
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 20,
textAlign: 'center',
},
buttonContainer: {
gap: 10,
marginBottom: 20,
},
button: {
backgroundColor: '#6366F1',
padding: 15,
borderRadius: 10,
alignItems: 'center',
},
clearButton: {
backgroundColor: '#EF4444',
padding: 15,
borderRadius: 10,
alignItems: 'center',
},
buttonText: {
color: '#FFFFFF',
fontSize: 16,
fontWeight: '600',
},
resultsContainer: {
flex: 1,
},
resultsTitle: {
fontSize: 18,
fontWeight: '600',
marginBottom: 10,
},
resultText: {
fontSize: 14,
marginBottom: 5,
padding: 10,
backgroundColor: '#F3F4F6',
borderRadius: 5,
},
});