feat(food): 添加拍摄指引弹窗与相册选择功能
- 在相机界面新增“拍摄示例”弹窗,展示正确/错误拍摄对比图 - 底部控制栏增加相册选择按钮与帮助按钮 - 优化控制栏布局为左右分布,提升操作便捷性 - 移除 food-recognition 中冗余的 isUploading 状态,简化上传流程
This commit is contained in:
@@ -2,12 +2,14 @@ import { HeaderBar } from '@/components/ui/HeaderBar';
|
||||
import { Colors } from '@/constants/Colors';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { CameraType, CameraView, useCameraPermissions } from 'expo-camera';
|
||||
import { Image } from 'expo-image';
|
||||
import * as ImagePicker from 'expo-image-picker';
|
||||
import { useLocalSearchParams, useRouter } from 'expo-router';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import {
|
||||
Alert,
|
||||
Dimensions,
|
||||
Modal,
|
||||
StatusBar,
|
||||
StyleSheet,
|
||||
Text,
|
||||
@@ -30,6 +32,7 @@ export default function FoodCameraScreen() {
|
||||
);
|
||||
const [facing, setFacing] = useState<CameraType>('back');
|
||||
const [permission, requestPermission] = useCameraPermissions();
|
||||
const [showInstructionModal, setShowInstructionModal] = useState(false);
|
||||
|
||||
// 餐次选择选项
|
||||
const mealOptions = [
|
||||
@@ -199,13 +202,79 @@ export default function FoodCameraScreen() {
|
||||
{/* 底部控制栏 */}
|
||||
<View style={styles.bottomContainer}>
|
||||
<View style={styles.controlsContainer}>
|
||||
{/* 相册选择按钮 */}
|
||||
<TouchableOpacity style={styles.galleryButton} onPress={pickImageFromGallery}>
|
||||
<Ionicons name="images-outline" size={24} color="#FFF" />
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* 拍照按钮 */}
|
||||
<TouchableOpacity style={styles.captureButton} onPress={takePicture}>
|
||||
<View style={styles.captureButtonInner} />
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* 帮助按钮 */}
|
||||
<TouchableOpacity style={styles.helpButton} onPress={() => setShowInstructionModal(true)}>
|
||||
<Ionicons name="help-outline" size={24} color="#FFF" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 拍摄说明弹窗 */}
|
||||
<Modal
|
||||
visible={showInstructionModal}
|
||||
animationType="fade"
|
||||
transparent={true}
|
||||
onRequestClose={() => setShowInstructionModal(false)}
|
||||
>
|
||||
<View style={styles.modalOverlay}>
|
||||
<View style={styles.instructionModal}>
|
||||
<Text style={styles.instructionTitle}>拍摄示例</Text>
|
||||
|
||||
<View style={styles.exampleContainer}>
|
||||
{/* 好的示例 */}
|
||||
<View style={styles.exampleItem}>
|
||||
<View style={styles.exampleImagePlaceholder}>
|
||||
<View style={styles.checkmarkContainer}>
|
||||
<Ionicons name="checkmark" size={32} color="#FFF" />
|
||||
</View>
|
||||
{/* 这里可以放置好的示例图片 */}
|
||||
<Image
|
||||
style={styles.exampleImage}
|
||||
source={{ uri: 'https://plates-1251306435.cos.ap-guangzhou.myqcloud.com/images/function/food-right.jpeg' }}
|
||||
cachePolicy={'memory-disk'}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 不好的示例 */}
|
||||
<View style={styles.exampleItem}>
|
||||
<View style={styles.exampleImagePlaceholder}>
|
||||
<View style={styles.crossContainer}>
|
||||
<Ionicons name="close" size={32} color="#FFF" />
|
||||
</View>
|
||||
<Image
|
||||
style={styles.exampleImage}
|
||||
source={{ uri: 'https://plates-1251306435.cos.ap-guangzhou.myqcloud.com/images/function/food-wrong.jpeg' }}
|
||||
cachePolicy={'memory-disk'}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Text style={styles.instructionDescription}>
|
||||
请上传或拍摄如左图所示的食物照片
|
||||
</Text>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.knowButton}
|
||||
onPress={() => setShowInstructionModal(false)}
|
||||
>
|
||||
<Text style={styles.knowButtonText}>知道了</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -366,7 +435,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
controlsContainer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 20,
|
||||
paddingHorizontal: 40,
|
||||
@@ -423,4 +492,111 @@ const styles = StyleSheet.create({
|
||||
fontSize: 14,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
galleryButton: {
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: 25,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderWidth: 2,
|
||||
borderColor: '#FFF',
|
||||
},
|
||||
helpButton: {
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: 25,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderWidth: 2,
|
||||
borderColor: '#FFF',
|
||||
},
|
||||
modalOverlay: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
instructionModal: {
|
||||
backgroundColor: '#FFF',
|
||||
borderTopLeftRadius: 20,
|
||||
borderTopRightRadius: 20,
|
||||
paddingHorizontal: 24,
|
||||
paddingVertical: 32,
|
||||
minHeight: 400,
|
||||
},
|
||||
instructionTitle: {
|
||||
fontSize: 24,
|
||||
fontWeight: 'bold',
|
||||
textAlign: 'center',
|
||||
marginBottom: 32,
|
||||
color: '#333',
|
||||
},
|
||||
exampleContainer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: 24,
|
||||
paddingHorizontal: 16,
|
||||
},
|
||||
exampleItem: {
|
||||
flex: 1,
|
||||
marginHorizontal: 8,
|
||||
},
|
||||
exampleImagePlaceholder: {
|
||||
width: '100%',
|
||||
aspectRatio: 3 / 4,
|
||||
backgroundColor: '#F0F0F0',
|
||||
borderRadius: 16,
|
||||
position: 'relative',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
checkmarkContainer: {
|
||||
position: 'absolute',
|
||||
top: 12,
|
||||
right: 12,
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: 16,
|
||||
backgroundColor: '#4CAF50',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
zIndex: 10,
|
||||
},
|
||||
crossContainer: {
|
||||
position: 'absolute',
|
||||
top: 12,
|
||||
right: 12,
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: 16,
|
||||
backgroundColor: '#F44336',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
zIndex: 10,
|
||||
},
|
||||
exampleImage: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
instructionDescription: {
|
||||
fontSize: 16,
|
||||
textAlign: 'center',
|
||||
color: '#666',
|
||||
marginBottom: 32,
|
||||
lineHeight: 24,
|
||||
paddingHorizontal: 16,
|
||||
},
|
||||
knowButton: {
|
||||
backgroundColor: '#000',
|
||||
borderRadius: 25,
|
||||
paddingVertical: 16,
|
||||
marginHorizontal: 16,
|
||||
},
|
||||
knowButtonText: {
|
||||
color: '#FFF',
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
textAlign: 'center',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user