Files
digital-pilates/app/onboarding/index.tsx
richarjiang 849447c5da feat: 引入路由常量并更新相关页面导航
- 新增 ROUTES 常量文件,集中管理应用路由
- 更新多个页面的导航逻辑,使用 ROUTES 常量替代硬编码路径
- 修改教练页面和今日训练页面的路由,提升代码可维护性
- 优化标签页和登录页面的导航,确保一致性和易用性
2025-08-18 10:05:22 +08:00

235 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';
import { ROUTES } from '@/constants/Routes';
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(ROUTES.ONBOARDING_PERSONAL_INFO);
};
const handleSkip = async () => {
try {
await AsyncStorage.setItem('@onboarding_completed', 'true');
router.replace(ROUTES.TAB_HOME);
} catch (error) {
console.error('保存引导状态失败:', error);
router.replace(ROUTES.TAB_HOME);
}
};
return (
<ThemedView style={[styles.container, { backgroundColor }]}>
<StatusBar
barStyle={'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',
},
});