import { Ionicons } from '@expo/vector-icons'; import React, { useEffect, useState } from 'react'; import { Alert, Dimensions, Keyboard, KeyboardAvoidingView, Modal, Platform, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View, } from 'react-native'; // 导入统一的食物类型定义 import { Colors } from '@/constants/Colors'; import { DEFAULT_IMAGE_FOOD } from '@/constants/Image'; import type { FoodItem } from '@/types/food'; import { Image } from 'expo-image'; // 导入统一的食物类型定义 // 营养信息接口 interface NutritionInfo { protein: number; // 蛋白质(克) fat: number; // 脂肪(克) carbs: number; // 碳水化合物(克) } // 快捷选择选项(基于100克的倍数) const QUICK_SELECT_OPTIONS = [ { id: 'small', name: '小份', amount: 80 }, // 80克 { id: 'medium', name: '中份', amount: 120 }, // 120克 { id: 'large', name: '大份', amount: 150 }, // 150克 ]; // 食物详情弹窗属性 export interface FoodDetailModalProps { visible: boolean; food: FoodItem | null; category?: { id: string; isSystem?: boolean } | null; onClose: () => void; onSave: (food: FoodItem, amount: number, unit: string) => void; onDelete?: (foodId: string) => void; } // 获取营养数据,优先使用FoodItem中的数据 const getNutritionInfo = (food: FoodItem): NutritionInfo => { // 检查是否有任何营养数据 const hasNutritionData = food.protein !== undefined || food.fat !== undefined || food.carbohydrate !== undefined; if (hasNutritionData) { // 优先使用FoodItem中的营养数据 return { protein: food.protein || 0, fat: food.fat || 0, carbs: food.carbohydrate || 0, }; } // 如果FoodItem中没有营养数据,使用模拟数据作为后备 const fallbackNutritionData: Record = { '5': { protein: 0.8, fat: 0.6, carbs: 14.5 }, // 猕猴桃 '1': { protein: 0.2, fat: 0.0, carbs: 0.1 }, // 咖啡 '2': { protein: 12.8, fat: 11.1, carbs: 0.7 }, // 荷包蛋 '3': { protein: 13.3, fat: 8.8, carbs: 2.8 }, // 鸡蛋 '4': { protein: 1.4, fat: 0.2, carbs: 22.8 }, // 香蕉 '6': { protein: 0.2, fat: 0.2, carbs: 13.8 }, // 苹果 '7': { protein: 0.7, fat: 0.3, carbs: 7.7 }, // 草莓 '8': { protein: 6.6, fat: 4.6, carbs: 22.7 }, // 蛋烧麦 '9': { protein: 2.6, fat: 0.3, carbs: 25.9 }, // 米饭 '10': { protein: 4.0, fat: 1.2, carbs: 22.8 }, // 玉米 }; return fallbackNutritionData[food.id] || { protein: 0, fat: 0, carbs: 0 }; }; export function FoodDetailModal({ visible, food, category, onClose, onSave, onDelete }: FoodDetailModalProps) { const [amount, setAmount] = useState('100'); const [isFavorite, setIsFavorite] = useState(false); const [keyboardHeight, setKeyboardHeight] = useState(0); // 键盘监听 useEffect(() => { const keyboardDidShowListener = Keyboard.addListener( Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow', (e) => { console.log('键盘显示,高度:', e.endCoordinates.height); setKeyboardHeight(e.endCoordinates.height); } ); const keyboardDidHideListener = Keyboard.addListener( Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide', () => { console.log('键盘隐藏'); setKeyboardHeight(0); } ); return () => { keyboardDidShowListener?.remove(); keyboardDidHideListener?.remove(); }; }, []); // 重置状态 useEffect(() => { if (visible && food) { console.log('FoodDetailModal: 接收到食物数据:', food); setAmount('100'); setIsFavorite(false); } }, [visible, food]); // 调试信息 console.log('FoodDetailModal render:', { visible, food: food?.name, foodId: food?.id, hasFood: !!food }); if (!food) { console.log('FoodDetailModal: food为空,不渲染内容'); return null; } const nutrition = getNutritionInfo(food); const amountNum = parseFloat(amount) || 0; // 计算实际营养值(基于输入的克数) const actualCalories = Math.round((food.calories * amountNum) / 100); const actualProtein = ((nutrition.protein * amountNum) / 100).toFixed(1); const actualFat = ((nutrition.fat * amountNum) / 100).toFixed(1); const actualCarbs = ((nutrition.carbs * amountNum) / 100).toFixed(1); // 快捷选择处理函数 const handleQuickSelect = (selectedAmount: number) => { setAmount(selectedAmount.toString()); }; const handleSave = () => { onSave(food, amountNum, '克'); onClose(); }; console.log('FoodDetailModal 即将渲染 Modal:', { visible, food: food.name }); return ( 0 && { height: screenHeight - keyboardHeight - 100, // 减去键盘高度和更多安全距离 maxHeight: screenHeight - keyboardHeight - 100, minHeight: Math.min(400, screenHeight * 0.4) // 确保最小高度,但不超过屏幕40% } ]}> 0 ? 20 : 0 // 键盘弹出时增加底部间距 }} scrollEnabled={true} bounces={false} > {/* 头部 */} {/* 我要纠错 */} {/* 食物信息 */} {food.name} {/* setIsFavorite(!isFavorite)} style={styles.favoriteButton} > */} {/* 删除按钮 - 仅对自定义食物显示 */} {category && category.id === 'custom' && onDelete && ( { Alert.alert( '删除食物', '确定要删除这个自定义食物吗?', [ { text: '取消', style: 'cancel' }, { text: '删除', style: 'destructive', onPress: () => onDelete(food.id) } ] ); }} style={styles.deleteButton} > )} {/* 营养信息 */} 热量 {actualCalories}千卡 蛋白质 {actualProtein}克 脂肪 {actualFat}克 碳水化合物 {actualCarbs}克 {/* 数量输入 */} {/* 快捷选择 */} {QUICK_SELECT_OPTIONS.map((option) => ( handleQuickSelect(option.amount)} > {option.name} ))} {/* 保存按钮 */} 添加 ); } const { width: screenWidth, height: screenHeight } = Dimensions.get('window'); const styles = StyleSheet.create({ overlay: { flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.5)', justifyContent: 'flex-end', alignItems: 'center', }, keyboardAvoidingView: { width: '100%', justifyContent: 'flex-end', alignItems: 'center', }, modalContainer: { width: screenWidth, backgroundColor: '#FFFFFF', borderRadius: 20, // 四周都设置圆角 // maxHeight: screenHeight * 0.75, // 最大高度为屏幕高度的75% // minHeight: screenHeight * 0.5, // 最小高度为屏幕高度的50% shadowColor: '#000', shadowOffset: { width: 0, height: -5, }, shadowOpacity: 0.25, shadowRadius: 20, elevation: 10, overflow: 'hidden', // 确保内容不会溢出 }, scrollView: { flexGrow: 1, }, header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: screenWidth > 400 ? 24 : 16, // 根据屏幕宽度调整内边距 paddingTop: 16, paddingBottom: 8, }, closeButton: { width: 40, height: 40, borderRadius: 20, backgroundColor: '#F5F5F5', justifyContent: 'center', alignItems: 'center', }, correctButton: { paddingHorizontal: 16, paddingVertical: 8, }, correctButtonText: { fontSize: 16, color: '#4CAF50', fontWeight: '500', }, foodHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: screenWidth > 400 ? 24 : 16, paddingVertical: 12, }, foodInfo: { flexDirection: 'row', alignItems: 'center', flex: 1, }, foodImage: { width: 40, height: 40, marginRight: 12, }, foodEmoji: { fontSize: 40, marginRight: 12, }, foodName: { fontSize: 20, fontWeight: '600', color: '#333', marginRight: 8, }, actionButtons: { flexDirection: 'row', alignItems: 'center', gap: 4, }, favoriteButton: { padding: 8, }, deleteButton: { padding: 8, }, nutritionContainer: { flexDirection: 'row', paddingHorizontal: screenWidth > 400 ? 24 : 16, justifyContent: 'space-between', }, nutritionItem: { alignItems: 'center', flex: 1, }, nutritionLabel: { fontSize: 14, color: '#666', marginBottom: 8, }, nutritionValue: { fontSize: 16, fontWeight: '600', color: '#333', }, amountContainer: { alignItems: 'center', }, inputWithUnit: { flexDirection: 'row', alignItems: 'center', borderRadius: 12, paddingHorizontal: 20, paddingVertical: 16, }, amountInput: { fontSize: 24, fontWeight: '600', color: Colors.light.text, textAlign: 'center', minWidth: 80, backgroundColor: 'transparent', borderBottomWidth: 1, borderBottomColor: 'gray', }, unitLabel: { fontSize: 18, fontWeight: '500', color: Colors.light.text, marginLeft: 8, }, quickSelectContainer: { flexDirection: 'row', justifyContent: 'center', paddingHorizontal: screenWidth > 400 ? 24 : 16, paddingBottom: 20, gap: screenWidth > 400 ? 16 : 12, // 根据屏幕宽度调整间距 }, quickSelectOption: { paddingHorizontal: 16, paddingVertical: 8, borderRadius: 20, backgroundColor: '#F5F5F5', minWidth: 60, alignItems: 'center', }, quickSelectOptionActive: { backgroundColor: Colors.light.primary, }, quickSelectText: { fontSize: 14, color: '#666', fontWeight: '500', }, quickSelectTextActive: { color: '#FFFFFF', }, saveButton: { backgroundColor: Colors.light.primary, marginHorizontal: screenWidth > 400 ? 24 : 16, marginBottom: 16, paddingVertical: 14, borderRadius: 12, alignItems: 'center', }, saveButtonText: { fontSize: 18, fontWeight: '600', color: '#FFFFFF', }, });