feat: Enhance Oxygen Saturation Card with health permissions and loading state management
feat(i18n): Add common translations and mood-related strings in English and Chinese fix(i18n): Update metabolism titles for consistency in health translations chore: Update Podfile.lock to include SDWebImage 5.21.4 and other dependency versions refactor(moodCheckins): Improve mood configuration retrieval with optional translation support refactor(sleepHealthKit): Replace useI18n with direct i18n import for sleep quality descriptions
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { HeaderBar } from '@/components/ui/HeaderBar';
|
||||
import { useAppSelector } from '@/hooks/redux';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useMoodData } from '@/hooks/useMoodData';
|
||||
import { useSafeAreaTop } from '@/hooks/useSafeAreaWithPadding';
|
||||
import { getMoodOptions } from '@/services/moodCheckins';
|
||||
@@ -61,6 +62,7 @@ const generateCalendarData = (targetDate: Date) => {
|
||||
};
|
||||
|
||||
export default function MoodCalendarScreen() {
|
||||
const { t } = useI18n();
|
||||
const safeAreaTop = useSafeAreaTop()
|
||||
const params = useLocalSearchParams();
|
||||
const { fetchMoodRecords, fetchMoodHistoryRecords } = useMoodData();
|
||||
@@ -89,9 +91,30 @@ export default function MoodCalendarScreen() {
|
||||
return selectLatestMoodRecordByDate(selectedDateString)(state);
|
||||
});
|
||||
|
||||
const moodOptions = getMoodOptions();
|
||||
const weekDays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
|
||||
const monthNames = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
|
||||
const moodOptions = getMoodOptions(t);
|
||||
const weekDays = [
|
||||
t('mood.calendar.weekDays.monday'),
|
||||
t('mood.calendar.weekDays.tuesday'),
|
||||
t('mood.calendar.weekDays.wednesday'),
|
||||
t('mood.calendar.weekDays.thursday'),
|
||||
t('mood.calendar.weekDays.friday'),
|
||||
t('mood.calendar.weekDays.saturday'),
|
||||
t('mood.calendar.weekDays.sunday'),
|
||||
];
|
||||
const monthNames = [
|
||||
t('mood.calendar.months.january'),
|
||||
t('mood.calendar.months.february'),
|
||||
t('mood.calendar.months.march'),
|
||||
t('mood.calendar.months.april'),
|
||||
t('mood.calendar.months.may'),
|
||||
t('mood.calendar.months.june'),
|
||||
t('mood.calendar.months.july'),
|
||||
t('mood.calendar.months.august'),
|
||||
t('mood.calendar.months.september'),
|
||||
t('mood.calendar.months.october'),
|
||||
t('mood.calendar.months.november'),
|
||||
t('mood.calendar.months.december'),
|
||||
];
|
||||
|
||||
// 生成当前月份的日历数据
|
||||
const { calendar, today, month, year } = generateCalendarData(currentMonth);
|
||||
@@ -103,7 +126,7 @@ export default function MoodCalendarScreen() {
|
||||
const endDate = dayjs(targetMonth).endOf('month').format('YYYY-MM-DD');
|
||||
await fetchMoodHistoryRecordsRef.current({ startDate, endDate });
|
||||
} catch (error) {
|
||||
console.error('加载月份心情数据失败:', error);
|
||||
console.error(t('mood.calendar.errors.loadMonthDataFailed'), error);
|
||||
}
|
||||
}, []);
|
||||
|
||||
@@ -112,7 +135,7 @@ export default function MoodCalendarScreen() {
|
||||
try {
|
||||
await fetchMoodRecordsRef.current(dateString);
|
||||
} catch (error) {
|
||||
console.error('加载心情记录失败:', error);
|
||||
console.error(t('mood.calendar.errors.loadDailyDataFailed'), error);
|
||||
}
|
||||
}, []);
|
||||
|
||||
@@ -235,7 +258,7 @@ export default function MoodCalendarScreen() {
|
||||
|
||||
<View style={styles.safeArea}>
|
||||
<HeaderBar
|
||||
title="心情日历"
|
||||
title={t('mood.calendar.title')}
|
||||
onBack={() => router.back()}
|
||||
withSafeTop={false}
|
||||
transparent={true}
|
||||
@@ -255,7 +278,7 @@ export default function MoodCalendarScreen() {
|
||||
>
|
||||
<Text style={styles.navButtonText}>‹</Text>
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.monthTitle}>{year}年{monthNames[month - 1]}</Text>
|
||||
<Text style={styles.monthTitle}>{year} {monthNames[month - 1]}</Text>
|
||||
<TouchableOpacity
|
||||
style={styles.navButton}
|
||||
onPress={goToNextMonth}
|
||||
@@ -315,13 +338,13 @@ export default function MoodCalendarScreen() {
|
||||
<View style={styles.selectedDateSection}>
|
||||
<View style={styles.selectedDateHeader}>
|
||||
<Text style={styles.selectedDateTitle}>
|
||||
{selectedDay ? dayjs(currentMonth).date(selectedDay).format('YYYY年M月D日') : '请选择日期'}
|
||||
{selectedDay ? dayjs(currentMonth).date(selectedDay).format(t('mood.calendar.selectedDate.dateFormat')) : t('mood.calendar.selectedDate.selectDate')}
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
style={styles.addMoodButton}
|
||||
onPress={openMoodEdit}
|
||||
>
|
||||
<Text style={styles.addMoodButtonText}>记录</Text>
|
||||
<Text style={styles.addMoodButtonText}>{t('mood.calendar.selectedDate.record')}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
@@ -343,7 +366,7 @@ export default function MoodCalendarScreen() {
|
||||
<Text style={styles.recordMood}>
|
||||
{moodOptions.find(m => m.type === selectedDateMood.moodType)?.label}
|
||||
</Text>
|
||||
<Text style={styles.recordIntensity}>强度: {selectedDateMood.intensity}</Text>
|
||||
<Text style={styles.recordIntensity}>{t('mood.calendar.selectedDate.intensity')}: {selectedDateMood.intensity}</Text>
|
||||
{selectedDateMood.description && (
|
||||
<Text style={styles.recordDescription}>{selectedDateMood.description}</Text>
|
||||
)}
|
||||
@@ -355,14 +378,14 @@ export default function MoodCalendarScreen() {
|
||||
</TouchableOpacity>
|
||||
) : (
|
||||
<View style={styles.emptyRecord}>
|
||||
<Text style={styles.emptyRecordText}>暂无心情记录</Text>
|
||||
<Text style={styles.emptyRecordSubtext}>点击右上角"记录"按钮添加心情</Text>
|
||||
<Text style={styles.emptyRecordText}>{t('mood.calendar.selectedDate.noRecord')}</Text>
|
||||
<Text style={styles.emptyRecordSubtext}>{t('mood.calendar.selectedDate.noRecordHint')}</Text>
|
||||
</View>
|
||||
)
|
||||
) : (
|
||||
<View style={styles.emptyRecord}>
|
||||
<Text style={styles.emptyRecordText}>请先选择一个日期</Text>
|
||||
<Text style={styles.emptyRecordSubtext}>点击日历中的日期,然后点击"记录"按钮添加心情</Text>
|
||||
<Text style={styles.emptyRecordText}>{t('mood.calendar.selectedDate.noDateSelected')}</Text>
|
||||
<Text style={styles.emptyRecordSubtext}>{t('mood.calendar.selectedDate.noDateSelectedHint')}</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
@@ -3,6 +3,7 @@ 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 {
|
||||
@@ -31,6 +32,7 @@ import {
|
||||
} from 'react-native';
|
||||
|
||||
export default function MoodEditScreen() {
|
||||
const { t } = useI18n();
|
||||
const safeAreaTop = useSafeAreaTop()
|
||||
|
||||
const theme = (useColorScheme() ?? 'light') as 'light' | 'dark';
|
||||
@@ -51,7 +53,7 @@ export default function MoodEditScreen() {
|
||||
const scrollViewRef = useRef<ScrollView>(null);
|
||||
const textInputRef = useRef<TextInput>(null);
|
||||
|
||||
const moodOptions = getMoodOptions();
|
||||
const moodOptions = getMoodOptions(t);
|
||||
|
||||
// 从 Redux 获取数据
|
||||
const moodRecords = useAppSelector(selectMoodRecordsByDate(selectedDate));
|
||||
@@ -95,7 +97,7 @@ export default function MoodEditScreen() {
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!selectedMood) {
|
||||
Alert.alert('提示', '请选择心情');
|
||||
Alert.alert(t('common.alert'), t('mood.edit.alerts.selectMood'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -120,12 +122,12 @@ export default function MoodEditScreen() {
|
||||
})).unwrap();
|
||||
}
|
||||
|
||||
Alert.alert('成功', existingMood ? '心情记录已更新' : '心情记录已保存', [
|
||||
{ text: '确定', onPress: () => router.back() }
|
||||
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('错误', '保存心情失败,请重试');
|
||||
Alert.alert(t('common.error'), t('mood.edit.alerts.saveError'));
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
@@ -135,24 +137,24 @@ export default function MoodEditScreen() {
|
||||
if (!existingMood) return;
|
||||
|
||||
Alert.alert(
|
||||
'确认删除',
|
||||
'确定要删除这条心情记录吗?',
|
||||
t('mood.edit.alerts.confirmDeleteTitle'),
|
||||
t('mood.edit.alerts.confirmDelete'),
|
||||
[
|
||||
{ text: '取消', style: 'cancel' },
|
||||
{ text: t('common.cancel'), style: 'cancel' },
|
||||
{
|
||||
text: '删除',
|
||||
text: t('common.delete'),
|
||||
style: 'destructive',
|
||||
onPress: async () => {
|
||||
try {
|
||||
setIsDeleting(true);
|
||||
await dispatch(deleteMoodRecord({ id: existingMood.id })).unwrap();
|
||||
|
||||
Alert.alert('成功', '心情记录已删除', [
|
||||
{ text: '确定', onPress: () => router.back() }
|
||||
Alert.alert(t('common.success'), t('mood.edit.alerts.deleteSuccess'), [
|
||||
{ text: t('common.confirm'), onPress: () => router.back() }
|
||||
]);
|
||||
} catch (error) {
|
||||
console.error('删除心情失败:', error);
|
||||
Alert.alert('错误', '删除心情失败,请重试');
|
||||
Alert.alert(t('common.error'), t('mood.edit.alerts.deleteError'));
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
}
|
||||
@@ -183,7 +185,7 @@ export default function MoodEditScreen() {
|
||||
<View style={styles.decorativeCircle2} />
|
||||
<View style={styles.safeArea} >
|
||||
<HeaderBar
|
||||
title={existingMood ? '编辑心情' : '记录心情'}
|
||||
title={existingMood ? t('mood.edit.editTitle') : t('mood.edit.title')}
|
||||
onBack={() => router.back()}
|
||||
withSafeTop={false}
|
||||
transparent={true}
|
||||
@@ -207,13 +209,13 @@ export default function MoodEditScreen() {
|
||||
{/* 日期显示 */}
|
||||
<View style={styles.dateSection}>
|
||||
<Text style={styles.dateTitle}>
|
||||
{dayjs(selectedDate).format('YYYY年M月D日')}
|
||||
{dayjs(selectedDate).format(t('mood.edit.dateFormat'))}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* 心情选择 */}
|
||||
<View style={styles.moodSection}>
|
||||
<Text style={styles.sectionTitle}>选择心情</Text>
|
||||
<Text style={styles.sectionTitle}>{t('mood.edit.selectMood')}</Text>
|
||||
<View style={styles.moodOptions}>
|
||||
{moodOptions.map((mood, index) => (
|
||||
<TouchableOpacity
|
||||
@@ -233,7 +235,7 @@ export default function MoodEditScreen() {
|
||||
|
||||
{/* 心情强度选择 */}
|
||||
<View style={styles.intensitySection}>
|
||||
<Text style={styles.sectionTitle}>心情强度</Text>
|
||||
<Text style={styles.sectionTitle}>{t('mood.edit.intensity')}</Text>
|
||||
<MoodIntensitySlider
|
||||
value={intensity}
|
||||
onValueChange={handleIntensityChange}
|
||||
@@ -248,18 +250,12 @@ export default function MoodEditScreen() {
|
||||
{/* 心情描述 */}
|
||||
|
||||
<View style={styles.descriptionSection}>
|
||||
<Text style={styles.sectionTitle}>心情日记</Text>
|
||||
<Text style={styles.diarySubtitle}>记录你的心情,珍藏美好回忆</Text>
|
||||
<Text style={styles.sectionTitle}>{t('mood.edit.diary')}</Text>
|
||||
<Text style={styles.diarySubtitle}>{t('mood.edit.diarySubtitle')}</Text>
|
||||
<TextInput
|
||||
ref={textInputRef}
|
||||
style={styles.descriptionInput}
|
||||
placeholder={`今天的心情如何?
|
||||
|
||||
你经历过什么特别的事情吗?
|
||||
有什么让你开心的事?
|
||||
或者,有什么让你感到困扰?
|
||||
|
||||
写下你的感受,让这些时刻成为你珍贵的记忆...`}
|
||||
placeholder={t('mood.edit.placeholder')}
|
||||
placeholderTextColor="#a8a8a8"
|
||||
value={description}
|
||||
onChangeText={setDescription}
|
||||
@@ -289,7 +285,7 @@ export default function MoodEditScreen() {
|
||||
disabled={!selectedMood || isLoading}
|
||||
>
|
||||
<Text style={styles.saveButtonText}>
|
||||
{isLoading ? '保存中...' : existingMood ? '更新心情' : '保存心情'}
|
||||
{isLoading ? t('mood.edit.saving') : existingMood ? t('mood.edit.update') : t('mood.edit.save')}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
{existingMood && (
|
||||
|
||||
Reference in New Issue
Block a user