feat(workout): 新增锻炼结束监听和个性化通知功能

实现了iOS HealthKit锻炼数据实时监听,当用户完成锻炼时自动发送个性化鼓励通知。包括锻炼类型筛选、时间范围控制、用户偏好设置等完整功能,并提供了测试工具和详细文档。
This commit is contained in:
richarjiang
2025-10-13 10:05:02 +08:00
parent 12883c5410
commit 971aebd560
18 changed files with 2210 additions and 1264 deletions

View File

@@ -6,6 +6,7 @@ import { useColorScheme } from '@/hooks/useColorScheme';
import { fetchWeightHistory } from '@/store/userSlice';
import { BMI_CATEGORIES } from '@/utils/bmi';
import { Ionicons } from '@expo/vector-icons';
import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect';
import { Image } from 'expo-image';
import { LinearGradient } from 'expo-linear-gradient';
import React, { useEffect, useState } from 'react';
@@ -33,7 +34,7 @@ export function WeightHistoryCard() {
const weightHistory = useAppSelector((s) => s.user.weightHistory);
const [showBMIModal, setShowBMIModal] = useState(false);
const isLgAvaliable = isLiquidGlassAvailable();
const { pushIfAuthedElseLogin, isLoggedIn } = useAuthGuard();
const colorScheme = useColorScheme();
@@ -133,16 +134,30 @@ export function WeightHistoryCard() {
style={styles.iconSquare}
/>
<Text style={styles.cardTitle}></Text>
<TouchableOpacity
style={styles.addButton}
onPress={(e) => {
e.stopPropagation();
navigateToCoach();
}}
activeOpacity={0.8}
>
<Ionicons name="add" size={18} color={Colors.light.primary} />
</TouchableOpacity>
{isLgAvaliable ? (
<TouchableOpacity
onPress={(e) => {
e.stopPropagation();
navigateToCoach();
}}
activeOpacity={0.8}
>
<GlassView style={styles.addButtonGlass}>
<Ionicons name="add" size={18} color={Colors.light.primary} />
</GlassView>
</TouchableOpacity>
) : (
<TouchableOpacity
style={styles.addButton}
onPress={(e) => {
e.stopPropagation();
navigateToCoach();
}}
activeOpacity={0.8}
>
<Ionicons name="add" size={18} color={Colors.light.primary} />
</TouchableOpacity>
)}
</View>
{/* 默认显示图表 */}
@@ -352,6 +367,14 @@ const styles = StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
},
addButtonGlass: {
width: 28,
height: 28,
borderRadius: 14,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgba(147, 112, 219, 0.3)',
},
emptyContent: {
alignItems: 'center',
},