From e87dc87e1bf30cca755d8ca9e19a9ca6db3bd280 Mon Sep 17 00:00:00 2001 From: richarjiang Date: Tue, 12 Aug 2025 10:13:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0AI=E4=BD=93=E6=80=81?= =?UTF-8?q?=E8=AF=84=E4=BC=B0=E9=A1=B5=E9=9D=A2=E5=8F=8A=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增AI体态评估页面,包含训练内容和统计信息 - 在首页中添加AI体态评估的导航链接 - 更新package-lock.json,调整依赖项的dev标记 - 修改布局文件以支持新页面的导航 --- app/(tabs)/index.tsx | 10 +- app/_layout.tsx | 1 + app/ai-posture-assessment.tsx | 347 +++++++++++++++++++ ios/digitalpilates.xcodeproj/project.pbxproj | 5 +- package-lock.json | 4 +- 5 files changed, 362 insertions(+), 5 deletions(-) create mode 100644 app/ai-posture-assessment.tsx diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 0415a44..196e214 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -4,6 +4,7 @@ import { ThemedText } from '@/components/ThemedText'; import { ThemedView } from '@/components/ThemedView'; import { WorkoutCard } from '@/components/WorkoutCard'; import { getChineseGreeting } from '@/utils/date'; +import { useRouter } from 'expo-router'; import React from 'react'; import { SafeAreaView, ScrollView, StyleSheet, View } from 'react-native'; @@ -22,6 +23,7 @@ const workoutData = [ ]; export default function HomeScreen() { + const router = useRouter(); return ( @@ -51,7 +53,13 @@ export default function HomeScreen() { title={workout.title} duration={workout.duration} imageSource={workout.imageSource} - onPress={() => console.log(`Pressed ${workout.title}`)} + onPress={() => { + if (workout.title === 'AI体态评估') { + router.push('/ai-posture-assessment'); + } else { + console.log(`Pressed ${workout.title}`); + } + }} /> ))} diff --git a/app/_layout.tsx b/app/_layout.tsx index 8d506f7..220acf2 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -21,6 +21,7 @@ export default function RootLayout() { + diff --git a/app/ai-posture-assessment.tsx b/app/ai-posture-assessment.tsx new file mode 100644 index 0000000..be557e0 --- /dev/null +++ b/app/ai-posture-assessment.tsx @@ -0,0 +1,347 @@ +import { Ionicons } from '@expo/vector-icons'; +import { useRouter } from 'expo-router'; +import React from 'react'; +import { + Image, + ImageBackground, + ScrollView, + StyleSheet, + Text, + TouchableOpacity, + View, +} from 'react-native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; + +import { Colors } from '@/constants/Colors'; + +type Exercise = { + id: string; + title: string; + duration: string; + imageUri: string; +}; + +const EXERCISES: Exercise[] = [ + { + id: '1', + title: 'Jumping Jacks', + duration: '00:30', + imageUri: + 'https://images.unsplash.com/photo-1546483875-ad9014c88eba?q=80&w=400&auto=format&fit=crop', + }, + { + id: '2', + title: 'Squats', + duration: '00:45', + imageUri: + 'https://images.unsplash.com/photo-1583454110551-21f2fa2f36f0?q=80&w=400&auto=format&fit=crop', + }, + { + id: '3', + title: 'Backward Lunge', + duration: '00:40', + imageUri: + 'https://images.unsplash.com/photo-1597074866923-5c3bfa3b6c46?q=80&w=400&auto=format&fit=crop', + }, + { + id: '4', + title: 'High Knees', + duration: '00:30', + imageUri: + 'https://images.unsplash.com/photo-1596357395104-5bcae0b1a5eb?q=80&w=400&auto=format&fit=crop', + }, +]; + +export default function AIPostureAssessmentScreen() { + const router = useRouter(); + const insets = useSafeAreaInsets(); + + const theme = Colors.dark; // 该页面采用深色视觉 + + return ( + + {/* Header */} + + router.back()} + style={styles.backButton} + > + + + AI体态评估 + + + + + {/* Hero */} + + + + + + {/* Floating stats */} + + } + label="Time" + value="20 min" + /> + + } + label="Burn" + value="95 kcal" + /> + + + + {/* Title & description */} + + Lower Body Training + + The lower abdomen and hips are the most difficult areas of the body to reduce when we are on + a diet. Even so, in this area, especially the legs as a whole, you can reduce weight even if + you don't use tools. + + + + {/* Rounds header */} + + Rounds + 1/8 + + + {/* Exercise list */} + + {EXERCISES.map((item) => ( + ) + )} + + + + {/* Bottom CTA */} + + { }} + style={[styles.bottomCta, { backgroundColor: theme.primary }]} + > + Lets Workout + + + + ); +} + +function StatCard({ + icon, + label, + value, +}: { + icon: React.ReactNode; + label: string; + value: string; +}) { + return ( + + {icon} + + {label} + {value} + + + ); +} + +function ExerciseItem({ exercise }: { exercise: Exercise }) { + return ( + + + + {exercise.title} + {exercise.duration} + + + + + + ); +} + +const styles = StyleSheet.create({ + screen: { + flex: 1, + }, + header: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + paddingHorizontal: 16, + }, + backButton: { + width: 32, + height: 32, + borderRadius: 16, + alignItems: 'center', + justifyContent: 'center', + backgroundColor: 'rgba(255,255,255,0.06)', + }, + headerTitle: { + fontSize: 22, + color: '#ECEDEE', + fontWeight: '700', + }, + heroContainer: { + marginTop: 14, + marginHorizontal: 16, + }, + heroImage: { + height: 260, + borderRadius: 28, + overflow: 'hidden', + justifyContent: 'flex-end', + }, + heroOverlay: { + ...StyleSheet.absoluteFillObject, + backgroundColor: 'rgba(0,0,0,0.18)', + borderRadius: 28, + }, + statsFloating: { + position: 'absolute', + left: 22, + right: 22, + bottom: -26, + height: 72, + borderRadius: 20, + backgroundColor: '#1E262C', + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-around', + paddingHorizontal: 14, + shadowColor: '#000', + shadowOpacity: 0.3, + shadowRadius: 10, + shadowOffset: { width: 0, height: 6 }, + elevation: 6, + }, + divider: { + width: 1, + height: 36, + backgroundColor: 'rgba(255,255,255,0.08)', + }, + statCard: { + flexDirection: 'row', + alignItems: 'center', + }, + statIconWrap: { + width: 36, + height: 36, + borderRadius: 12, + backgroundColor: '#BBF246', + alignItems: 'center', + justifyContent: 'center', + }, + statLabel: { + color: 'rgba(255,255,255,0.75)', + fontSize: 12, + marginBottom: 2, + }, + statValue: { + color: '#ECEDEE', + fontSize: 16, + fontWeight: '700', + }, + contentSection: { + marginTop: 46, + paddingHorizontal: 20, + gap: 12, + }, + title: { + fontSize: 28, + color: '#ECEDEE', + fontWeight: '800', + }, + description: { + fontSize: 15, + lineHeight: 22, + color: 'rgba(255,255,255,0.75)', + }, + roundsHeader: { + marginTop: 18, + paddingHorizontal: 20, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + }, + roundsTitle: { + color: '#ECEDEE', + fontSize: 22, + fontWeight: '700', + }, + roundsCount: { + color: 'rgba(255,255,255,0.6)', + fontSize: 16, + }, + exerciseItem: { + flexDirection: 'row', + alignItems: 'center', + backgroundColor: '#1E262C', + padding: 12, + borderRadius: 18, + }, + exerciseThumb: { + width: 56, + height: 56, + borderRadius: 12, + }, + exerciseTitle: { + color: '#ECEDEE', + fontSize: 16, + fontWeight: '600', + }, + exerciseDuration: { + color: 'rgba(255,255,255,0.6)', + marginTop: 4, + fontSize: 13, + }, + exercisePlayButton: { + width: 36, + height: 36, + borderRadius: 18, + borderWidth: 1, + borderColor: 'rgba(255,255,255,0.2)', + alignItems: 'center', + justifyContent: 'center', + backgroundColor: '#192126', + }, + bottomCtaWrap: { + position: 'absolute', + left: 16, + right: 16, + bottom: 0, + }, + bottomCta: { + height: 64, + borderRadius: 32, + alignItems: 'center', + justifyContent: 'center', + }, + bottomCtaText: { + color: '#192126', + fontSize: 18, + fontWeight: '800', + }, +}); + + diff --git a/ios/digitalpilates.xcodeproj/project.pbxproj b/ios/digitalpilates.xcodeproj/project.pbxproj index af18aa3..5b886f4 100644 --- a/ios/digitalpilates.xcodeproj/project.pbxproj +++ b/ios/digitalpilates.xcodeproj/project.pbxproj @@ -21,7 +21,7 @@ 13B07F961A680F5B00A75B9A /* digitalpilates.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = digitalpilates.app; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = digitalpilates/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = digitalpilates/Info.plist; sourceTree = ""; }; - 905D0A94B379FF06B1A262B2 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = digitalpilates/PrivacyInfo.xcprivacy; sourceTree = ""; }; + 905D0A94B379FF06B1A262B2 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = digitalpilates/PrivacyInfo.xcprivacy; sourceTree = ""; }; 951C0617485F4FEF590D4C5D /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-digitalpilates/ExpoModulesProvider.swift"; sourceTree = ""; }; AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = digitalpilates/SplashScreen.storyboard; sourceTree = ""; }; B8247601A9965B9A71737DFD /* Pods-digitalpilates.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-digitalpilates.debug.xcconfig"; path = "Target Support Files/Pods-digitalpilates/Pods-digitalpilates.debug.xcconfig"; sourceTree = ""; }; @@ -128,7 +128,6 @@ B8247601A9965B9A71737DFD /* Pods-digitalpilates.debug.xcconfig */, E41FEE326E770C4798A5541A /* Pods-digitalpilates.release.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -336,6 +335,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = digitalpilates/digitalpilates.entitlements; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 756WVXJ6MT; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", @@ -372,6 +372,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = digitalpilates/digitalpilates.entitlements; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 756WVXJ6MT; INFOPLIST_FILE = digitalpilates/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/package-lock.json b/package-lock.json index 03f99be..9ec735b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3261,7 +3261,7 @@ "version": "19.0.14", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.14.tgz", "integrity": "sha512-ixLZ7zG7j1fM0DijL9hDArwhwcCb4vqmePgwtV0GfnkHRSCUEv4LvzarcTdhoqgyMznUx/EhoTUv31CKZzkQlw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -5193,7 +5193,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/data-view-buffer": {