Files
digital-pilates/utils/userPreferences.ts
richarjiang a014998848 feat(water): 重构饮水模块并新增自定义提醒设置功能
- 新增饮水详情页面 `/water/detail` 展示每日饮水记录与统计
- 新增饮水设置页面 `/water/settings` 支持目标与快速添加配置
- 新增喝水提醒设置页面 `/water/reminder-settings` 支持自定义时间段与间隔
- 重构 `useWaterData` Hook,支持按日期查询与实时刷新
- 新增 `WaterNotificationHelpers.scheduleCustomWaterReminders` 实现个性化提醒
- 优化心情编辑页键盘体验,新增 `KeyboardAvoidingView` 与滚动逻辑
- 升级版本号至 1.0.14 并补充路由常量
- 补充用户偏好存储字段 `waterReminderEnabled/startTime/endTime/interval`
- 废弃后台定时任务中的旧版喝水提醒逻辑,改为用户手动管理
2025-09-26 11:02:17 +08:00

382 lines
14 KiB
TypeScript
Raw Permalink 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.

import AsyncStorage from '@/utils/kvStore';
// 用户偏好设置的存储键
const PREFERENCES_KEYS = {
QUICK_WATER_AMOUNT: 'user_preference_quick_water_amount',
WATER_GOAL: 'user_preference_water_goal',
NOTIFICATION_ENABLED: 'user_preference_notification_enabled',
FITNESS_EXERCISE_MINUTES_INFO_DISMISSED: 'user_preference_fitness_exercise_minutes_info_dismissed',
FITNESS_ACTIVE_HOURS_INFO_DISMISSED: 'user_preference_fitness_active_hours_info_dismissed',
WATER_REMINDER_ENABLED: 'user_preference_water_reminder_enabled',
WATER_REMINDER_START_TIME: 'user_preference_water_reminder_start_time',
WATER_REMINDER_END_TIME: 'user_preference_water_reminder_end_time',
WATER_REMINDER_INTERVAL: 'user_preference_water_reminder_interval',
} as const;
// 用户偏好设置接口
export interface UserPreferences {
quickWaterAmount: number;
waterGoal: number;
notificationEnabled: boolean;
fitnessExerciseMinutesInfoDismissed: boolean;
fitnessActiveHoursInfoDismissed: boolean;
waterReminderEnabled: boolean;
waterReminderStartTime: string; // 格式: "08:00"
waterReminderEndTime: string; // 格式: "22:00"
waterReminderInterval: number; // 分钟
}
// 默认的用户偏好设置
const DEFAULT_PREFERENCES: UserPreferences = {
quickWaterAmount: 150, // 默认快速添加饮水量为 150ml
waterGoal: 2000, // 默认每日饮水目标为 2000ml
notificationEnabled: true, // 默认开启消息推送
fitnessExerciseMinutesInfoDismissed: false, // 默认显示锻炼分钟说明
fitnessActiveHoursInfoDismissed: false, // 默认显示活动小时说明
waterReminderEnabled: true, // 默认关闭喝水提醒
waterReminderStartTime: '08:00', // 默认开始时间早上8点
waterReminderEndTime: '22:00', // 默认结束时间晚上10点
waterReminderInterval: 60, // 默认提醒间隔60分钟
};
/**
* 获取用户偏好设置
*/
export const getUserPreferences = async (): Promise<UserPreferences> => {
try {
const quickWaterAmount = await AsyncStorage.getItem(PREFERENCES_KEYS.QUICK_WATER_AMOUNT);
const waterGoal = await AsyncStorage.getItem(PREFERENCES_KEYS.WATER_GOAL);
const notificationEnabled = await AsyncStorage.getItem(PREFERENCES_KEYS.NOTIFICATION_ENABLED);
const fitnessExerciseMinutesInfoDismissed = await AsyncStorage.getItem(PREFERENCES_KEYS.FITNESS_EXERCISE_MINUTES_INFO_DISMISSED);
const fitnessActiveHoursInfoDismissed = await AsyncStorage.getItem(PREFERENCES_KEYS.FITNESS_ACTIVE_HOURS_INFO_DISMISSED);
const waterReminderEnabled = await AsyncStorage.getItem(PREFERENCES_KEYS.WATER_REMINDER_ENABLED);
const waterReminderStartTime = await AsyncStorage.getItem(PREFERENCES_KEYS.WATER_REMINDER_START_TIME);
const waterReminderEndTime = await AsyncStorage.getItem(PREFERENCES_KEYS.WATER_REMINDER_END_TIME);
const waterReminderInterval = await AsyncStorage.getItem(PREFERENCES_KEYS.WATER_REMINDER_INTERVAL);
return {
quickWaterAmount: quickWaterAmount ? parseInt(quickWaterAmount, 10) : DEFAULT_PREFERENCES.quickWaterAmount,
waterGoal: waterGoal ? parseInt(waterGoal, 10) : DEFAULT_PREFERENCES.waterGoal,
notificationEnabled: notificationEnabled !== null ? notificationEnabled === 'true' : DEFAULT_PREFERENCES.notificationEnabled,
fitnessExerciseMinutesInfoDismissed: fitnessExerciseMinutesInfoDismissed !== null ? fitnessExerciseMinutesInfoDismissed === 'true' : DEFAULT_PREFERENCES.fitnessExerciseMinutesInfoDismissed,
fitnessActiveHoursInfoDismissed: fitnessActiveHoursInfoDismissed !== null ? fitnessActiveHoursInfoDismissed === 'true' : DEFAULT_PREFERENCES.fitnessActiveHoursInfoDismissed,
waterReminderEnabled: waterReminderEnabled !== null ? waterReminderEnabled === 'true' : DEFAULT_PREFERENCES.waterReminderEnabled,
waterReminderStartTime: waterReminderStartTime || DEFAULT_PREFERENCES.waterReminderStartTime,
waterReminderEndTime: waterReminderEndTime || DEFAULT_PREFERENCES.waterReminderEndTime,
waterReminderInterval: waterReminderInterval ? parseInt(waterReminderInterval, 10) : DEFAULT_PREFERENCES.waterReminderInterval,
};
} catch (error) {
console.error('获取用户偏好设置失败:', error);
return DEFAULT_PREFERENCES;
}
};
/**
* 设置快速添加饮水的默认值
* @param amount 饮水量(毫升)
*/
export const setQuickWaterAmount = async (amount: number): Promise<void> => {
try {
// 确保值在合理范围内50ml - 1000ml
const validAmount = Math.max(50, Math.min(1000, amount));
await AsyncStorage.setItem(PREFERENCES_KEYS.QUICK_WATER_AMOUNT, validAmount.toString());
} catch (error) {
console.error('设置快速添加饮水默认值失败:', error);
throw error;
}
};
/**
* 获取快速添加饮水的默认值
*/
export const getQuickWaterAmount = async (): Promise<number> => {
try {
const amount = await AsyncStorage.getItem(PREFERENCES_KEYS.QUICK_WATER_AMOUNT);
return amount ? parseInt(amount, 10) : DEFAULT_PREFERENCES.quickWaterAmount;
} catch (error) {
console.error('获取快速添加饮水默认值失败:', error);
return DEFAULT_PREFERENCES.quickWaterAmount;
}
};
/**
* 设置每日饮水目标
* @param goal 饮水目标(毫升)
*/
export const setWaterGoalToStorage = async (goal: number): Promise<void> => {
try {
// 确保值在合理范围内500ml - 5000ml
const validGoal = Math.max(500, Math.min(5000, goal));
await AsyncStorage.setItem(PREFERENCES_KEYS.WATER_GOAL, validGoal.toString());
} catch (error) {
console.error('设置每日饮水目标失败:', error);
throw error;
}
};
/**
* 获取每日饮水目标
*/
export const getWaterGoalFromStorage = async (): Promise<number> => {
try {
const goal = await AsyncStorage.getItem(PREFERENCES_KEYS.WATER_GOAL);
return goal ? parseInt(goal, 10) : DEFAULT_PREFERENCES.waterGoal;
} catch (error) {
console.error('获取每日饮水目标失败:', error);
return DEFAULT_PREFERENCES.waterGoal;
}
};
/**
* 设置消息推送开关
* @param enabled 是否开启消息推送
*/
export const setNotificationEnabled = async (enabled: boolean): Promise<void> => {
try {
await AsyncStorage.setItem(PREFERENCES_KEYS.NOTIFICATION_ENABLED, enabled.toString());
} catch (error) {
console.error('设置消息推送开关失败:', error);
throw error;
}
};
/**
* 获取消息推送开关状态
*/
export const getNotificationEnabled = async (): Promise<boolean> => {
try {
const enabled = await AsyncStorage.getItem(PREFERENCES_KEYS.NOTIFICATION_ENABLED);
return enabled !== null ? enabled === 'true' : DEFAULT_PREFERENCES.notificationEnabled;
} catch (error) {
console.error('获取消息推送开关状态失败:', error);
return DEFAULT_PREFERENCES.notificationEnabled;
}
};
/**
* 设置健身锻炼分钟说明已阅读状态
* @param dismissed 是否已阅读
*/
export const setFitnessExerciseMinutesInfoDismissed = async (dismissed: boolean): Promise<void> => {
try {
await AsyncStorage.setItem(PREFERENCES_KEYS.FITNESS_EXERCISE_MINUTES_INFO_DISMISSED, dismissed.toString());
} catch (error) {
console.error('设置健身锻炼分钟说明已阅读状态失败:', error);
throw error;
}
};
/**
* 获取健身锻炼分钟说明已阅读状态
*/
export const getFitnessExerciseMinutesInfoDismissed = async (): Promise<boolean> => {
try {
const dismissed = await AsyncStorage.getItem(PREFERENCES_KEYS.FITNESS_EXERCISE_MINUTES_INFO_DISMISSED);
return dismissed !== null ? dismissed === 'true' : DEFAULT_PREFERENCES.fitnessExerciseMinutesInfoDismissed;
} catch (error) {
console.error('获取健身锻炼分钟说明已阅读状态失败:', error);
return DEFAULT_PREFERENCES.fitnessExerciseMinutesInfoDismissed;
}
};
/**
* 设置健身活动小时说明已阅读状态
* @param dismissed 是否已阅读
*/
export const setFitnessActiveHoursInfoDismissed = async (dismissed: boolean): Promise<void> => {
try {
await AsyncStorage.setItem(PREFERENCES_KEYS.FITNESS_ACTIVE_HOURS_INFO_DISMISSED, dismissed.toString());
} catch (error) {
console.error('设置健身活动小时说明已阅读状态失败:', error);
throw error;
}
};
/**
* 获取健身活动小时说明已阅读状态
*/
export const getFitnessActiveHoursInfoDismissed = async (): Promise<boolean> => {
try {
const dismissed = await AsyncStorage.getItem(PREFERENCES_KEYS.FITNESS_ACTIVE_HOURS_INFO_DISMISSED);
return dismissed !== null ? dismissed === 'true' : DEFAULT_PREFERENCES.fitnessActiveHoursInfoDismissed;
} catch (error) {
console.error('获取健身活动小时说明已阅读状态失败:', error);
return DEFAULT_PREFERENCES.fitnessActiveHoursInfoDismissed;
}
};
/**
* 设置喝水提醒开关
* @param enabled 是否开启喝水提醒
*/
export const setWaterReminderEnabled = async (enabled: boolean): Promise<void> => {
try {
await AsyncStorage.setItem(PREFERENCES_KEYS.WATER_REMINDER_ENABLED, enabled.toString());
} catch (error) {
console.error('设置喝水提醒开关失败:', error);
throw error;
}
};
/**
* 获取喝水提醒开关状态
*/
export const getWaterReminderEnabled = async (): Promise<boolean> => {
try {
const enabled = await AsyncStorage.getItem(PREFERENCES_KEYS.WATER_REMINDER_ENABLED);
return enabled !== null ? enabled === 'true' : DEFAULT_PREFERENCES.waterReminderEnabled;
} catch (error) {
console.error('获取喝水提醒开关状态失败:', error);
return DEFAULT_PREFERENCES.waterReminderEnabled;
}
};
/**
* 设置喝水提醒开始时间
* @param startTime 开始时间,格式为 "HH:mm"
*/
export const setWaterReminderStartTime = async (startTime: string): Promise<void> => {
try {
await AsyncStorage.setItem(PREFERENCES_KEYS.WATER_REMINDER_START_TIME, startTime);
} catch (error) {
console.error('设置喝水提醒开始时间失败:', error);
throw error;
}
};
/**
* 获取喝水提醒开始时间
*/
export const getWaterReminderStartTime = async (): Promise<string> => {
try {
const startTime = await AsyncStorage.getItem(PREFERENCES_KEYS.WATER_REMINDER_START_TIME);
return startTime || DEFAULT_PREFERENCES.waterReminderStartTime;
} catch (error) {
console.error('获取喝水提醒开始时间失败:', error);
return DEFAULT_PREFERENCES.waterReminderStartTime;
}
};
/**
* 设置喝水提醒结束时间
* @param endTime 结束时间,格式为 "HH:mm"
*/
export const setWaterReminderEndTime = async (endTime: string): Promise<void> => {
try {
await AsyncStorage.setItem(PREFERENCES_KEYS.WATER_REMINDER_END_TIME, endTime);
} catch (error) {
console.error('设置喝水提醒结束时间失败:', error);
throw error;
}
};
/**
* 获取喝水提醒结束时间
*/
export const getWaterReminderEndTime = async (): Promise<string> => {
try {
const endTime = await AsyncStorage.getItem(PREFERENCES_KEYS.WATER_REMINDER_END_TIME);
return endTime || DEFAULT_PREFERENCES.waterReminderEndTime;
} catch (error) {
console.error('获取喝水提醒结束时间失败:', error);
return DEFAULT_PREFERENCES.waterReminderEndTime;
}
};
/**
* 设置喝水提醒间隔时间
* @param interval 间隔时间(分钟),范围 30-180
*/
export const setWaterReminderInterval = async (interval: number): Promise<void> => {
try {
// 确保值在合理范围内30-180分钟
const validInterval = Math.max(30, Math.min(180, interval));
await AsyncStorage.setItem(PREFERENCES_KEYS.WATER_REMINDER_INTERVAL, validInterval.toString());
} catch (error) {
console.error('设置喝水提醒间隔时间失败:', error);
throw error;
}
};
/**
* 获取喝水提醒间隔时间
*/
export const getWaterReminderInterval = async (): Promise<number> => {
try {
const interval = await AsyncStorage.getItem(PREFERENCES_KEYS.WATER_REMINDER_INTERVAL);
return interval ? parseInt(interval, 10) : DEFAULT_PREFERENCES.waterReminderInterval;
} catch (error) {
console.error('获取喝水提醒间隔时间失败:', error);
return DEFAULT_PREFERENCES.waterReminderInterval;
}
};
/**
* 获取完整的喝水提醒配置
*/
export const getWaterReminderSettings = async () => {
try {
const [enabled, startTime, endTime, interval] = await Promise.all([
getWaterReminderEnabled(),
getWaterReminderStartTime(),
getWaterReminderEndTime(),
getWaterReminderInterval(),
]);
return {
enabled,
startTime,
endTime,
interval,
};
} catch (error) {
console.error('获取喝水提醒配置失败:', error);
return {
enabled: DEFAULT_PREFERENCES.waterReminderEnabled,
startTime: DEFAULT_PREFERENCES.waterReminderStartTime,
endTime: DEFAULT_PREFERENCES.waterReminderEndTime,
interval: DEFAULT_PREFERENCES.waterReminderInterval,
};
}
};
/**
* 批量设置喝水提醒配置
*/
export const setWaterReminderSettings = async (settings: {
enabled: boolean;
startTime: string;
endTime: string;
interval: number;
}): Promise<void> => {
try {
await Promise.all([
setWaterReminderEnabled(settings.enabled),
setWaterReminderStartTime(settings.startTime),
setWaterReminderEndTime(settings.endTime),
setWaterReminderInterval(settings.interval),
]);
} catch (error) {
console.error('批量设置喝水提醒配置失败:', error);
throw error;
}
};
/**
* 重置所有用户偏好设置为默认值
*/
export const resetUserPreferences = async (): Promise<void> => {
try {
await AsyncStorage.removeItem(PREFERENCES_KEYS.QUICK_WATER_AMOUNT);
await AsyncStorage.removeItem(PREFERENCES_KEYS.NOTIFICATION_ENABLED);
await AsyncStorage.removeItem(PREFERENCES_KEYS.FITNESS_EXERCISE_MINUTES_INFO_DISMISSED);
await AsyncStorage.removeItem(PREFERENCES_KEYS.FITNESS_ACTIVE_HOURS_INFO_DISMISSED);
await AsyncStorage.removeItem(PREFERENCES_KEYS.WATER_REMINDER_ENABLED);
await AsyncStorage.removeItem(PREFERENCES_KEYS.WATER_REMINDER_START_TIME);
await AsyncStorage.removeItem(PREFERENCES_KEYS.WATER_REMINDER_END_TIME);
await AsyncStorage.removeItem(PREFERENCES_KEYS.WATER_REMINDER_INTERVAL);
} catch (error) {
console.error('重置用户偏好设置失败:', error);
throw error;
}
};