import MoodIntensitySlider from '@/components/MoodIntensitySlider'; import { HeaderBar } from '@/components/ui/HeaderBar'; import { Colors } from '@/constants/Colors'; import { useAppDispatch, useAppSelector } from '@/hooks/redux'; import { useColorScheme } from '@/hooks/useColorScheme'; import { useI18n } from '@/hooks/useI18n'; import { useSafeAreaTop } from '@/hooks/useSafeAreaWithPadding'; import { getMoodOptions, MoodType } from '@/services/moodCheckins'; import { createMoodRecord, deleteMoodRecord, fetchDailyMoodCheckins, selectMoodRecordsByDate, updateMoodRecord } from '@/store/moodSlice'; 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, useRef, useState } from 'react'; import { Alert, Image, Keyboard, KeyboardAvoidingView, Platform, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'; export default function MoodEditScreen() { const { t } = useI18n(); const safeAreaTop = useSafeAreaTop() const theme = (useColorScheme() ?? 'light') as 'light' | 'dark'; const colorTokens = Colors[theme]; const params = useLocalSearchParams(); const dispatch = useAppDispatch(); const { date, moodId } = params; const selectedDate = date as string || dayjs().format('YYYY-MM-DD'); const [selectedMood, setSelectedMood] = useState(''); const [intensity, setIntensity] = useState(5); const [description, setDescription] = useState(''); const [isLoading, setIsLoading] = useState(false); const [isDeleting, setIsDeleting] = useState(false); const [existingMood, setExistingMood] = useState(null); const scrollViewRef = useRef(null); const textInputRef = useRef(null); const moodOptions = getMoodOptions(t); // 从 Redux 获取数据 const moodRecords = useAppSelector(selectMoodRecordsByDate(selectedDate)); const loading = useAppSelector(state => state.mood.loading); // 初始化数据 useEffect(() => { // 加载当前日期的心情记录 dispatch(fetchDailyMoodCheckins(selectedDate)); }, [selectedDate, dispatch]); // 当 moodRecords 更新时,查找现有记录 useEffect(() => { if (moodId && moodRecords.length > 0) { const mood = moodRecords.find((c: any) => c.id === moodId) || moodRecords[0]; setExistingMood(mood); setSelectedMood(mood.moodType); setIntensity(mood.intensity); setDescription(mood.description || ''); } }, [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(t('common.alert'), t('mood.edit.alerts.selectMood')); return; } try { setIsLoading(true); if (existingMood) { // 更新现有记录 await dispatch(updateMoodRecord({ id: existingMood.id, moodType: selectedMood, intensity, description: description.trim() || undefined, })).unwrap(); } else { // 创建新记录 await dispatch(createMoodRecord({ moodType: selectedMood, intensity, description: description.trim() || undefined, checkinDate: selectedDate, })).unwrap(); } Alert.alert(t('common.success'), existingMood ? t('mood.edit.alerts.updateSuccess') : t('mood.edit.alerts.saveSuccess'), [ { text: t('common.confirm'), onPress: () => router.back() } ]); } catch (error) { console.error('保存心情失败:', error); Alert.alert(t('common.error'), t('mood.edit.alerts.saveError')); } finally { setIsLoading(false); } }; const handleDelete = async () => { if (!existingMood) return; Alert.alert( t('mood.edit.alerts.confirmDeleteTitle'), t('mood.edit.alerts.confirmDelete'), [ { text: t('common.cancel'), style: 'cancel' }, { text: t('common.delete'), style: 'destructive', onPress: async () => { try { setIsDeleting(true); await dispatch(deleteMoodRecord({ id: existingMood.id })).unwrap(); Alert.alert(t('common.success'), t('mood.edit.alerts.deleteSuccess'), [ { text: t('common.confirm'), onPress: () => router.back() } ]); } catch (error) { console.error('删除心情失败:', error); Alert.alert(t('common.error'), t('mood.edit.alerts.deleteError')); } finally { setIsDeleting(false); } }, }, ] ); }; const handleIntensityChange = (value: number) => { setIntensity(value); }; // 使用统一的渐变背景色 const backgroundGradientColors = [colorTokens.backgroundGradientStart, colorTokens.backgroundGradientEnd] as const; return ( {/* 装饰性圆圈 */} router.back()} withSafeTop={false} transparent={true} tone="light" /> {/* 日期显示 */} {dayjs(selectedDate).format(t('mood.edit.dateFormat'))} {/* 心情选择 */} {t('mood.edit.selectMood')} {moodOptions.map((mood, index) => ( setSelectedMood(mood.type)} > {mood.label} ))} {/* 心情强度选择 */} {t('mood.edit.intensity')} {/* 心情描述 */} {t('mood.edit.diary')} {t('mood.edit.diarySubtitle')} { // 当文本输入框获得焦点时,滚动到输入框 setTimeout(() => { scrollViewRef.current?.scrollToEnd({ animated: true }); }, 300); }} /> {description.length}/1000 {/* 底部按钮 */} {isLoading ? t('mood.edit.saving') : existingMood ? t('mood.edit.update') : t('mood.edit.save')} {existingMood && ( )} ); } const styles = StyleSheet.create({ container: { flex: 1, }, gradientBackground: { position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, }, decorativeCircle1: { position: 'absolute', top: 30, right: 15, width: 45, height: 45, borderRadius: 22.5, backgroundColor: '#7a5af8', opacity: 0.06, }, decorativeCircle2: { position: 'absolute', bottom: -10, left: -10, width: 30, height: 30, borderRadius: 15, backgroundColor: '#7a5af8', opacity: 0.04, }, safeArea: { flex: 1, }, keyboardAvoidingView: { flex: 1, }, content: { flex: 1, }, scrollContent: { paddingBottom: 100, // 为底部按钮留出空间 }, dateSection: { backgroundColor: 'rgba(255,255,255,0.95)', margin: 12, borderRadius: 16, padding: 16, alignItems: 'center', shadowColor: '#7a5af8', shadowOffset: { width: 0, height: 3 }, shadowOpacity: 0.08, shadowRadius: 8, elevation: 4, }, dateTitle: { fontSize: 20, fontWeight: '700', color: '#192126', }, moodSection: { backgroundColor: 'rgba(255,255,255,0.95)', margin: 12, marginTop: 0, borderRadius: 16, padding: 16, shadowColor: '#7a5af8', shadowOffset: { width: 0, height: 3 }, shadowOpacity: 0.08, shadowRadius: 8, elevation: 4, }, sectionTitle: { fontSize: 16, fontWeight: '600', color: '#192126', marginBottom: 16, }, moodOptions: { flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between', }, moodOption: { width: '18%', alignItems: 'center', paddingVertical: 12, marginBottom: 8, borderRadius: 12, backgroundColor: 'rgba(122,90,248,0.05)', borderWidth: 1, borderColor: 'rgba(122,90,248,0.1)', }, selectedMoodOption: { backgroundColor: 'rgba(122,90,248,0.15)', borderWidth: 2, borderColor: '#7a5af8', shadowColor: '#7a5af8', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.12, shadowRadius: 3, elevation: 2, }, moodImage: { width: 32, height: 32, marginBottom: 6, }, moodLabel: { fontSize: 12, color: '#192126', fontWeight: '500', }, intensitySection: { backgroundColor: 'rgba(255,255,255,0.95)', margin: 12, marginTop: 0, borderRadius: 16, padding: 16, shadowColor: '#7a5af8', shadowOffset: { width: 0, height: 3 }, shadowOpacity: 0.08, shadowRadius: 8, elevation: 4, }, descriptionSection: { backgroundColor: 'rgba(255,255,255,0.95)', margin: 12, marginTop: 0, borderRadius: 16, padding: 16, shadowColor: '#7a5af8', shadowOffset: { width: 0, height: 3 }, shadowOpacity: 0.08, shadowRadius: 8, elevation: 4, }, diarySubtitle: { fontSize: 13, color: '#666', fontWeight: '500', marginBottom: 12, lineHeight: 18, }, descriptionInput: { borderWidth: 1.5, borderColor: 'rgba(122,90,248,0.2)', borderRadius: 10, padding: 12, fontSize: 14, minHeight: 120, textAlignVertical: 'top', backgroundColor: 'rgba(122,90,248,0.02)', color: '#192126', lineHeight: 20, }, characterCount: { fontSize: 12, color: '#777f8c', textAlign: 'right', marginTop: 8, fontWeight: '500', }, footer: { padding: 12, position: 'absolute', bottom: 20, right: 8, }, buttonRow: { flexDirection: 'row', justifyContent: 'flex-end', alignItems: 'center', }, saveButton: { backgroundColor: '#7a5af8', borderRadius: 10, paddingVertical: 10, paddingHorizontal: 20, alignItems: 'center', marginLeft: 8, shadowColor: '#7a5af8', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.15, shadowRadius: 3, elevation: 2, }, deleteIconButton: { width: 32, height: 32, borderRadius: 16, justifyContent: 'center', alignItems: 'center', marginLeft: 8, }, deleteButton: { backgroundColor: '#f95555', borderRadius: 12, paddingVertical: 12, paddingHorizontal: 24, alignItems: 'center', shadowColor: '#f95555', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.2, shadowRadius: 4, elevation: 3, }, disabledButton: { backgroundColor: '#c0c4ca', shadowOpacity: 0, elevation: 0, }, saveButtonText: { color: '#fff', fontSize: 13, fontWeight: '600', }, deleteButtonText: { color: '#fff', fontSize: 14, fontWeight: '600', }, });