feat: Refactor MoodCalendarScreen to use dayjs for date handling and improve calendar data generation
feat: Update FitnessRingsCard to navigate to fitness rings detail page on press feat: Modify NutritionRadarCard to enhance UI and add haptic feedback on actions feat: Add FITNESS_RINGS_DETAIL route for navigation fix: Adjust minimum fetch interval in BackgroundTaskManager for background tasks feat: Implement haptic feedback utility functions for better user experience feat: Extend health permissions to include Apple Exercise Time and Apple Stand Time feat: Add functions to fetch hourly activity, exercise, and stand data for improved health tracking feat: Enhance user preferences to manage fitness exercise minutes and active hours info dismissal
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
import { HeaderBar } from '@/components/ui/HeaderBar';
|
||||
import { Colors } from '@/constants/Colors';
|
||||
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
|
||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
||||
import { useAppSelector } from '@/hooks/redux';
|
||||
import { useMoodData } from '@/hooks/useMoodData';
|
||||
import { getMoodOptions } from '@/services/moodCheckins';
|
||||
import { selectLatestMoodRecordByDate } from '@/store/moodSlice';
|
||||
@@ -22,16 +20,22 @@ const { width } = Dimensions.get('window');
|
||||
|
||||
// 心情日历数据生成函数
|
||||
const generateCalendarData = (targetDate: Date) => {
|
||||
const year = targetDate.getFullYear();
|
||||
const month = targetDate.getMonth();
|
||||
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
||||
const firstDayOfWeek = new Date(year, month, 1).getDay();
|
||||
// 使用 dayjs 确保时区一致性
|
||||
const targetDayjs = dayjs(targetDate);
|
||||
const year = targetDayjs.year();
|
||||
const month = targetDayjs.month(); // dayjs month is 0-based
|
||||
const daysInMonth = targetDayjs.daysInMonth();
|
||||
|
||||
// 使用 dayjs 获取月初第一天是周几(0=周日,1=周一...6=周六)
|
||||
const firstDayOfWeek = targetDayjs.startOf('month').day();
|
||||
// 转换为中国习惯(周一为一周开始):周日(0)转为6,其他减1
|
||||
const firstDayAdjusted = firstDayOfWeek === 0 ? 6 : firstDayOfWeek - 1;
|
||||
|
||||
const calendar = [];
|
||||
const weeks = [];
|
||||
|
||||
// 添加空白日期
|
||||
for (let i = 0; i < firstDayOfWeek; i++) {
|
||||
// 添加空白日期(基于周一开始)
|
||||
for (let i = 0; i < firstDayAdjusted; i++) {
|
||||
weeks.push(null);
|
||||
}
|
||||
|
||||
@@ -45,14 +49,18 @@ const generateCalendarData = (targetDate: Date) => {
|
||||
calendar.push(weeks.slice(i, i + 7));
|
||||
}
|
||||
|
||||
return { calendar, today: new Date().getDate(), month: month + 1, year };
|
||||
// 使用 dayjs 获取今天的日期,确保时区一致
|
||||
const today = dayjs();
|
||||
return {
|
||||
calendar,
|
||||
today: today.date(),
|
||||
month: month + 1, // 转回1-based用于显示
|
||||
year
|
||||
};
|
||||
};
|
||||
|
||||
export default function MoodCalendarScreen() {
|
||||
const theme = (useColorScheme() ?? 'light') as 'light' | 'dark';
|
||||
const colorTokens = Colors[theme];
|
||||
const params = useLocalSearchParams();
|
||||
const dispatch = useAppDispatch();
|
||||
const { fetchMoodRecords, fetchMoodHistoryRecords } = useMoodData();
|
||||
|
||||
// 使用 useRef 来存储函数引用,避免依赖循环
|
||||
@@ -116,9 +124,9 @@ export default function MoodCalendarScreen() {
|
||||
loadDailyMoodCheckins(dateString);
|
||||
loadMonthMoodData(date.toDate());
|
||||
} else {
|
||||
const today = new Date();
|
||||
const today = dayjs().toDate();
|
||||
setCurrentMonth(today);
|
||||
setSelectedDay(today.getDate());
|
||||
setSelectedDay(dayjs().date());
|
||||
const dateString = dayjs().format('YYYY-MM-DD');
|
||||
loadDailyMoodCheckins(dateString);
|
||||
loadMonthMoodData(today);
|
||||
@@ -144,16 +152,14 @@ export default function MoodCalendarScreen() {
|
||||
|
||||
// 月份切换函数
|
||||
const goToPreviousMonth = () => {
|
||||
const newMonth = new Date(currentMonth);
|
||||
newMonth.setMonth(newMonth.getMonth() - 1);
|
||||
const newMonth = dayjs(currentMonth).subtract(1, 'month').toDate();
|
||||
setCurrentMonth(newMonth);
|
||||
setSelectedDay(null);
|
||||
loadMonthMoodData(newMonth);
|
||||
};
|
||||
|
||||
const goToNextMonth = () => {
|
||||
const newMonth = new Date(currentMonth);
|
||||
newMonth.setMonth(newMonth.getMonth() + 1);
|
||||
const newMonth = dayjs(currentMonth).add(1, 'month').toDate();
|
||||
setCurrentMonth(newMonth);
|
||||
setSelectedDay(null);
|
||||
loadMonthMoodData(newMonth);
|
||||
@@ -188,9 +194,9 @@ export default function MoodCalendarScreen() {
|
||||
const dayRecords = moodRecords[dayDateString] || [];
|
||||
const moodRecord = dayRecords.length > 0 ? dayRecords[0] : null;
|
||||
|
||||
const isToday = day === new Date().getDate() &&
|
||||
month === new Date().getMonth() + 1 &&
|
||||
year === new Date().getFullYear();
|
||||
const isToday = day === dayjs().date() &&
|
||||
month === dayjs().month() + 1 &&
|
||||
year === dayjs().year();
|
||||
|
||||
if (moodRecord) {
|
||||
const mood = moodOptions.find(m => m.type === moodRecord.moodType);
|
||||
@@ -260,43 +266,45 @@ export default function MoodCalendarScreen() {
|
||||
))}
|
||||
</View>
|
||||
|
||||
{calendar.map((week, weekIndex) => (
|
||||
<View key={weekIndex} style={styles.weekRow}>
|
||||
{week.map((day, dayIndex) => {
|
||||
const isSelected = day === selectedDay;
|
||||
const isToday = day === today && month === new Date().getMonth() + 1 && year === new Date().getFullYear();
|
||||
const isFutureDate = Boolean(day && dayjs(currentMonth).date(day).isAfter(dayjs(), 'day'));
|
||||
<View >
|
||||
{calendar.map((week, weekIndex) => (
|
||||
<View key={weekIndex} style={styles.weekRow}>
|
||||
{week.map((day, dayIndex) => {
|
||||
const isSelected = day === selectedDay;
|
||||
const isToday = day === today && month === dayjs().month() + 1 && year === dayjs().year();
|
||||
const isFutureDate = Boolean(day && dayjs(currentMonth).date(day).isAfter(dayjs(), 'day'));
|
||||
|
||||
return (
|
||||
<View key={dayIndex} style={styles.dayContainer}>
|
||||
{day && (
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.dayButton,
|
||||
isSelected && styles.dayButtonSelected,
|
||||
isToday && styles.dayButtonToday
|
||||
]}
|
||||
onPress={() => !isFutureDate && day && onSelectDate(day)}
|
||||
disabled={isFutureDate}
|
||||
>
|
||||
<View style={styles.dayContent}>
|
||||
<Text style={[
|
||||
styles.dayNumber,
|
||||
isSelected && styles.dayNumberSelected,
|
||||
isToday && styles.dayNumberToday,
|
||||
isFutureDate && styles.dayNumberDisabled
|
||||
]}>
|
||||
{day.toString().padStart(2, '0')}
|
||||
</Text>
|
||||
{renderMoodRing(day, isSelected)}
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
))}
|
||||
return (
|
||||
<View key={dayIndex} style={styles.dayContainer}>
|
||||
{day && (
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.dayButton,
|
||||
isSelected && styles.dayButtonSelected,
|
||||
isToday && styles.dayButtonToday
|
||||
]}
|
||||
onPress={() => !isFutureDate && day && onSelectDate(day)}
|
||||
disabled={isFutureDate}
|
||||
>
|
||||
<View style={styles.dayContent}>
|
||||
<Text style={[
|
||||
styles.dayNumber,
|
||||
isSelected && styles.dayNumberSelected,
|
||||
isToday && styles.dayNumberToday,
|
||||
isFutureDate && styles.dayNumberDisabled
|
||||
]}>
|
||||
{day.toString().padStart(2, '0')}
|
||||
</Text>
|
||||
{renderMoodRing(day, isSelected)}
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 选中日期的记录 */}
|
||||
@@ -402,6 +410,8 @@ const styles = StyleSheet.create({
|
||||
backgroundColor: 'rgba(255,255,255,0.95)',
|
||||
margin: 16,
|
||||
borderRadius: 20,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: 20,
|
||||
shadowColor: '#7a5af8',
|
||||
shadowOffset: { width: 0, height: 4 },
|
||||
@@ -411,6 +421,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
monthNavigation: {
|
||||
flexDirection: 'row',
|
||||
width: '100%',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 24,
|
||||
@@ -440,7 +451,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
weekHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-around',
|
||||
justifyContent: 'flex-start',
|
||||
marginBottom: 20,
|
||||
},
|
||||
weekDay: {
|
||||
@@ -452,7 +463,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
weekRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-around',
|
||||
justifyContent: 'flex-start',
|
||||
marginBottom: 16,
|
||||
},
|
||||
dayContainer: {
|
||||
|
||||
Reference in New Issue
Block a user