feat(water): 重构饮水模块并新增自定义提醒设置功能

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

View File

@@ -7,6 +7,10 @@ const PREFERENCES_KEYS = {
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;
// 用户偏好设置接口
@@ -16,6 +20,10 @@ export interface UserPreferences {
notificationEnabled: boolean;
fitnessExerciseMinutesInfoDismissed: boolean;
fitnessActiveHoursInfoDismissed: boolean;
waterReminderEnabled: boolean;
waterReminderStartTime: string; // 格式: "08:00"
waterReminderEndTime: string; // 格式: "22:00"
waterReminderInterval: number; // 分钟
}
// 默认的用户偏好设置
@@ -25,6 +33,10 @@ const DEFAULT_PREFERENCES: UserPreferences = {
notificationEnabled: true, // 默认开启消息推送
fitnessExerciseMinutesInfoDismissed: false, // 默认显示锻炼分钟说明
fitnessActiveHoursInfoDismissed: false, // 默认显示活动小时说明
waterReminderEnabled: true, // 默认关闭喝水提醒
waterReminderStartTime: '08:00', // 默认开始时间早上8点
waterReminderEndTime: '22:00', // 默认结束时间晚上10点
waterReminderInterval: 60, // 默认提醒间隔60分钟
};
/**
@@ -37,6 +49,10 @@ export const getUserPreferences = async (): Promise<UserPreferences> => {
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,
@@ -44,6 +60,10 @@ export const getUserPreferences = async (): Promise<UserPreferences> => {
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);
@@ -185,6 +205,163 @@ export const getFitnessActiveHoursInfoDismissed = async (): Promise<boolean> =>
}
};
/**
* 设置喝水提醒开关
* @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;
}
};
/**
* 重置所有用户偏好设置为默认值
*/
@@ -194,6 +371,10 @@ export const resetUserPreferences = async (): Promise<void> => {
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;