Files
digital-pilates/app/onboarding/index.tsx
richarjiang ddcc1320a4 feat: 添加引导流程和个人信息收集功能
- 在应用中集成引导流程,用户首次启动时显示欢迎页面和个人信息收集页面
- 使用 AsyncStorage 存储用户的引导状态和个人信息
- 在个人页面中添加重置引导流程的功能
- 更新依赖项,添加 @react-native-async-storage/async-storage 库以支持数据存储
- 修改布局以支持新页面的导航和显示
2025-08-12 14:12:59 +08:00

234 lines
6.0 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
import { useColorScheme } from '@/hooks/useColorScheme';
import { useThemeColor } from '@/hooks/useThemeColor';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { router } from 'expo-router';
import React from 'react';
import {
Dimensions,
StatusBar,
StyleSheet,
Text,
TouchableOpacity,
View
} from 'react-native';
const { width, height } = Dimensions.get('window');
export default function WelcomeScreen() {
const colorScheme = useColorScheme();
const backgroundColor = useThemeColor({}, 'background');
const primaryColor = useThemeColor({}, 'primary');
const textColor = useThemeColor({}, 'text');
const handleGetStarted = () => {
router.push('/onboarding/personal-info');
};
const handleSkip = async () => {
try {
await AsyncStorage.setItem('@onboarding_completed', 'true');
router.replace('/(tabs)');
} catch (error) {
console.error('保存引导状态失败:', error);
router.replace('/(tabs)');
}
};
return (
<ThemedView style={[styles.container, { backgroundColor }]}>
<StatusBar
barStyle={colorScheme === 'dark' ? 'light-content' : 'dark-content'}
backgroundColor={backgroundColor}
/>
{/* 跳过按钮 */}
<TouchableOpacity style={styles.skipButton} onPress={handleSkip}>
<ThemedText style={[styles.skipText, { color: textColor }]}>
</ThemedText>
</TouchableOpacity>
{/* 主要内容区域 */}
<View style={styles.contentContainer}>
{/* Logo 或插图区域 */}
<View style={styles.imageContainer}>
<View style={[styles.logoPlaceholder, { backgroundColor: primaryColor }]}>
<Text style={styles.logoText}>🧘</Text>
</View>
</View>
{/* 标题和描述 */}
<View style={styles.textContainer}>
<ThemedText type="title" style={styles.title}>
</ThemedText>
<ThemedText style={[styles.subtitle, { color: textColor + '90' }]}>
{'\n'}
</ThemedText>
</View>
{/* 特色功能点 */}
<View style={styles.featuresContainer}>
{[
{ icon: '📊', title: '个性化训练', desc: '根据您的身体状况定制训练计划' },
{ icon: '🤖', title: 'AI 姿态分析', desc: '实时纠正您的动作姿态' },
{ icon: '📈', title: '进度追踪', desc: '记录您的每一次进步' },
].map((feature, index) => (
<View key={index} style={styles.featureItem}>
<Text style={styles.featureIcon}>{feature.icon}</Text>
<View style={styles.featureTextContainer}>
<ThemedText style={[styles.featureTitle, { color: textColor }]}>
{feature.title}
</ThemedText>
<ThemedText style={[styles.featureDesc, { color: textColor + '70' }]}>
{feature.desc}
</ThemedText>
</View>
</View>
))}
</View>
</View>
{/* 底部按钮 */}
<View style={styles.buttonContainer}>
<TouchableOpacity
style={[styles.getStartedButton, { backgroundColor: primaryColor }]}
onPress={handleGetStarted}
activeOpacity={0.8}
>
<Text style={styles.getStartedButtonText}></Text>
</TouchableOpacity>
<TouchableOpacity style={styles.laterButton} onPress={handleSkip}>
<ThemedText style={[styles.laterButtonText, { color: textColor + '70' }]}>
</ThemedText>
</TouchableOpacity>
</View>
</ThemedView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: StatusBar.currentHeight || 44,
},
skipButton: {
position: 'absolute',
top: StatusBar.currentHeight ? StatusBar.currentHeight + 16 : 60,
right: 20,
zIndex: 10,
padding: 8,
},
skipText: {
fontSize: 16,
fontWeight: '500',
},
contentContainer: {
flex: 1,
paddingHorizontal: 24,
justifyContent: 'center',
},
imageContainer: {
alignItems: 'center',
marginBottom: 40,
},
logoPlaceholder: {
width: 120,
height: 120,
borderRadius: 60,
justifyContent: 'center',
alignItems: 'center',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 4,
},
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 8,
},
logoText: {
fontSize: 48,
},
textContainer: {
alignItems: 'center',
marginBottom: 48,
},
title: {
textAlign: 'center',
marginBottom: 16,
fontWeight: '700',
},
subtitle: {
fontSize: 16,
textAlign: 'center',
lineHeight: 24,
paddingHorizontal: 12,
},
featuresContainer: {
marginBottom: 40,
},
featureItem: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 24,
paddingHorizontal: 8,
},
featureIcon: {
fontSize: 32,
marginRight: 16,
width: 40,
textAlign: 'center',
},
featureTextContainer: {
flex: 1,
},
featureTitle: {
fontSize: 18,
fontWeight: '600',
marginBottom: 4,
},
featureDesc: {
fontSize: 14,
lineHeight: 20,
},
buttonContainer: {
paddingHorizontal: 24,
paddingBottom: 48,
},
getStartedButton: {
height: 56,
borderRadius: 16,
justifyContent: 'center',
alignItems: 'center',
marginBottom: 16,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 4,
},
getStartedButtonText: {
color: '#192126',
fontSize: 18,
fontWeight: '600',
},
laterButton: {
height: 48,
justifyContent: 'center',
alignItems: 'center',
},
laterButtonText: {
fontSize: 16,
fontWeight: '500',
},
});