feat(workout): 新增锻炼结束监听和个性化通知功能
实现了iOS HealthKit锻炼数据实时监听,当用户完成锻炼时自动发送个性化鼓励通知。包括锻炼类型筛选、时间范围控制、用户偏好设置等完整功能,并提供了测试工具和详细文档。
This commit is contained in:
152
utils/workoutPreferences.ts
Normal file
152
utils/workoutPreferences.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import AsyncStorage from '@/utils/kvStore';
|
||||
|
||||
const WORKOUT_NOTIFICATION_ENABLED_KEY = '@workout_notification_enabled';
|
||||
const WORKOUT_NOTIFICATION_TIME_RANGE_KEY = '@workout_notification_time_range';
|
||||
const WORKOUT_NOTIFICATION_TYPES_KEY = '@workout_notification_types';
|
||||
|
||||
export interface WorkoutNotificationPreferences {
|
||||
enabled: boolean;
|
||||
startTimeHour: number; // 开始时间(小时,0-23)
|
||||
endTimeHour: number; // 结束时间(小时,0-23)
|
||||
enabledWorkoutTypes: string[]; // 启用通知的锻炼类型
|
||||
}
|
||||
|
||||
const DEFAULT_PREFERENCES: WorkoutNotificationPreferences = {
|
||||
enabled: true,
|
||||
startTimeHour: 8, // 早上8点
|
||||
endTimeHour: 22, // 晚上10点
|
||||
enabledWorkoutTypes: [] // 空数组表示所有类型都启用
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取锻炼通知偏好设置
|
||||
*/
|
||||
export async function getWorkoutNotificationPreferences(): Promise<WorkoutNotificationPreferences> {
|
||||
try {
|
||||
const enabled = await AsyncStorage.getItem(WORKOUT_NOTIFICATION_ENABLED_KEY);
|
||||
const timeRange = await AsyncStorage.getItem(WORKOUT_NOTIFICATION_TIME_RANGE_KEY);
|
||||
const workoutTypes = await AsyncStorage.getItem(WORKOUT_NOTIFICATION_TYPES_KEY);
|
||||
|
||||
return {
|
||||
enabled: enabled !== 'false', // 默认启用
|
||||
startTimeHour: timeRange ? JSON.parse(timeRange).start : DEFAULT_PREFERENCES.startTimeHour,
|
||||
endTimeHour: timeRange ? JSON.parse(timeRange).end : DEFAULT_PREFERENCES.endTimeHour,
|
||||
enabledWorkoutTypes: workoutTypes ? JSON.parse(workoutTypes) : DEFAULT_PREFERENCES.enabledWorkoutTypes
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('获取锻炼通知偏好设置失败:', error);
|
||||
return DEFAULT_PREFERENCES;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存锻炼通知偏好设置
|
||||
*/
|
||||
export async function saveWorkoutNotificationPreferences(preferences: Partial<WorkoutNotificationPreferences>): Promise<void> {
|
||||
try {
|
||||
const currentPrefs = await getWorkoutNotificationPreferences();
|
||||
const newPrefs = { ...currentPrefs, ...preferences };
|
||||
|
||||
if (preferences.enabled !== undefined) {
|
||||
await AsyncStorage.setItem(WORKOUT_NOTIFICATION_ENABLED_KEY, preferences.enabled.toString());
|
||||
}
|
||||
|
||||
if (preferences.startTimeHour !== undefined || preferences.endTimeHour !== undefined) {
|
||||
const timeRange = {
|
||||
start: preferences.startTimeHour ?? currentPrefs.startTimeHour,
|
||||
end: preferences.endTimeHour ?? currentPrefs.endTimeHour
|
||||
};
|
||||
await AsyncStorage.setItem(WORKOUT_NOTIFICATION_TIME_RANGE_KEY, JSON.stringify(timeRange));
|
||||
}
|
||||
|
||||
if (preferences.enabledWorkoutTypes !== undefined) {
|
||||
await AsyncStorage.setItem(WORKOUT_NOTIFICATION_TYPES_KEY, JSON.stringify(preferences.enabledWorkoutTypes));
|
||||
}
|
||||
|
||||
console.log('锻炼通知偏好设置已保存:', newPrefs);
|
||||
} catch (error) {
|
||||
console.error('保存锻炼通知偏好设置失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查当前时间是否在允许的通知时间范围内
|
||||
*/
|
||||
export async function isNotificationTimeAllowed(): Promise<boolean> {
|
||||
try {
|
||||
const preferences = await getWorkoutNotificationPreferences();
|
||||
const currentHour = new Date().getHours();
|
||||
|
||||
// 处理跨天的情况(例如 22:00 - 8:00)
|
||||
if (preferences.startTimeHour <= preferences.endTimeHour) {
|
||||
// 正常情况,如 8:00 - 22:00
|
||||
return currentHour >= preferences.startTimeHour && currentHour <= preferences.endTimeHour;
|
||||
} else {
|
||||
// 跨天情况,如 22:00 - 8:00
|
||||
return currentHour >= preferences.startTimeHour || currentHour <= preferences.endTimeHour;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('检查通知时间失败:', error);
|
||||
return true; // 默认允许
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查特定锻炼类型是否启用了通知
|
||||
*/
|
||||
export async function isWorkoutTypeEnabled(workoutType: string): Promise<boolean> {
|
||||
try {
|
||||
const preferences = await getWorkoutNotificationPreferences();
|
||||
|
||||
// 如果启用的类型列表为空,表示所有类型都启用
|
||||
if (preferences.enabledWorkoutTypes.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return preferences.enabledWorkoutTypes.includes(workoutType);
|
||||
} catch (error) {
|
||||
console.error('检查锻炼类型通知设置失败:', error);
|
||||
return true; // 默认允许
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取锻炼通知的简化状态(仅检查是否启用)
|
||||
*/
|
||||
export async function getWorkoutNotificationEnabled(): Promise<boolean> {
|
||||
try {
|
||||
const preferences = await getWorkoutNotificationPreferences();
|
||||
return preferences.enabled;
|
||||
} catch (error) {
|
||||
console.error('获取锻炼通知启用状态失败:', error);
|
||||
return true; // 默认启用
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置锻炼通知启用状态
|
||||
*/
|
||||
export async function setWorkoutNotificationEnabled(enabled: boolean): Promise<void> {
|
||||
try {
|
||||
await saveWorkoutNotificationPreferences({ enabled });
|
||||
} catch (error) {
|
||||
console.error('设置锻炼通知启用状态失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置锻炼通知偏好设置为默认值
|
||||
*/
|
||||
export async function resetWorkoutNotificationPreferences(): Promise<void> {
|
||||
try {
|
||||
await AsyncStorage.removeItem(WORKOUT_NOTIFICATION_ENABLED_KEY);
|
||||
await AsyncStorage.removeItem(WORKOUT_NOTIFICATION_TIME_RANGE_KEY);
|
||||
await AsyncStorage.removeItem(WORKOUT_NOTIFICATION_TYPES_KEY);
|
||||
console.log('锻炼通知偏好设置已重置为默认值');
|
||||
} catch (error) {
|
||||
console.error('重置锻炼通知偏好设置失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user