feat: 添加心情记录功能
在统计页面新增心情卡片和弹窗组件,支持用户记录和查看每日心情状态。
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { AnimatedNumber } from '@/components/AnimatedNumber';
|
import { AnimatedNumber } from '@/components/AnimatedNumber';
|
||||||
import { BMICard } from '@/components/BMICard';
|
import { BMICard } from '@/components/BMICard';
|
||||||
import { FitnessRingsCard } from '@/components/FitnessRingsCard';
|
import { FitnessRingsCard } from '@/components/FitnessRingsCard';
|
||||||
|
import { MoodModal } from '@/components/MoodModal';
|
||||||
import { NutritionRadarCard } from '@/components/NutritionRadarCard';
|
import { NutritionRadarCard } from '@/components/NutritionRadarCard';
|
||||||
import { ProgressBar } from '@/components/ProgressBar';
|
import { ProgressBar } from '@/components/ProgressBar';
|
||||||
import { StressMeter } from '@/components/StressMeter';
|
import { StressMeter } from '@/components/StressMeter';
|
||||||
@@ -88,7 +89,7 @@ export default function ExploreScreen() {
|
|||||||
|
|
||||||
const { pushIfAuthedElseLogin, isLoggedIn } = useAuthGuard();
|
const { pushIfAuthedElseLogin, isLoggedIn } = useAuthGuard();
|
||||||
|
|
||||||
// 使用 dayjs:当月日期与默认选中“今天”
|
// 使用 dayjs:当月日期与默认选中"今天"
|
||||||
const days = getMonthDaysZh();
|
const days = getMonthDaysZh();
|
||||||
const [selectedIndex, setSelectedIndex] = useState(getTodayIndexInMonth());
|
const [selectedIndex, setSelectedIndex] = useState(getTodayIndexInMonth());
|
||||||
const tabBarHeight = useBottomTabBarHeight();
|
const tabBarHeight = useBottomTabBarHeight();
|
||||||
@@ -161,11 +162,29 @@ export default function ExploreScreen() {
|
|||||||
const [nutritionSummary, setNutritionSummary] = useState<NutritionSummary | null>(null);
|
const [nutritionSummary, setNutritionSummary] = useState<NutritionSummary | null>(null);
|
||||||
const [isNutritionLoading, setIsNutritionLoading] = useState(false);
|
const [isNutritionLoading, setIsNutritionLoading] = useState(false);
|
||||||
|
|
||||||
// 记录最近一次请求的“日期键”,避免旧请求覆盖新结果
|
// 心情相关状态
|
||||||
|
const [moodModalVisible, setMoodModalVisible] = useState(false);
|
||||||
|
const [moodRecords, setMoodRecords] = useState<Array<{ mood: string, date: string, time: string }>>([]);
|
||||||
|
|
||||||
|
// 记录最近一次请求的"日期键",避免旧请求覆盖新结果
|
||||||
const latestRequestKeyRef = useRef<string | null>(null);
|
const latestRequestKeyRef = useRef<string | null>(null);
|
||||||
|
|
||||||
const getDateKey = (d: Date) => `${dayjs(d).year()}-${dayjs(d).month() + 1}-${dayjs(d).date()}`;
|
const getDateKey = (d: Date) => `${dayjs(d).year()}-${dayjs(d).month() + 1}-${dayjs(d).date()}`;
|
||||||
|
|
||||||
|
// 心情保存处理函数
|
||||||
|
const handleMoodSave = (mood: string, time: string) => {
|
||||||
|
const today = new Date();
|
||||||
|
const dateString = `${today.getFullYear()}年${today.getMonth() + 1}月${today.getDate()}日`;
|
||||||
|
|
||||||
|
const newRecord = {
|
||||||
|
mood,
|
||||||
|
date: dateString,
|
||||||
|
time
|
||||||
|
};
|
||||||
|
|
||||||
|
setMoodRecords(prev => [newRecord, ...prev]);
|
||||||
|
setMoodModalVisible(false);
|
||||||
|
};
|
||||||
|
|
||||||
const loadHealthData = async (targetDate?: Date) => {
|
const loadHealthData = async (targetDate?: Date) => {
|
||||||
try {
|
try {
|
||||||
@@ -288,7 +307,6 @@ export default function ExploreScreen() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// 使用统一的渐变背景色
|
// 使用统一的渐变背景色
|
||||||
const backgroundGradientColors = [colorTokens.backgroundGradientStart, colorTokens.backgroundGradientEnd] as const;
|
const backgroundGradientColors = [colorTokens.backgroundGradientStart, colorTokens.backgroundGradientEnd] as const;
|
||||||
|
|
||||||
@@ -404,6 +422,26 @@ export default function ExploreScreen() {
|
|||||||
showLabel={false}
|
showLabel={false}
|
||||||
/>
|
/>
|
||||||
</FloatingCard>
|
</FloatingCard>
|
||||||
|
{/* 心情卡片 */}
|
||||||
|
<FloatingCard style={[styles.masonryCard, styles.moodCard]} delay={1500}>
|
||||||
|
<TouchableOpacity onPress={() => setMoodModalVisible(true)} style={styles.moodCardContent}>
|
||||||
|
<View style={styles.cardHeaderRow}>
|
||||||
|
<View style={styles.moodIconContainer}>
|
||||||
|
<Text style={styles.moodIcon}>😊</Text>
|
||||||
|
</View>
|
||||||
|
<Text style={styles.cardTitle}>心情</Text>
|
||||||
|
</View>
|
||||||
|
<Text style={styles.moodSubtitle}>记录你的每日心情</Text>
|
||||||
|
{moodRecords.length > 0 ? (
|
||||||
|
<View style={styles.moodPreview}>
|
||||||
|
<Text style={styles.moodPreviewText}>今日:{moodRecords[0].mood}</Text>
|
||||||
|
<Text style={styles.moodPreviewTime}>{moodRecords[0].time}</Text>
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<Text style={styles.moodEmptyText}>点击记录心情</Text>
|
||||||
|
)}
|
||||||
|
</TouchableOpacity>
|
||||||
|
</FloatingCard>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* 右列 */}
|
{/* 右列 */}
|
||||||
@@ -413,7 +451,6 @@ export default function ExploreScreen() {
|
|||||||
weight={userProfile?.weight ? parseFloat(userProfile.weight) : undefined}
|
weight={userProfile?.weight ? parseFloat(userProfile.weight) : undefined}
|
||||||
height={userProfile?.height ? parseFloat(userProfile.height) : undefined}
|
height={userProfile?.height ? parseFloat(userProfile.height) : undefined}
|
||||||
style={styles.bmiCardOverride}
|
style={styles.bmiCardOverride}
|
||||||
// compact={true}
|
|
||||||
/>
|
/>
|
||||||
</FloatingCard>
|
</FloatingCard>
|
||||||
|
|
||||||
@@ -441,15 +478,19 @@ export default function ExploreScreen() {
|
|||||||
<Text style={styles.sleepValue}>——</Text>
|
<Text style={styles.sleepValue}>——</Text>
|
||||||
)}
|
)}
|
||||||
</FloatingCard>
|
</FloatingCard>
|
||||||
|
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
|
|
||||||
|
{/* 心情弹窗 */}
|
||||||
|
<MoodModal
|
||||||
|
visible={moodModalVisible}
|
||||||
|
onClose={() => setMoodModalVisible(false)}
|
||||||
|
onSave={handleMoodSave}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -580,7 +621,6 @@ const styles = StyleSheet.create({
|
|||||||
trainingCard: {
|
trainingCard: {
|
||||||
backgroundColor: '#EEE9FF',
|
backgroundColor: '#EEE9FF',
|
||||||
},
|
},
|
||||||
|
|
||||||
cardTitleSecondary: {
|
cardTitleSecondary: {
|
||||||
color: '#9AA3AE',
|
color: '#9AA3AE',
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
@@ -823,4 +863,49 @@ const styles = StyleSheet.create({
|
|||||||
top: 0,
|
top: 0,
|
||||||
padding: 4,
|
padding: 4,
|
||||||
},
|
},
|
||||||
|
moodCard: {
|
||||||
|
backgroundColor: '#F0FDF4',
|
||||||
|
},
|
||||||
|
moodCardContent: {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
moodIconContainer: {
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
borderRadius: 8,
|
||||||
|
backgroundColor: '#DCFCE7',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
marginRight: 10,
|
||||||
|
},
|
||||||
|
moodIcon: {
|
||||||
|
fontSize: 14,
|
||||||
|
},
|
||||||
|
moodSubtitle: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: '#6B7280',
|
||||||
|
marginTop: 4,
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
moodPreview: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginTop: 4,
|
||||||
|
},
|
||||||
|
moodPreviewText: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#059669',
|
||||||
|
fontWeight: '600',
|
||||||
|
},
|
||||||
|
moodPreviewTime: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: '#6B7280',
|
||||||
|
},
|
||||||
|
moodEmptyText: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: '#9CA3AF',
|
||||||
|
fontStyle: 'italic',
|
||||||
|
marginTop: 4,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
76
components/MoodCard.tsx
Normal file
76
components/MoodCard.tsx
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||||
|
import { ThemedText } from './ThemedText';
|
||||||
|
import { ThemedView } from './ThemedView';
|
||||||
|
|
||||||
|
interface MoodCardProps {
|
||||||
|
onPress: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MoodCard({ onPress }: MoodCardProps) {
|
||||||
|
return (
|
||||||
|
<ThemedView style={styles.container}>
|
||||||
|
<View style={styles.header}>
|
||||||
|
<ThemedText style={styles.title}>心情</ThemedText>
|
||||||
|
<ThemedText style={styles.subtitle}>记录你的每日心情</ThemedText>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<TouchableOpacity style={styles.content} onPress={onPress}>
|
||||||
|
<View style={styles.moodIcon}>
|
||||||
|
<Text style={styles.emoji}>😊</Text>
|
||||||
|
</View>
|
||||||
|
<ThemedText style={styles.moodText}>点击记录今日心情</ThemedText>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</ThemedView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
borderRadius: 16,
|
||||||
|
padding: 16,
|
||||||
|
marginBottom: 16,
|
||||||
|
shadowColor: '#000',
|
||||||
|
shadowOffset: {
|
||||||
|
width: 0,
|
||||||
|
height: 2,
|
||||||
|
},
|
||||||
|
shadowOpacity: 0.1,
|
||||||
|
shadowRadius: 3.84,
|
||||||
|
elevation: 5,
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: '600',
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
|
subtitle: {
|
||||||
|
fontSize: 14,
|
||||||
|
opacity: 0.6,
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingVertical: 8,
|
||||||
|
},
|
||||||
|
moodIcon: {
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
borderRadius: 20,
|
||||||
|
backgroundColor: '#f0f0f0',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginRight: 12,
|
||||||
|
},
|
||||||
|
emoji: {
|
||||||
|
fontSize: 20,
|
||||||
|
},
|
||||||
|
moodText: {
|
||||||
|
fontSize: 16,
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
63
components/MoodCardCompact.tsx
Normal file
63
components/MoodCardCompact.tsx
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||||
|
|
||||||
|
interface MoodCardCompactProps {
|
||||||
|
onPress: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MoodCardCompact({ onPress }: MoodCardCompactProps) {
|
||||||
|
return (
|
||||||
|
<TouchableOpacity style={styles.container} onPress={onPress}>
|
||||||
|
<View style={styles.header}>
|
||||||
|
<Text style={styles.title}>心情</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.content}>
|
||||||
|
<View style={styles.moodIcon}>
|
||||||
|
<Text style={styles.emoji}>😊</Text>
|
||||||
|
</View>
|
||||||
|
<Text style={styles.moodText}>记录今日心情</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
backgroundColor: '#E8F5E8',
|
||||||
|
borderRadius: 16,
|
||||||
|
padding: 16,
|
||||||
|
minHeight: 100,
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: '800',
|
||||||
|
color: '#192126',
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
moodIcon: {
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
borderRadius: 16,
|
||||||
|
backgroundColor: '#4CAF50',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginRight: 8,
|
||||||
|
},
|
||||||
|
emoji: {
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
moodText: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: '#2E7D32',
|
||||||
|
fontWeight: '600',
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
422
components/MoodModal.tsx
Normal file
422
components/MoodModal.tsx
Normal file
@@ -0,0 +1,422 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import {
|
||||||
|
Dimensions,
|
||||||
|
Modal,
|
||||||
|
SafeAreaView,
|
||||||
|
ScrollView,
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
} from 'react-native';
|
||||||
|
|
||||||
|
const { width, height } = Dimensions.get('window');
|
||||||
|
|
||||||
|
interface MoodModalProps {
|
||||||
|
visible: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
onSave: (mood: string, date: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 心情日历数据
|
||||||
|
const generateCalendarData = () => {
|
||||||
|
const today = new Date();
|
||||||
|
const year = today.getFullYear();
|
||||||
|
const month = today.getMonth();
|
||||||
|
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
||||||
|
const firstDayOfWeek = new Date(year, month, 1).getDay();
|
||||||
|
|
||||||
|
const calendar = [];
|
||||||
|
const weeks = [];
|
||||||
|
|
||||||
|
// 添加空白日期
|
||||||
|
for (let i = 0; i < firstDayOfWeek; i++) {
|
||||||
|
weeks.push(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加实际日期
|
||||||
|
for (let day = 1; day <= daysInMonth; day++) {
|
||||||
|
weeks.push(day);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按周分组
|
||||||
|
for (let i = 0; i < weeks.length; i += 7) {
|
||||||
|
calendar.push(weeks.slice(i, i + 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
return { calendar, today: today.getDate(), month: month + 1, year };
|
||||||
|
};
|
||||||
|
|
||||||
|
const moodOptions = [
|
||||||
|
{ emoji: '😊', label: '开心', color: '#4CAF50' },
|
||||||
|
{ emoji: '😢', label: '难过', color: '#2196F3' },
|
||||||
|
{ emoji: '😰', label: '焦虑', color: '#FF9800' },
|
||||||
|
{ emoji: '😴', label: '疲惫', color: '#9C27B0' },
|
||||||
|
{ emoji: '😡', label: '愤怒', color: '#F44336' },
|
||||||
|
{ emoji: '😐', label: '平静', color: '#607D8B' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export function MoodModal({ visible, onClose, onSave }: MoodModalProps) {
|
||||||
|
const [selectedMood, setSelectedMood] = useState<string>('');
|
||||||
|
const { calendar, today, month, year } = generateCalendarData();
|
||||||
|
|
||||||
|
const weekDays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
|
||||||
|
const monthNames = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
if (selectedMood) {
|
||||||
|
const now = new Date();
|
||||||
|
const timeString = `${now.getHours()}:${now.getMinutes().toString().padStart(2, '0')}`;
|
||||||
|
onSave(selectedMood, timeString);
|
||||||
|
onClose();
|
||||||
|
setSelectedMood('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderMoodIcon = (day: number | null, isToday: boolean) => {
|
||||||
|
if (!day) return null;
|
||||||
|
|
||||||
|
if (isToday && selectedMood) {
|
||||||
|
const mood = moodOptions.find(m => m.label === selectedMood);
|
||||||
|
return (
|
||||||
|
<View style={[styles.moodIconContainer, { backgroundColor: mood?.color }]}>
|
||||||
|
<View style={styles.bearIcon}>
|
||||||
|
<Text style={styles.bearEmoji}>🐻</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.defaultMoodIcon}>
|
||||||
|
<Text style={styles.defaultMoodEmoji}>😊</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
visible={visible}
|
||||||
|
animationType="slide"
|
||||||
|
presentationStyle="pageSheet"
|
||||||
|
onRequestClose={onClose}
|
||||||
|
>
|
||||||
|
<SafeAreaView style={styles.container}>
|
||||||
|
<View style={styles.header}>
|
||||||
|
<TouchableOpacity onPress={onClose}>
|
||||||
|
<Text style={styles.backButton}>←</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<Text style={styles.headerTitle}>{year}年{monthNames[month - 1]}</Text>
|
||||||
|
<TouchableOpacity>
|
||||||
|
<Text style={styles.nextButton}>→</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<ScrollView style={styles.content}>
|
||||||
|
{/* 日历视图 */}
|
||||||
|
<View style={styles.calendar}>
|
||||||
|
<View style={styles.weekHeader}>
|
||||||
|
{weekDays.map((day, index) => (
|
||||||
|
<Text key={index} style={styles.weekDay}>{day}</Text>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{calendar.map((week, weekIndex) => (
|
||||||
|
<View key={weekIndex} style={styles.weekRow}>
|
||||||
|
{week.map((day, dayIndex) => (
|
||||||
|
<View key={dayIndex} style={styles.dayContainer}>
|
||||||
|
{day && (
|
||||||
|
<>
|
||||||
|
<Text style={[
|
||||||
|
styles.dayNumber,
|
||||||
|
day === today && styles.todayNumber
|
||||||
|
]}>
|
||||||
|
{day.toString().padStart(2, '0')}
|
||||||
|
</Text>
|
||||||
|
{renderMoodIcon(day, day === today)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 心情选择 */}
|
||||||
|
<View style={styles.moodSection}>
|
||||||
|
<Text style={styles.sectionTitle}>选择今日心情</Text>
|
||||||
|
<View style={styles.moodOptions}>
|
||||||
|
{moodOptions.map((mood, index) => (
|
||||||
|
<TouchableOpacity
|
||||||
|
key={index}
|
||||||
|
style={[
|
||||||
|
styles.moodOption,
|
||||||
|
selectedMood === mood.label && styles.selectedMoodOption
|
||||||
|
]}
|
||||||
|
onPress={() => setSelectedMood(mood.label)}
|
||||||
|
>
|
||||||
|
<Text style={styles.moodEmoji}>{mood.emoji}</Text>
|
||||||
|
<Text style={styles.moodLabel}>{mood.label}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 近期记录 */}
|
||||||
|
<View style={styles.recentSection}>
|
||||||
|
<Text style={styles.sectionTitle}>近期记录</Text>
|
||||||
|
<Text style={styles.recentDate}>{year}年{month}月{today}日</Text>
|
||||||
|
|
||||||
|
{selectedMood && (
|
||||||
|
<View style={styles.recentRecord}>
|
||||||
|
<View style={styles.recordIcon}>
|
||||||
|
<View style={styles.bearIcon}>
|
||||||
|
<Text style={styles.bearEmoji}>🐻</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<Text style={styles.recordMood}>{selectedMood}</Text>
|
||||||
|
<View style={styles.spacer} />
|
||||||
|
<Text style={styles.recordTime}>
|
||||||
|
{new Date().getHours()}:{new Date().getMinutes().toString().padStart(2, '0')}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
{/* 保存按钮 */}
|
||||||
|
<View style={styles.footer}>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[styles.saveButton, !selectedMood && styles.disabledButton]}
|
||||||
|
onPress={handleSave}
|
||||||
|
disabled={!selectedMood}
|
||||||
|
>
|
||||||
|
<Text style={styles.saveButtonText}>保存心情</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 添加按钮 */}
|
||||||
|
<TouchableOpacity style={styles.addButton} onPress={handleSave}>
|
||||||
|
<Text style={styles.addButtonText}>+</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</SafeAreaView>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: '#f5f5f5',
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingHorizontal: 20,
|
||||||
|
paddingVertical: 16,
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
},
|
||||||
|
backButton: {
|
||||||
|
fontSize: 24,
|
||||||
|
color: '#666',
|
||||||
|
},
|
||||||
|
headerTitle: {
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: '600',
|
||||||
|
color: '#333',
|
||||||
|
},
|
||||||
|
nextButton: {
|
||||||
|
fontSize: 24,
|
||||||
|
color: '#666',
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
calendar: {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
margin: 16,
|
||||||
|
borderRadius: 16,
|
||||||
|
padding: 16,
|
||||||
|
},
|
||||||
|
weekHeader: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-around',
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
weekDay: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#666',
|
||||||
|
textAlign: 'center',
|
||||||
|
width: (width - 64) / 7,
|
||||||
|
},
|
||||||
|
weekRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-around',
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
dayContainer: {
|
||||||
|
width: (width - 64) / 7,
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
dayNumber: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#999',
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
todayNumber: {
|
||||||
|
color: '#333',
|
||||||
|
fontWeight: '600',
|
||||||
|
},
|
||||||
|
moodIconContainer: {
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
borderRadius: 20,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
bearIcon: {
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
borderRadius: 12,
|
||||||
|
backgroundColor: 'rgba(255,255,255,0.9)',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
bearEmoji: {
|
||||||
|
fontSize: 12,
|
||||||
|
},
|
||||||
|
defaultMoodIcon: {
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
borderRadius: 20,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: '#ddd',
|
||||||
|
borderStyle: 'dashed',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
defaultMoodEmoji: {
|
||||||
|
fontSize: 16,
|
||||||
|
opacity: 0.3,
|
||||||
|
},
|
||||||
|
moodSection: {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
margin: 16,
|
||||||
|
marginTop: 0,
|
||||||
|
borderRadius: 16,
|
||||||
|
padding: 16,
|
||||||
|
},
|
||||||
|
sectionTitle: {
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: '600',
|
||||||
|
color: '#333',
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
moodOptions: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
},
|
||||||
|
moodOption: {
|
||||||
|
width: (width - 80) / 3,
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingVertical: 16,
|
||||||
|
marginBottom: 16,
|
||||||
|
borderRadius: 12,
|
||||||
|
backgroundColor: '#f8f8f8',
|
||||||
|
},
|
||||||
|
selectedMoodOption: {
|
||||||
|
backgroundColor: '#e8f5e8',
|
||||||
|
borderWidth: 2,
|
||||||
|
borderColor: '#4CAF50',
|
||||||
|
},
|
||||||
|
moodEmoji: {
|
||||||
|
fontSize: 24,
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
moodLabel: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#333',
|
||||||
|
},
|
||||||
|
recentSection: {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
margin: 16,
|
||||||
|
marginTop: 0,
|
||||||
|
borderRadius: 16,
|
||||||
|
padding: 16,
|
||||||
|
},
|
||||||
|
recentDate: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#999',
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
recentRecord: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingVertical: 12,
|
||||||
|
},
|
||||||
|
recordIcon: {
|
||||||
|
width: 48,
|
||||||
|
height: 48,
|
||||||
|
borderRadius: 24,
|
||||||
|
backgroundColor: '#4CAF50',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginRight: 12,
|
||||||
|
},
|
||||||
|
recordMood: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: '#333',
|
||||||
|
fontWeight: '500',
|
||||||
|
},
|
||||||
|
spacer: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
recordTime: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#999',
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
padding: 16,
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
},
|
||||||
|
saveButton: {
|
||||||
|
backgroundColor: '#4CAF50',
|
||||||
|
borderRadius: 12,
|
||||||
|
paddingVertical: 16,
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
disabledButton: {
|
||||||
|
backgroundColor: '#ccc',
|
||||||
|
},
|
||||||
|
saveButtonText: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: '600',
|
||||||
|
},
|
||||||
|
addButton: {
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 100,
|
||||||
|
right: 20,
|
||||||
|
width: 56,
|
||||||
|
height: 56,
|
||||||
|
borderRadius: 28,
|
||||||
|
backgroundColor: '#00C853',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
shadowColor: '#000',
|
||||||
|
shadowOffset: {
|
||||||
|
width: 0,
|
||||||
|
height: 2,
|
||||||
|
},
|
||||||
|
shadowOpacity: 0.25,
|
||||||
|
shadowRadius: 3.84,
|
||||||
|
elevation: 5,
|
||||||
|
},
|
||||||
|
addButtonText: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: '300',
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user