import { HeaderBar } from '@/components/ui/HeaderBar'; import { Colors } from '@/constants/Colors'; import { useSafeAreaTop } from '@/hooks/useSafeAreaWithPadding'; 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, Modal, StatusBar, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; type MealType = 'breakfast' | 'lunch' | 'dinner' | 'snack'; export default function FoodCameraScreen() { const safeAreaTop = useSafeAreaTop() const router = useRouter(); const params = useLocalSearchParams<{ mealType?: string }>(); const cameraRef = useRef(null); const [currentMealType, setCurrentMealType] = useState( (params.mealType as MealType) || 'dinner' ); const [facing, setFacing] = useState('back'); const [permission, requestPermission] = useCameraPermissions(); const [showInstructionModal, setShowInstructionModal] = useState(false); // 餐次选择选项 const mealOptions = [ { key: 'breakfast' as const, label: '早餐', icon: '☀️' }, { key: 'lunch' as const, label: '午餐', icon: '🌤️' }, { key: 'dinner' as const, label: '晚餐', icon: '🌙' }, { key: 'snack' as const, label: '加餐', icon: '🍎' }, ]; if (!permission) { // 权限仍在加载中 return ( router.back()} transparent={true} /> 正在加载相机... ); } if (!permission.granted) { // 没有相机权限 return ( router.back()} backColor='#ffffff' /> 需要相机权限 为了拍摄食物,需要访问您的相机 授权访问 ); } // 切换相机前后摄像头 function toggleCameraFacing() { setFacing(current => (current === 'back' ? 'front' : 'back')); } // 拍摄照片 const takePicture = async () => { if (cameraRef.current) { try { const photo = await cameraRef.current.takePictureAsync({ quality: 0.8, base64: false, }); if (photo) { // 跳转到食物识别页面 console.log('照片拍摄成功:', photo.uri); router.replace(`/food/food-recognition?imageUri=${encodeURIComponent(photo.uri)}&mealType=${currentMealType}`); } } catch (error) { console.error('拍照失败:', error); Alert.alert('拍照失败', '请重试'); } } }; // 从相册选择照片 const pickImageFromGallery = async () => { try { const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['images'], allowsEditing: true, aspect: [4, 3], quality: 0.8, }); if (!result.canceled && result.assets[0]) { const imageUri = result.assets[0].uri; console.log('从相册选择的照片:', imageUri); router.push(`/food/food-recognition?imageUri=${encodeURIComponent(imageUri)}&mealType=${currentMealType}`); } } catch (error) { console.error('选择照片失败:', error); Alert.alert('选择失败', '请重试'); } }; // AR功能(暂时显示提示) const handleARPress = () => { Alert.alert('AR功能', 'AR食物识别功能即将推出'); }; // 餐次选择 const handleMealTypeChange = (mealType: MealType) => { setCurrentMealType(mealType); }; return ( {/* 头部导航 */} router.back()} transparent={true} backColor={'#fff'} /> {/* 主要内容区域 */} {/* 取景框容器 */} 确保食物在取景框内 {/* 相机取景框包装器 */} {/* 相机取景框 */} {/* 取景框装饰 - 放在外层避免被截断 */} {/* 餐次选择器 */} {mealOptions.map((option) => ( handleMealTypeChange(option.key)} > {option.icon} {option.label} ))} {/* 底部控制栏 */} {/* 相册选择按钮 */} {/* 拍照按钮 */} {/* 帮助按钮 */} setShowInstructionModal(true)}> {/* 拍摄说明弹窗 */} setShowInstructionModal(false)} > 拍摄示例 {/* 好的示例 */} {/* 这里可以放置好的示例图片 */} {/* 不好的示例 */} 请上传或拍摄如左图所示的食物照片 setShowInstructionModal(false)} > 知道了 ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#000', }, contentContainer: { flex: 1, paddingTop: 100, }, cameraFrameContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 20, }, cameraWrapper: { width: 300, height: 300, position: 'relative', }, cameraFrame: { width: 300, height: 300, borderRadius: 20, overflow: 'hidden', backgroundColor: '#000', }, cameraView: { flex: 1, }, viewfinderOverlay: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, zIndex: 1, pointerEvents: 'none', }, camera: { flex: 1, }, loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#000', }, loadingText: { color: '#FFF', fontSize: 16, }, permissionContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#000', paddingHorizontal: 40, }, permissionTitle: { color: '#FFF', fontSize: 20, fontWeight: '600', marginTop: 20, marginBottom: 10, }, permissionText: { color: '#CCC', fontSize: 16, textAlign: 'center', marginBottom: 30, lineHeight: 22, }, permissionButton: { backgroundColor: Colors.light.primary, paddingHorizontal: 24, paddingVertical: 12, borderRadius: 24, }, permissionButtonText: { color: '#FFF', fontSize: 16, fontWeight: '600', }, header: { position: 'absolute', top: 0, left: 0, right: 0, zIndex: 10, }, hintText: { color: '#FFF', fontSize: 16, fontWeight: '500', marginBottom: 20, textAlign: 'center', }, corner: { position: 'absolute', width: 30, height: 30, borderColor: '#FFF', borderWidth: 3, }, topLeft: { top: 0, left: 0, borderRightWidth: 0, borderBottomWidth: 0, }, topRight: { top: 0, right: 0, borderLeftWidth: 0, borderBottomWidth: 0, }, bottomLeft: { bottom: 0, left: 0, borderRightWidth: 0, borderTopWidth: 0, }, bottomRight: { bottom: 0, right: 0, borderLeftWidth: 0, borderTopWidth: 0, }, mealTypeContainer: { flexDirection: 'row', justifyContent: 'center', paddingHorizontal: 20, marginVertical: 20, }, mealTypeButton: { alignItems: 'center', paddingHorizontal: 16, paddingVertical: 8, marginHorizontal: 8, borderRadius: 20, backgroundColor: 'rgba(255, 255, 255, 0.2)', minWidth: 70, }, mealTypeButtonActive: { backgroundColor: 'rgba(255, 255, 255, 0.9)', }, mealTypeIcon: { fontSize: 20, marginBottom: 2, }, mealTypeText: { color: '#FFF', fontSize: 12, fontWeight: '500', }, mealTypeTextActive: { color: '#333', }, bottomContainer: { paddingBottom: 40, }, controlsContainer: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: 20, paddingHorizontal: 40, }, controlButton: { alignItems: 'center', }, controlButtonText: { color: '#FFF', fontSize: 12, marginTop: 8, fontWeight: '500', }, albumButton: { width: 50, height: 50, borderRadius: 10, backgroundColor: 'rgba(255, 255, 255, 0.2)', justifyContent: 'center', alignItems: 'center', borderWidth: 2, borderColor: '#FFF', }, captureButton: { width: 80, height: 80, borderRadius: 40, backgroundColor: '#FFF', justifyContent: 'center', alignItems: 'center', borderWidth: 4, borderColor: 'rgba(255, 255, 255, 0.3)', }, captureButtonInner: { width: 60, height: 60, borderRadius: 30, backgroundColor: '#FFF', borderWidth: 2, borderColor: '#333', }, arButton: { width: 50, height: 50, borderRadius: 25, backgroundColor: 'rgba(255, 255, 255, 0.2)', justifyContent: 'center', alignItems: 'center', borderWidth: 2, borderColor: '#FFF', }, arButtonText: { color: '#FFF', 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', }, });