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:
@@ -15,9 +15,12 @@ import { Ionicons } from '@expo/vector-icons';
|
||||
import dayjs from 'dayjs';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { router, useLocalSearchParams } from 'expo-router';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
Alert, Image,
|
||||
Keyboard,
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
@@ -43,6 +46,9 @@ export default function MoodEditScreen() {
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
const [existingMood, setExistingMood] = useState<any>(null);
|
||||
|
||||
const scrollViewRef = useRef<ScrollView>(null);
|
||||
const textInputRef = useRef<TextInput>(null);
|
||||
|
||||
const moodOptions = getMoodOptions();
|
||||
|
||||
// 从 Redux 获取数据
|
||||
@@ -66,6 +72,25 @@ export default function MoodEditScreen() {
|
||||
}
|
||||
}, [moodId, moodRecords]);
|
||||
|
||||
// 键盘事件监听器
|
||||
useEffect(() => {
|
||||
const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => {
|
||||
// 键盘出现时,延迟滚动到文本输入框
|
||||
setTimeout(() => {
|
||||
scrollViewRef.current?.scrollToEnd({ animated: true });
|
||||
}, 100);
|
||||
});
|
||||
|
||||
const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => {
|
||||
// 键盘隐藏时,可以进行必要的调整
|
||||
});
|
||||
|
||||
return () => {
|
||||
keyboardDidShowListener?.remove();
|
||||
keyboardDidHideListener?.remove();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!selectedMood) {
|
||||
Alert.alert('提示', '请选择心情');
|
||||
@@ -163,7 +188,18 @@ export default function MoodEditScreen() {
|
||||
tone="light"
|
||||
/>
|
||||
|
||||
<ScrollView style={styles.content}>
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
style={styles.keyboardAvoidingView}
|
||||
keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : 0}
|
||||
>
|
||||
<ScrollView
|
||||
ref={scrollViewRef}
|
||||
style={styles.content}
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
{/* 日期显示 */}
|
||||
<View style={styles.dateSection}>
|
||||
<Text style={styles.dateTitle}>
|
||||
@@ -211,6 +247,7 @@ export default function MoodEditScreen() {
|
||||
<Text style={styles.sectionTitle}>心情日记</Text>
|
||||
<Text style={styles.diarySubtitle}>记录你的心情,珍藏美好回忆</Text>
|
||||
<TextInput
|
||||
ref={textInputRef}
|
||||
style={styles.descriptionInput}
|
||||
placeholder={`今天的心情如何?
|
||||
|
||||
@@ -225,11 +262,18 @@ export default function MoodEditScreen() {
|
||||
multiline
|
||||
maxLength={1000}
|
||||
textAlignVertical="top"
|
||||
onFocus={() => {
|
||||
// 当文本输入框获得焦点时,滚动到输入框
|
||||
setTimeout(() => {
|
||||
scrollViewRef.current?.scrollToEnd({ animated: true });
|
||||
}, 300);
|
||||
}}
|
||||
/>
|
||||
<Text style={styles.characterCount}>{description.length}/1000</Text>
|
||||
</View>
|
||||
|
||||
</ScrollView>
|
||||
</ScrollView>
|
||||
</KeyboardAvoidingView>
|
||||
|
||||
{/* 底部按钮 */}
|
||||
<View style={styles.footer}>
|
||||
@@ -294,10 +338,15 @@ const styles = StyleSheet.create({
|
||||
safeArea: {
|
||||
flex: 1,
|
||||
},
|
||||
|
||||
keyboardAvoidingView: {
|
||||
flex: 1,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
},
|
||||
scrollContent: {
|
||||
paddingBottom: 100, // 为底部按钮留出空间
|
||||
},
|
||||
dateSection: {
|
||||
backgroundColor: 'rgba(255,255,255,0.95)',
|
||||
margin: 12,
|
||||
|
||||
Reference in New Issue
Block a user