feat: 增强通知功能及用户体验
- 在 Bootstrapper 组件中新增通知服务初始化逻辑,注册每日午餐提醒 - 在 CoachScreen 中优化欢迎消息生成逻辑,整合用户配置文件数据 - 更新 GoalsScreen 组件,优化目标创建时的通知设置逻辑 - 在 NotificationTest 组件中添加调试通知状态功能,提升开发便利性 - 新增 NutritionNotificationHelpers 中的午餐提醒功能,支持每日提醒设置 - 更新相关文档,详细描述新功能和使用方法
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import * as Notifications from 'expo-notifications';
|
||||
import { NotificationData, notificationService } from '../services/notifications';
|
||||
|
||||
/**
|
||||
@@ -36,7 +37,7 @@ export class WorkoutNotificationHelpers {
|
||||
static async scheduleDailyWorkoutReminder(userName: string, hour: number = 9, minute: number = 0) {
|
||||
const reminderTime = new Date();
|
||||
reminderTime.setHours(hour, minute, 0, 0);
|
||||
|
||||
|
||||
// 如果今天的时间已经过了,设置为明天
|
||||
if (reminderTime.getTime() <= Date.now()) {
|
||||
reminderTime.setDate(reminderTime.getDate() + 1);
|
||||
@@ -105,12 +106,12 @@ export class GoalNotificationHelpers {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据目标设置创建定时推送
|
||||
* @param goalData 目标数据
|
||||
* @param userName 用户名
|
||||
* @returns 通知ID数组
|
||||
*/
|
||||
/**
|
||||
* 根据目标设置创建定时推送
|
||||
* @param goalData 目标数据
|
||||
* @param userName 用户名
|
||||
* @returns 通知ID数组
|
||||
*/
|
||||
static async scheduleGoalNotifications(
|
||||
goalData: {
|
||||
title: string;
|
||||
@@ -137,13 +138,13 @@ export class GoalNotificationHelpers {
|
||||
try {
|
||||
// 解析提醒时间
|
||||
const [hours, minutes] = goalData.reminderTime.split(':').map(Number);
|
||||
|
||||
|
||||
// 创建通知内容
|
||||
const notification: NotificationData = {
|
||||
title: '目标提醒',
|
||||
body: `${userName},该完成您的目标"${goalData.title}"了!`,
|
||||
data: {
|
||||
type: 'goal_reminder',
|
||||
data: {
|
||||
type: 'goal_reminder',
|
||||
goalTitle: goalData.title,
|
||||
repeatType: goalData.repeatType,
|
||||
frequency: goalData.frequency
|
||||
@@ -159,7 +160,7 @@ export class GoalNotificationHelpers {
|
||||
const dailyId = await notificationService.scheduleCalendarRepeatingNotification(
|
||||
notification,
|
||||
{
|
||||
type: 'daily',
|
||||
type: Notifications.SchedulableTriggerInputTypes.DAILY,
|
||||
hour: hours,
|
||||
minute: minutes,
|
||||
}
|
||||
@@ -175,7 +176,7 @@ export class GoalNotificationHelpers {
|
||||
const weeklyId = await notificationService.scheduleCalendarRepeatingNotification(
|
||||
notification,
|
||||
{
|
||||
type: 'weekly',
|
||||
type: Notifications.SchedulableTriggerInputTypes.WEEKLY,
|
||||
hour: hours,
|
||||
minute: minutes,
|
||||
weekdays: [weekday],
|
||||
@@ -189,7 +190,7 @@ export class GoalNotificationHelpers {
|
||||
const weeklyId = await notificationService.scheduleCalendarRepeatingNotification(
|
||||
notification,
|
||||
{
|
||||
type: 'weekly',
|
||||
type: Notifications.SchedulableTriggerInputTypes.WEEKLY,
|
||||
hour: hours,
|
||||
minute: minutes,
|
||||
}
|
||||
@@ -206,7 +207,7 @@ export class GoalNotificationHelpers {
|
||||
const monthlyId = await notificationService.scheduleCalendarRepeatingNotification(
|
||||
notification,
|
||||
{
|
||||
type: 'monthly',
|
||||
type: Notifications.SchedulableTriggerInputTypes.MONTHLY,
|
||||
hour: hours,
|
||||
minute: minutes,
|
||||
dayOfMonth: dayOfMonth,
|
||||
@@ -220,7 +221,7 @@ export class GoalNotificationHelpers {
|
||||
const monthlyId = await notificationService.scheduleCalendarRepeatingNotification(
|
||||
notification,
|
||||
{
|
||||
type: 'monthly',
|
||||
type: Notifications.SchedulableTriggerInputTypes.MONTHLY,
|
||||
hour: hours,
|
||||
minute: minutes,
|
||||
dayOfMonth: 1,
|
||||
@@ -249,10 +250,10 @@ export class GoalNotificationHelpers {
|
||||
static async cancelGoalNotifications(goalTitle: string): Promise<void> {
|
||||
try {
|
||||
const notifications = await notificationService.getAllScheduledNotifications();
|
||||
|
||||
|
||||
for (const notification of notifications) {
|
||||
if (notification.content.data?.type === 'goal_reminder' &&
|
||||
notification.content.data?.goalTitle === goalTitle) {
|
||||
if (notification.content.data?.type === 'goal_reminder' &&
|
||||
notification.content.data?.goalTitle === goalTitle) {
|
||||
await notificationService.cancelNotification(notification.identifier);
|
||||
console.log(`已取消目标"${goalTitle}"的通知:${notification.identifier}`);
|
||||
}
|
||||
@@ -287,7 +288,7 @@ export class MoodNotificationHelpers {
|
||||
static async scheduleDailyMoodReminder(userName: string, hour: number = 20, minute: number = 0) {
|
||||
const reminderTime = new Date();
|
||||
reminderTime.setHours(hour, minute, 0, 0);
|
||||
|
||||
|
||||
// 如果今天的时间已经过了,设置为明天
|
||||
if (reminderTime.getTime() <= Date.now()) {
|
||||
reminderTime.setDate(reminderTime.getDate() + 1);
|
||||
@@ -323,6 +324,96 @@ export class NutritionNotificationHelpers {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 安排每日午餐提醒
|
||||
* @param userName 用户名
|
||||
* @param hour 小时 (默认12点)
|
||||
* @param minute 分钟 (默认0分)
|
||||
* @returns 通知ID
|
||||
*/
|
||||
static async scheduleDailyLunchReminder(
|
||||
userName: string,
|
||||
hour: number = 12,
|
||||
minute: number = 0
|
||||
): Promise<string | null> {
|
||||
try {
|
||||
// 检查是否已经存在午餐提醒
|
||||
const existingNotifications = await notificationService.getAllScheduledNotifications();
|
||||
|
||||
|
||||
console.log('existingNotifications', existingNotifications);
|
||||
const existingLunchReminder = existingNotifications.find(
|
||||
notification =>
|
||||
notification.content.data?.type === 'lunch_reminder' &&
|
||||
notification.content.data?.isDailyReminder === true
|
||||
);
|
||||
|
||||
if (existingLunchReminder) {
|
||||
console.log('午餐提醒已存在,跳过重复注册:', existingLunchReminder.identifier);
|
||||
return existingLunchReminder.identifier;
|
||||
}
|
||||
|
||||
// 创建午餐提醒通知
|
||||
const notificationId = await notificationService.scheduleCalendarRepeatingNotification(
|
||||
{
|
||||
title: '午餐记录提醒',
|
||||
body: `${userName},记得记录今天的午餐情况哦!`,
|
||||
data: {
|
||||
type: 'lunch_reminder',
|
||||
isDailyReminder: true,
|
||||
meal: '午餐'
|
||||
},
|
||||
sound: true,
|
||||
priority: 'normal',
|
||||
},
|
||||
{
|
||||
type: Notifications.SchedulableTriggerInputTypes.DAILY,
|
||||
hour: hour,
|
||||
minute: minute,
|
||||
}
|
||||
);
|
||||
|
||||
console.log('每日午餐提醒已安排,ID:', notificationId);
|
||||
return notificationId;
|
||||
} catch (error) {
|
||||
console.error('安排每日午餐提醒失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送午餐记录提醒
|
||||
*/
|
||||
static async sendLunchReminder(userName: string) {
|
||||
return notificationService.sendImmediateNotification({
|
||||
title: '午餐记录提醒',
|
||||
body: `${userName},记得记录今天的午餐情况哦!`,
|
||||
data: { type: 'lunch_reminder', meal: '午餐' },
|
||||
sound: true,
|
||||
priority: 'normal',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消午餐提醒
|
||||
*/
|
||||
static async cancelLunchReminder(): Promise<void> {
|
||||
try {
|
||||
const notifications = await notificationService.getAllScheduledNotifications();
|
||||
|
||||
for (const notification of notifications) {
|
||||
if (notification.content.data?.type === 'lunch_reminder' &&
|
||||
notification.content.data?.isDailyReminder === true) {
|
||||
await notificationService.cancelNotification(notification.identifier);
|
||||
console.log('已取消午餐提醒:', notification.identifier);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('取消午餐提醒失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 安排营养记录提醒
|
||||
*/
|
||||
@@ -339,7 +430,7 @@ export class NutritionNotificationHelpers {
|
||||
for (const mealTime of mealTimes) {
|
||||
const reminderTime = new Date();
|
||||
reminderTime.setHours(mealTime.hour, mealTime.minute, 0, 0);
|
||||
|
||||
|
||||
// 如果今天的时间已经过了,设置为明天
|
||||
if (reminderTime.getTime() <= Date.now()) {
|
||||
reminderTime.setDate(reminderTime.getDate() + 1);
|
||||
@@ -411,7 +502,7 @@ export class GeneralNotificationHelpers {
|
||||
*/
|
||||
static async cancelNotificationsByType(type: string) {
|
||||
const notifications = await notificationService.getAllScheduledNotifications();
|
||||
|
||||
|
||||
for (const notification of notifications) {
|
||||
if (notification.content.data?.type === type) {
|
||||
await notificationService.cancelNotification(notification.identifier);
|
||||
@@ -424,7 +515,7 @@ export class GeneralNotificationHelpers {
|
||||
*/
|
||||
static async sendBatchNotifications(notifications: NotificationData[]) {
|
||||
const results = [];
|
||||
|
||||
|
||||
for (const notification of notifications) {
|
||||
try {
|
||||
const id = await notificationService.sendImmediateNotification(notification);
|
||||
@@ -433,7 +524,7 @@ export class GeneralNotificationHelpers {
|
||||
results.push({ success: false, error, notification });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
@@ -491,5 +582,12 @@ export const NotificationTemplates = {
|
||||
sound: true,
|
||||
priority: 'normal' as const,
|
||||
}),
|
||||
lunch: (userName: string) => ({
|
||||
title: '午餐记录提醒',
|
||||
body: `${userName},记得记录今天的午餐情况哦!`,
|
||||
data: { type: 'lunch_reminder', meal: '午餐' },
|
||||
sound: true,
|
||||
priority: 'normal' as const,
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user