feat: 更新应用图标和启动画面

- 将应用图标更改为 logo.jpeg,更新相关配置文件
- 删除旧的图标文件,确保资源整洁
- 更新启动画面使用新的 logo 图片,提升视觉一致性
- 在训练计划相关功能中集成新的 API 接口,支持训练计划的创建和管理
- 优化 Redux 状态管理,支持训练计划的加载和删除功能
- 更新样式以适应新图标和功能的展示
This commit is contained in:
richarjiang
2025-08-14 19:28:38 +08:00
parent 5d09cc05dc
commit 56d4c7fd7f
18 changed files with 1411 additions and 536 deletions

View File

@@ -4,6 +4,7 @@ import * as ImagePicker from 'expo-image-picker';
import { useRouter } from 'expo-router';
import React, { useEffect, useMemo, useState } from 'react';
import {
ActivityIndicator,
Alert,
Image,
Linking,
@@ -12,13 +13,14 @@ import {
StyleSheet,
Text,
TouchableOpacity,
View,
View
} from 'react-native';
import ImageViewing from 'react-native-image-viewing';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { HeaderBar } from '@/components/ui/HeaderBar';
import { Colors } from '@/constants/Colors';
import { useCosUpload } from '@/hooks/useCosUpload';
type PoseView = 'front' | 'side' | 'back';
@@ -59,6 +61,9 @@ export default function AIPostureAssessmentScreen() {
[uploadState]
);
const { upload, uploading } = useCosUpload();
const [uploadingKey, setUploadingKey] = useState<PoseView | null>(null);
const [cameraPerm, setCameraPerm] = useState<ImagePicker.PermissionStatus | null>(null);
const [libraryPerm, setLibraryPerm] = useState<ImagePicker.PermissionStatus | null>(null);
const [libraryAccess, setLibraryAccess] = useState<'all' | 'limited' | 'none' | null>(null);
@@ -129,7 +134,25 @@ export default function AIPostureAssessmentScreen() {
aspect: [3, 4],
});
if (!result.canceled) {
setUploadState((s) => ({ ...s, [key]: result.assets[0]?.uri ?? null }));
// 设置正在上传状态
setUploadingKey(key);
try {
// 上传到 COS
const { url } = await upload(
{ uri: result.assets[0]?.uri ?? '', name: `posture-${key}.jpg`, type: 'image/jpeg' },
{ prefix: 'posture-assessment/' }
);
// 上传成功,更新状态
setUploadState((s) => ({ ...s, [key]: url }));
} catch (uploadError) {
console.warn('上传图片失败', uploadError);
Alert.alert('上传失败', '图片上传失败,请重试');
// 上传失败,清除状态
setUploadState((s) => ({ ...s, [key]: null }));
} finally {
// 清除上传状态
setUploadingKey(null);
}
}
} else {
const resp = await ImagePicker.requestMediaLibraryPermissionsAsync();
@@ -158,7 +181,25 @@ export default function AIPostureAssessmentScreen() {
aspect: [3, 4],
});
if (!result.canceled) {
setUploadState((s) => ({ ...s, [key]: result.assets[0]?.uri ?? null }));
// 设置正在上传状态
setUploadingKey(key);
try {
// 上传到 COS
const { url } = await upload(
{ uri: result.assets[0]?.uri ?? '', name: `posture-${key}.jpg`, type: 'image/jpeg' },
{ prefix: 'posture-assessment/' }
);
// 上传成功,更新状态
setUploadState((s) => ({ ...s, [key]: url }));
} catch (uploadError) {
console.warn('上传图片失败', uploadError);
Alert.alert('上传失败', '图片上传失败,请重试');
// 上传失败,清除状态
setUploadState((s) => ({ ...s, [key]: null }));
} finally {
// 清除上传状态
setUploadingKey(null);
}
}
}
} catch (e) {
@@ -219,6 +260,7 @@ export default function AIPostureAssessmentScreen() {
onPickCamera={() => requestPermissionAndPick('camera', 'front')}
onPickLibrary={() => requestPermissionAndPick('library', 'front')}
samples={SAMPLES.front}
uploading={uploading && uploadingKey === 'front'}
/>
<UploadTile
@@ -227,6 +269,7 @@ export default function AIPostureAssessmentScreen() {
onPickCamera={() => requestPermissionAndPick('camera', 'side')}
onPickLibrary={() => requestPermissionAndPick('library', 'side')}
samples={SAMPLES.side}
uploading={uploading && uploadingKey === 'side'}
/>
<UploadTile
@@ -235,6 +278,7 @@ export default function AIPostureAssessmentScreen() {
onPickCamera={() => requestPermissionAndPick('camera', 'back')}
onPickLibrary={() => requestPermissionAndPick('library', 'back')}
samples={SAMPLES.back}
uploading={uploading && uploadingKey === 'back'}
/>
</ScrollView>
@@ -264,12 +308,14 @@ function UploadTile({
onPickCamera,
onPickLibrary,
samples,
uploading,
}: {
label: string;
value?: string | null;
onPickCamera: () => void;
onPickLibrary: () => void;
samples: Sample[];
uploading?: boolean;
}) {
const [viewerVisible, setViewerVisible] = React.useState(false);
const [viewerIndex, setViewerIndex] = React.useState(0);
@@ -291,8 +337,14 @@ function UploadTile({
onLongPress={onPickLibrary}
onPress={onPickCamera}
style={styles.uploader}
disabled={uploading}
>
{value ? (
{uploading ? (
<View style={[styles.placeholder, { backgroundColor: '#f5f5f5' }]}>
<ActivityIndicator size="large" color="#BBF246" />
<Text style={styles.placeholderTitle}>...</Text>
</View>
) : value ? (
<Image source={{ uri: value }} style={styles.preview} />
) : (
<View style={styles.placeholder}>