feat: 添加食物编辑功能,支持修改食物名称、重量和卡路里
This commit is contained in:
@@ -15,9 +15,11 @@ import {
|
||||
BackHandler,
|
||||
Image,
|
||||
Modal,
|
||||
Pressable,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native';
|
||||
@@ -84,6 +86,8 @@ export default function FoodAnalysisResultScreen() {
|
||||
const [isRecording, setIsRecording] = useState(false);
|
||||
const [showImagePreview, setShowImagePreview] = useState(false);
|
||||
const [animationTrigger, setAnimationTrigger] = useState(0);
|
||||
const [editingFood, setEditingFood] = useState<string | null>(null);
|
||||
const [editFormData, setEditFormData] = useState({ name: '', amount: '', calories: '' });
|
||||
const { imageUri, recognitionId, hideRecordBar } = params;
|
||||
|
||||
// 判断是否隐藏记录栏(默认显示)
|
||||
@@ -199,6 +203,39 @@ export default function FoodAnalysisResultScreen() {
|
||||
setFoodItems(prev => prev.filter(item => item.id !== itemId));
|
||||
};
|
||||
|
||||
// 打开编辑弹窗
|
||||
const handleEditFood = (item: typeof mockFoodItems[0]) => {
|
||||
setEditFormData({
|
||||
name: item.name,
|
||||
amount: item.amount.toString(),
|
||||
calories: item.calories.toString(),
|
||||
});
|
||||
setEditingFood(item.id);
|
||||
};
|
||||
|
||||
// 保存编辑
|
||||
const handleSaveEdit = () => {
|
||||
if (!editingFood) return;
|
||||
|
||||
const amount = parseFloat(editFormData.amount) || 0;
|
||||
const calories = parseFloat(editFormData.calories) || 0;
|
||||
|
||||
setFoodItems(prev => prev.map(item =>
|
||||
item.id === editingFood
|
||||
? { ...item, name: editFormData.name, amount, calories }
|
||||
: item
|
||||
));
|
||||
|
||||
setEditingFood(null);
|
||||
setEditFormData({ name: '', amount: '', calories: '' });
|
||||
};
|
||||
|
||||
// 关闭编辑弹窗
|
||||
const handleCloseEdit = () => {
|
||||
setEditingFood(null);
|
||||
setEditFormData({ name: '', amount: '', calories: '' });
|
||||
};
|
||||
|
||||
// 获取随机食物emoji
|
||||
function getRandomFoodEmoji(): string {
|
||||
const foodEmojis = ['🍎', '🍌', '🍞', '🥛', '🥗', '🍗', '🍖', '🥕', '🥦', '🥬', '🍅', '🥒', '🍇', '🥝', '🍓'];
|
||||
@@ -367,7 +404,10 @@ export default function FoodAnalysisResultScreen() {
|
||||
|
||||
<View style={styles.foodIntakeCalories}>
|
||||
<Text style={styles.foodIntakeCaloriesValue}>{item.calories}千卡</Text>
|
||||
{shouldHideRecordBar ? null : <TouchableOpacity style={styles.editButton}>
|
||||
{shouldHideRecordBar ? null : <TouchableOpacity
|
||||
style={styles.editButton}
|
||||
onPress={() => handleEditFood(item)}
|
||||
>
|
||||
<Ionicons name="create-outline" size={16} color="#666" />
|
||||
</TouchableOpacity>}
|
||||
{shouldHideRecordBar ? null : <TouchableOpacity
|
||||
@@ -508,10 +548,109 @@ export default function FoodAnalysisResultScreen() {
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* 编辑食物弹窗 */}
|
||||
<FoodEditModal
|
||||
visible={!!editingFood}
|
||||
formData={editFormData}
|
||||
onFormDataChange={setEditFormData}
|
||||
onClose={handleCloseEdit}
|
||||
onSave={handleSaveEdit}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
// 编辑食物弹窗组件
|
||||
function FoodEditModal({
|
||||
visible,
|
||||
formData,
|
||||
onFormDataChange,
|
||||
onClose,
|
||||
onSave
|
||||
}: {
|
||||
visible: boolean;
|
||||
formData: { name: string; amount: string; calories: string };
|
||||
onFormDataChange: (data: { name: string; amount: string; calories: string }) => void;
|
||||
onClose: () => void;
|
||||
onSave: () => void;
|
||||
}) {
|
||||
const handleFieldChange = (field: string, value: string) => {
|
||||
onFormDataChange({ ...formData, [field]: value });
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
transparent
|
||||
animationType="fade"
|
||||
onRequestClose={onClose}
|
||||
>
|
||||
<Pressable style={styles.modalBackdrop} onPress={onClose} />
|
||||
<View style={styles.editModalSheet}>
|
||||
<View style={styles.modalHandle} />
|
||||
|
||||
<Text style={styles.modalTitle}>编辑食物信息</Text>
|
||||
|
||||
{/* 食物名称 */}
|
||||
<View style={styles.editFieldContainer}>
|
||||
<Text style={styles.editFieldLabel}>食物名称</Text>
|
||||
<TextInput
|
||||
style={styles.editInput}
|
||||
placeholder="输入食物名称"
|
||||
placeholderTextColor="#999"
|
||||
value={formData.name}
|
||||
onChangeText={(value) => handleFieldChange('name', value)}
|
||||
autoFocus
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* 重量/数量 */}
|
||||
<View style={styles.editFieldContainer}>
|
||||
<Text style={styles.editFieldLabel}>重量 (克)</Text>
|
||||
<TextInput
|
||||
style={styles.editInput}
|
||||
placeholder="输入重量"
|
||||
placeholderTextColor="#999"
|
||||
value={formData.amount}
|
||||
onChangeText={(value) => handleFieldChange('amount', value)}
|
||||
keyboardType="numeric"
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* 卡路里 */}
|
||||
<View style={styles.editFieldContainer}>
|
||||
<Text style={styles.editFieldLabel}>卡路里 (千卡)</Text>
|
||||
<TextInput
|
||||
style={styles.editInput}
|
||||
placeholder="输入卡路里"
|
||||
placeholderTextColor="#999"
|
||||
value={formData.calories}
|
||||
onChangeText={(value) => handleFieldChange('calories', value)}
|
||||
keyboardType="numeric"
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* 按钮区域 */}
|
||||
<View style={styles.modalButtons}>
|
||||
<TouchableOpacity
|
||||
onPress={onClose}
|
||||
style={styles.modalCancelBtn}
|
||||
>
|
||||
<Text style={styles.modalCancelText}>取消</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={onSave}
|
||||
style={[styles.modalSaveBtn, { backgroundColor: Colors.light.primary }]}
|
||||
>
|
||||
<Text style={[styles.modalSaveText, { color: Colors.light.onPrimary }]}>保存</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
// 营养圆环组件
|
||||
function NutritionRing({
|
||||
label,
|
||||
@@ -1039,4 +1178,84 @@ const styles = StyleSheet.create({
|
||||
fontSize: 16,
|
||||
fontWeight: '500',
|
||||
},
|
||||
modalBackdrop: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
backgroundColor: 'rgba(0,0,0,0.4)',
|
||||
},
|
||||
// 编辑弹窗样式
|
||||
editModalSheet: {
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderTopLeftRadius: 20,
|
||||
borderTopRightRadius: 20,
|
||||
paddingHorizontal: 20,
|
||||
paddingBottom: 40,
|
||||
paddingTop: 20,
|
||||
},
|
||||
modalHandle: {
|
||||
width: 36,
|
||||
height: 4,
|
||||
backgroundColor: '#E0E0E0',
|
||||
borderRadius: 2,
|
||||
alignSelf: 'center',
|
||||
marginBottom: 20,
|
||||
},
|
||||
modalTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: '600',
|
||||
color: '#333333',
|
||||
marginBottom: 24,
|
||||
textAlign: 'center',
|
||||
},
|
||||
editFieldContainer: {
|
||||
marginBottom: 20,
|
||||
},
|
||||
editFieldLabel: {
|
||||
fontSize: 16,
|
||||
fontWeight: '500',
|
||||
color: '#333333',
|
||||
marginBottom: 8,
|
||||
},
|
||||
editInput: {
|
||||
height: 50,
|
||||
borderWidth: 1,
|
||||
borderColor: '#E0E0E0',
|
||||
borderRadius: 12,
|
||||
paddingHorizontal: 16,
|
||||
fontSize: 16,
|
||||
backgroundColor: '#FFFFFF',
|
||||
color: '#333333',
|
||||
},
|
||||
modalButtons: {
|
||||
flexDirection: 'row',
|
||||
gap: 12,
|
||||
marginTop: 8,
|
||||
},
|
||||
modalCancelBtn: {
|
||||
flex: 1,
|
||||
height: 50,
|
||||
backgroundColor: '#F0F0F0',
|
||||
borderRadius: 12,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
modalCancelText: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: '#666666',
|
||||
},
|
||||
modalSaveBtn: {
|
||||
flex: 1,
|
||||
height: 50,
|
||||
borderRadius: 12,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
modalSaveText: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user