feat: 优化健康数据相关组件及功能
- 在 CoachScreen 中调整键盘高度计算,移除不必要的 insets.bottom - 更新 Statistics 组件,移除未使用的健康数据相关函数,简化代码 - 修改多个统计卡片,移除不必要的图标属性,提升组件简洁性 - 优化 HealthDataCard 和其他统计卡片的样式,提升视觉一致性 - 更新健康数据获取逻辑,确保数据处理更为准确 - 移除 MoodCard 中的多余元素,简化心情记录展示 - 调整 StressMeter 和其他组件的样式,提升用户体验
This commit is contained in:
@@ -419,7 +419,7 @@ export default function CoachScreen() {
|
||||
showSub = Keyboard.addListener('keyboardWillChangeFrame', (e: any) => {
|
||||
try {
|
||||
if (e?.endCoordinates?.height) {
|
||||
const height = Math.max(0, e.endCoordinates.height - insets.bottom);
|
||||
const height = Math.max(0, e.endCoordinates.height);
|
||||
setKeyboardOffset(height);
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -18,7 +18,7 @@ import { useColorScheme } from '@/hooks/useColorScheme';
|
||||
import { calculateNutritionSummary, getDietRecords, NutritionSummary } from '@/services/dietRecords';
|
||||
import { fetchDailyMoodCheckins, selectLatestMoodRecordByDate } from '@/store/moodSlice';
|
||||
import { getMonthDaysZh, getTodayIndexInMonth } from '@/utils/date';
|
||||
import { ensureHealthPermissions, fetchHealthDataForDate, testOxygenSaturationData } from '@/utils/health';
|
||||
import { ensureHealthPermissions, fetchHealthDataForDate } from '@/utils/health';
|
||||
import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
|
||||
import { useFocusEffect } from '@react-navigation/native';
|
||||
import dayjs from 'dayjs';
|
||||
@@ -124,14 +124,12 @@ export default function ExploreScreen() {
|
||||
const [oxygenSaturation, setOxygenSaturation] = useState<number | null>(null);
|
||||
const [heartRate, setHeartRate] = useState<number | null>(null);
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
// 用于触发动画重置的 token(当日期或数据变化时更新)
|
||||
const [animToken, setAnimToken] = useState(0);
|
||||
const [trainingProgress, setTrainingProgress] = useState(0); // 暂定静态80%
|
||||
|
||||
// 营养数据状态
|
||||
const [nutritionSummary, setNutritionSummary] = useState<NutritionSummary | null>(null);
|
||||
const [isNutritionLoading, setIsNutritionLoading] = useState(false);
|
||||
|
||||
const { registerTask } = useBackgroundTasks();
|
||||
// 心情相关状态
|
||||
const dispatch = useAppDispatch();
|
||||
@@ -182,7 +180,6 @@ export default function ExploreScreen() {
|
||||
const loadHealthData = async (targetDate?: Date) => {
|
||||
try {
|
||||
console.log('=== 开始HealthKit初始化流程 ===');
|
||||
setIsLoading(true);
|
||||
|
||||
const ok = await ensureHealthPermissions();
|
||||
if (!ok) {
|
||||
@@ -246,15 +243,12 @@ export default function ExploreScreen() {
|
||||
// 重置血氧饱和度和心率数据
|
||||
setOxygenSaturation(null);
|
||||
setHeartRate(null);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 加载营养数据
|
||||
const loadNutritionData = async (targetDate?: Date) => {
|
||||
try {
|
||||
setIsNutritionLoading(true);
|
||||
|
||||
// 确定要查询的日期:优先使用传入的日期,否则使用当前选中索引对应的日期
|
||||
let derivedDate: Date;
|
||||
@@ -281,8 +275,6 @@ export default function ExploreScreen() {
|
||||
} catch (error) {
|
||||
console.error('营养数据加载失败:', error);
|
||||
setNutritionSummary(null);
|
||||
} finally {
|
||||
setIsNutritionLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -300,20 +292,20 @@ export default function ExploreScreen() {
|
||||
}, [selectedIndex])
|
||||
);
|
||||
|
||||
// useEffect(() => {
|
||||
// // 注册任务
|
||||
// registerTask({
|
||||
// id: 'health-data-task',
|
||||
// name: 'health-data-task',
|
||||
// handler: async () => {
|
||||
// try {
|
||||
// await loadHealthData();
|
||||
// } catch (error) {
|
||||
// console.error('健康数据任务执行失败:', error);
|
||||
// }
|
||||
// },
|
||||
// });
|
||||
// }, []);
|
||||
useEffect(() => {
|
||||
// 注册任务
|
||||
registerTask({
|
||||
id: 'health-data-task',
|
||||
name: 'health-data-task',
|
||||
handler: async () => {
|
||||
try {
|
||||
await loadHealthData();
|
||||
} catch (error) {
|
||||
console.error('健康数据任务执行失败:', error);
|
||||
}
|
||||
},
|
||||
});
|
||||
}, []);
|
||||
|
||||
// 日期点击时,加载对应日期数据
|
||||
const onSelectDate = (index: number, date: Date) => {
|
||||
@@ -325,16 +317,6 @@ export default function ExploreScreen() {
|
||||
}
|
||||
};
|
||||
|
||||
// 测试血氧饱和度数据
|
||||
const testOxygenData = async () => {
|
||||
console.log('开始测试血氧饱和度数据...');
|
||||
const currentDate = getCurrentSelectedDate();
|
||||
await testOxygenSaturationData(currentDate);
|
||||
};
|
||||
|
||||
// 使用统一的渐变背景色
|
||||
const backgroundGradientColors = [colorTokens.backgroundGradientStart, colorTokens.backgroundGradientEnd] as const;
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{/* 背景渐变 */}
|
||||
@@ -384,8 +366,8 @@ export default function ExploreScreen() {
|
||||
/>
|
||||
</FloatingCard>
|
||||
|
||||
<FloatingCard style={[styles.masonryCard, styles.caloriesCard]} delay={500}>
|
||||
<Text style={styles.cardTitleSecondary}>消耗卡路里</Text>
|
||||
<FloatingCard style={styles.masonryCard} delay={500}>
|
||||
<Text style={styles.cardTitle}>消耗卡路里</Text>
|
||||
{activeCalories != null ? (
|
||||
<AnimatedNumber
|
||||
value={activeCalories}
|
||||
@@ -398,7 +380,7 @@ export default function ExploreScreen() {
|
||||
)}
|
||||
</FloatingCard>
|
||||
|
||||
<FloatingCard style={[styles.masonryCard, styles.stepsCard]} delay={1000}>
|
||||
<FloatingCard style={styles.masonryCard} delay={1000}>
|
||||
<View style={styles.cardHeaderRow}>
|
||||
<Text style={styles.cardTitle}>步数</Text>
|
||||
</View>
|
||||
@@ -414,14 +396,14 @@ export default function ExploreScreen() {
|
||||
)}
|
||||
<ProgressBar
|
||||
progress={Math.min(1, Math.max(0, (stepCount ?? 0) / stepGoal))}
|
||||
height={16}
|
||||
height={14}
|
||||
trackColor="#FFEBCB"
|
||||
fillColor="#FFC365"
|
||||
showLabel={false}
|
||||
/>
|
||||
</FloatingCard>
|
||||
{/* 心情卡片 */}
|
||||
<FloatingCard style={[styles.masonryCard, styles.moodCard]} delay={1500}>
|
||||
<FloatingCard style={styles.masonryCard} delay={1500}>
|
||||
<MoodCard
|
||||
moodCheckin={currentMoodCheckin}
|
||||
onPress={() => pushIfAuthedElseLogin('/mood/calendar')}
|
||||
@@ -444,7 +426,7 @@ export default function ExploreScreen() {
|
||||
/>
|
||||
</FloatingCard>
|
||||
|
||||
<FloatingCard style={[styles.masonryCard, styles.sleepCard]} delay={750}>
|
||||
<FloatingCard style={styles.masonryCard} delay={750}>
|
||||
<View style={styles.cardHeaderRow}>
|
||||
<Text style={styles.cardTitle}>睡眠</Text>
|
||||
</View>
|
||||
@@ -473,13 +455,6 @@ export default function ExploreScreen() {
|
||||
style={styles.basalMetabolismCardOverride}
|
||||
oxygenSaturation={oxygenSaturation}
|
||||
/>
|
||||
{/* 测试按钮 - 开发时使用 */}
|
||||
<Text
|
||||
style={styles.testButton}
|
||||
onPress={testOxygenData}
|
||||
>
|
||||
测试血氧数据
|
||||
</Text>
|
||||
</FloatingCard>
|
||||
|
||||
{/* 心率卡片 */}
|
||||
@@ -577,22 +552,11 @@ const styles = StyleSheet.create({
|
||||
borderRadius: 22,
|
||||
padding: 16,
|
||||
},
|
||||
caloriesCard: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
},
|
||||
trainingCard: {
|
||||
backgroundColor: '#EEE9FF',
|
||||
},
|
||||
cardTitleSecondary: {
|
||||
color: '#9AA3AE',
|
||||
fontSize: 10,
|
||||
fontWeight: '600',
|
||||
marginBottom: 10,
|
||||
},
|
||||
caloriesValue: {
|
||||
color: '#192126',
|
||||
fontSize: 18,
|
||||
fontWeight: '800',
|
||||
marginTop: 18,
|
||||
},
|
||||
trainingContent: {
|
||||
marginTop: 8,
|
||||
@@ -706,9 +670,6 @@ const styles = StyleSheet.create({
|
||||
color: '#5B5B5B',
|
||||
fontWeight: '600',
|
||||
},
|
||||
stepsCard: {
|
||||
backgroundColor: '#FFE4B8',
|
||||
},
|
||||
stepsValue: {
|
||||
fontSize: 14,
|
||||
color: '#7A6A42',
|
||||
@@ -797,9 +758,6 @@ const styles = StyleSheet.create({
|
||||
justifyContent: 'space-between',
|
||||
marginTop: 8,
|
||||
},
|
||||
sleepCard: {
|
||||
backgroundColor: '#E8F4FD',
|
||||
},
|
||||
sleepValue: {
|
||||
fontSize: 16,
|
||||
color: '#1E40AF',
|
||||
@@ -821,14 +779,5 @@ const styles = StyleSheet.create({
|
||||
top: 0,
|
||||
padding: 4,
|
||||
},
|
||||
moodCard: {
|
||||
backgroundColor: '#F0FDF4',
|
||||
},
|
||||
testButton: {
|
||||
fontSize: 12,
|
||||
color: '#3B82F6',
|
||||
textAlign: 'center',
|
||||
marginTop: 8,
|
||||
padding: 4,
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user