- 将应用版本更新至 1.0.3,修改相关配置文件 - 强制全局使用浅色主题,确保一致的用户体验 - 在训练计划功能中新增激活计划的 API 接口,支持用户激活训练计划 - 优化打卡功能,支持自动同步打卡记录至服务器 - 更新样式以适应新功能的展示和交互
234 lines
6.0 KiB
TypeScript
234 lines
6.0 KiB
TypeScript
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={'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',
|
||
},
|
||
});
|