Add Chinese translations for medication management and personal settings

- Introduced new translation files for medication, personal, and weight management in Chinese.
- Updated the main index file to include the new translation modules.
- Enhanced the medication type definitions to include 'ointment'.
- Refactored workout type labels to utilize i18n for better localization support.
- Improved sleep quality descriptions and recommendations with i18n integration.
This commit is contained in:
richarjiang
2025-11-28 17:29:51 +08:00
parent fbe0c92f0f
commit bca6670390
42 changed files with 7972 additions and 6632 deletions

View File

@@ -1,6 +1,11 @@
import { useAppSelector } from '@/hooks/redux';
import { useCosUpload } from '@/hooks/useCosUpload';
import { useI18n } from '@/hooks/useI18n';
import { Ionicons } from '@expo/vector-icons';
import { BlurView } from 'expo-blur';
import { Image } from 'expo-image';
import * as ImagePicker from 'expo-image-picker';
import { LinearGradient } from 'expo-linear-gradient';
import React, { useEffect, useMemo, useState } from 'react';
import {
ActivityIndicator,
@@ -15,11 +20,11 @@ import {
Text,
TextInput,
TouchableOpacity,
View
View,
} from 'react-native';
import { useAppSelector } from '@/hooks/redux';
import { useCosUpload } from '@/hooks/useCosUpload';
import { Colors } from '@/constants/Colors';
const CTA_GRADIENT: [string, string] = ['#5E8BFF', '#6B6CFF'];
const CTA_DISABLED_GRADIENT: [string, string] = ['#d3d7e8', '#c1c6da'];
export interface CreateCustomFoodModalProps {
visible: boolean;
@@ -43,9 +48,10 @@ export function CreateCustomFoodModal({
onClose,
onSave
}: CreateCustomFoodModalProps) {
const { t } = useI18n();
const [foodName, setFoodName] = useState('');
const [defaultAmount, setDefaultAmount] = useState('100');
const [caloriesUnit, setCaloriesUnit] = useState('千卡');
const [caloriesUnit, setCaloriesUnit] = useState(t('createCustomFood.units.kcal'));
const [calories, setCalories] = useState('100');
const [imageUrl, setImageUrl] = useState<string>('');
const [protein, setProtein] = useState('0');
@@ -93,7 +99,7 @@ export function CreateCustomFoodModal({
if (visible) {
setFoodName('');
setDefaultAmount('100');
setCaloriesUnit('千卡');
setCaloriesUnit(t('createCustomFood.units.kcal'));
setCalories('100');
setImageUrl('');
setProtein('0');
@@ -102,16 +108,16 @@ export function CreateCustomFoodModal({
}
}, [visible]);
// 选择热量单位
// 选择图片
const handleSelectImage = async () => {
try {
const resp = await ImagePicker.requestMediaLibraryPermissionsAsync();
const libGranted = resp.status === 'granted' || (resp as any).accessPrivileges === 'limited';
if (!libGranted) {
Alert.alert('权限不足', '需要相册权限以选择照片');
Alert.alert(
t('createCustomFood.alerts.permissionDenied.title'),
t('createCustomFood.alerts.permissionDenied.message')
);
return;
}
@@ -137,11 +143,17 @@ export function CreateCustomFoodModal({
setImageUrl(url);
} catch (e) {
console.warn('上传照片失败', e);
Alert.alert('上传失败', '照片上传失败,请重试');
Alert.alert(
t('createCustomFood.alerts.uploadFailed.title'),
t('createCustomFood.alerts.uploadFailed.message')
);
}
}
} catch (e) {
Alert.alert('发生错误', '选择照片失败,请重试');
Alert.alert(
t('createCustomFood.alerts.error.title'),
t('createCustomFood.alerts.error.message')
);
}
};
@@ -151,12 +163,18 @@ export function CreateCustomFoodModal({
// 保存自定义食物
const handleSave = () => {
if (!foodName.trim()) {
Alert.alert('提示', '请输入食物名称');
Alert.alert(
t('createCustomFood.alerts.validation.title'),
t('createCustomFood.alerts.validation.nameRequired')
);
return;
}
if (!calories.trim() || parseFloat(calories) <= 0) {
Alert.alert('提示', '请输入有效的热量值');
Alert.alert(
t('createCustomFood.alerts.validation.title'),
t('createCustomFood.alerts.validation.caloriesRequired')
);
return;
}
@@ -175,75 +193,99 @@ export function CreateCustomFoodModal({
onClose();
};
const isSaveDisabled = !foodName.trim() || !calories.trim();
return (
<Modal
visible={visible}
animationType="fade"
animationType="slide"
transparent={true}
onRequestClose={onClose}
presentationStyle="overFullScreen"
>
<View style={styles.overlay}>
<BlurView intensity={20} tint="dark" style={styles.overlay}>
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={styles.keyboardAvoidingView}
>
<View style={[
styles.modalContainer,
keyboardHeight > 0 && {
height: screenHeight - keyboardHeight,
maxHeight: screenHeight - keyboardHeight,
}
]}>
<TouchableOpacity activeOpacity={1} onPress={onClose} style={styles.dismissArea} />
<View
style={[
styles.modalContainer,
keyboardHeight > 0 && {
height: screenHeight - keyboardHeight - 60,
maxHeight: screenHeight - keyboardHeight - 60,
},
]}
>
<View style={styles.modalHeaderBar}>
<View style={styles.dragIndicator} />
</View>
<ScrollView
style={styles.scrollView}
showsVerticalScrollIndicator={false}
keyboardShouldPersistTaps="handled"
contentContainerStyle={{
flexGrow: 1,
paddingBottom: keyboardHeight > 0 ? 20 : 0
paddingBottom: keyboardHeight > 0 ? 20 : 40,
}}
>
{/* 头部 */}
<View style={styles.header}>
<TouchableOpacity onPress={onClose} style={styles.backButton}>
<Ionicons name="chevron-back" size={24} color="#333" />
<TouchableOpacity onPress={onClose} style={styles.backButton} activeOpacity={0.7}>
<Ionicons name="close-circle" size={32} color="#E2E8F0" />
</TouchableOpacity>
<Text style={styles.headerTitle}></Text>
<Text style={styles.headerTitle}>{t('createCustomFood.title')}</Text>
<TouchableOpacity
style={[
styles.saveButton,
(!foodName.trim() || !calories.trim()) && styles.saveButtonDisabled
]}
style={[styles.saveButton, isSaveDisabled && styles.saveButtonDisabled]}
onPress={handleSave}
disabled={!foodName.trim() || !calories.trim()}
disabled={isSaveDisabled}
activeOpacity={0.8}
>
<Text style={[
styles.saveButtonText,
(!foodName.trim() || !calories.trim()) && styles.saveButtonTextDisabled
]}></Text>
<LinearGradient
colors={isSaveDisabled ? CTA_DISABLED_GRADIENT : CTA_GRADIENT}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
style={styles.saveButtonGradient}
>
<Text style={styles.saveButtonText}>{t('createCustomFood.save')}</Text>
</LinearGradient>
</TouchableOpacity>
</View>
{/* 效果预览区域 */}
<View style={styles.previewSection}>
<Text style={styles.sectionTitle}></Text>
<View style={styles.previewCard}>
<LinearGradient
colors={['#ffffff', '#F8F9FF']}
start={{ x: 0, y: 0 }}
end={{ x: 0, y: 1 }}
style={StyleSheet.absoluteFill}
/>
<View style={styles.previewHeader}>
<Text style={styles.sectionTitle}>{t('createCustomFood.preview.title')}</Text>
</View>
<View style={styles.previewContent}>
{imageUrl ? (
<Image style={styles.previewImage} source={{ uri: imageUrl }} />
) : (
<View style={styles.previewImagePlaceholder}>
<Ionicons name="restaurant" size={20} color="#999" />
</View>
)}
<View style={styles.imageWrapper}>
{imageUrl ? (
<Image style={styles.previewImage} source={{ uri: imageUrl }} />
) : (
<View style={styles.previewImagePlaceholder}>
<Ionicons name="restaurant" size={24} color="#94A3B8" />
</View>
)}
</View>
<View style={styles.previewInfo}>
<Text style={styles.previewName}>
{foodName || '食物名称'}
</Text>
<Text style={styles.previewCalories}>
{actualCalories}{caloriesUnit}/{defaultAmount}g
<Text style={styles.previewName} numberOfLines={1}>
{foodName || t('createCustomFood.preview.defaultName')}
</Text>
<View style={styles.previewBadge}>
<Ionicons name="flame" size={14} color="#F59E0B" />
<Text style={styles.previewCalories}>
{actualCalories} {caloriesUnit} / {defaultAmount}
{t('createCustomFood.units.g')}
</Text>
</View>
</View>
</View>
</View>
@@ -252,21 +294,21 @@ export function CreateCustomFoodModal({
{/* 基本信息 */}
<View style={styles.section}>
<View style={styles.sectionHeader}>
<Text style={styles.sectionTitle}></Text>
<Text style={styles.sectionTitle}>{t('createCustomFood.basicInfo.title')}</Text>
<Text style={styles.requiredIndicator}>*</Text>
</View>
<View style={styles.sectionCard}>
{/* 食物名称和单位 */}
{/* 食物名称 */}
<View style={styles.inputRowContainer}>
<Text style={styles.inputRowLabel}></Text>
<Text style={styles.inputRowLabel}>{t('createCustomFood.basicInfo.name')}</Text>
<View style={styles.inputRowContent}>
<View style={styles.numberInputContainer}>
<View style={styles.modernInputContainer}>
<TextInput
style={styles.modernNumberInput}
value={foodName}
onChangeText={setFoodName}
placeholder="例如,汉堡"
placeholderTextColor="#A0A0A0"
placeholder={t('createCustomFood.basicInfo.namePlaceholder')}
placeholderTextColor="#94A3B8"
/>
</View>
</View>
@@ -274,36 +316,36 @@ export function CreateCustomFoodModal({
{/* 默认数量 */}
<View style={styles.inputRowContainer}>
<Text style={styles.inputRowLabel}></Text>
<Text style={styles.inputRowLabel}>{t('createCustomFood.basicInfo.defaultAmount')}</Text>
<View style={styles.inputRowContent}>
<View style={styles.numberInputContainer}>
<View style={styles.modernInputContainer}>
<TextInput
style={styles.modernNumberInput}
value={defaultAmount}
onChangeText={setDefaultAmount}
keyboardType="numeric"
placeholder="100"
placeholderTextColor="#A0A0A0"
placeholderTextColor="#94A3B8"
/>
<Text style={styles.unitText}>g</Text>
<Text style={styles.unitText}>{t('createCustomFood.units.g')}</Text>
</View>
</View>
</View>
{/* 食物热量 */}
<View style={[styles.inputRowContainer, { marginBottom: 0 }]}>
<Text style={styles.inputRowLabel}></Text>
<Text style={styles.inputRowLabel}>{t('createCustomFood.basicInfo.calories')}</Text>
<View style={styles.inputRowContent}>
<View style={styles.numberInputContainer}>
<View style={styles.modernInputContainer}>
<TextInput
style={styles.modernNumberInput}
value={calories}
onChangeText={setCalories}
keyboardType="numeric"
placeholder="100"
placeholderTextColor="#A0A0A0"
placeholder="0"
placeholderTextColor="#94A3B8"
/>
<Text style={styles.unitText}></Text>
<Text style={styles.unitText}>{t('createCustomFood.units.kcal')}</Text>
</View>
</View>
</View>
@@ -312,23 +354,26 @@ export function CreateCustomFoodModal({
{/* 可选信息 */}
<View style={styles.section}>
<Text style={styles.sectionTitle}></Text>
<Text style={styles.sectionTitle}>{t('createCustomFood.optionalInfo.title')}</Text>
<View style={styles.sectionCard}>
{/* 照片 */}
<View style={styles.inputRowContainer}>
<Text style={styles.inputRowLabel}></Text>
<Text style={styles.inputRowLabel}>{t('createCustomFood.optionalInfo.photo')}</Text>
<View style={styles.inputRowContent}>
<TouchableOpacity
style={styles.modernImageSelector}
<TouchableOpacity
style={styles.modernImageSelector}
onPress={handleSelectImage}
disabled={uploading}
activeOpacity={0.8}
>
{imageUrl ? (
<Image style={styles.selectedImage} source={{ uri: imageUrl }} />
) : (
<View style={styles.modernImagePlaceholder}>
<Ionicons name="camera" size={28} color="#A0A0A0" />
<Text style={styles.imagePlaceholderText}></Text>
<Ionicons name="camera-outline" size={28} color="#94A3B8" />
<Text style={styles.imagePlaceholderText}>
{t('createCustomFood.optionalInfo.addPhoto')}
</Text>
</View>
)}
{uploading && (
@@ -342,54 +387,56 @@ export function CreateCustomFoodModal({
{/* 蛋白质 */}
<View style={styles.inputRowContainer}>
<Text style={styles.inputRowLabel}></Text>
<Text style={styles.inputRowLabel}>{t('createCustomFood.optionalInfo.protein')}</Text>
<View style={styles.inputRowContent}>
<View style={styles.numberInputContainer}>
<View style={styles.modernInputContainer}>
<TextInput
style={styles.modernNumberInput}
value={protein}
onChangeText={setProtein}
keyboardType="numeric"
placeholder="0"
placeholderTextColor="#A0A0A0"
placeholderTextColor="#94A3B8"
/>
<Text style={styles.unitText}></Text>
<Text style={styles.unitText}>{t('createCustomFood.units.gram')}</Text>
</View>
</View>
</View>
{/* 脂肪 */}
<View style={styles.inputRowContainer}>
<Text style={styles.inputRowLabel}></Text>
<Text style={styles.inputRowLabel}>{t('createCustomFood.optionalInfo.fat')}</Text>
<View style={styles.inputRowContent}>
<View style={styles.numberInputContainer}>
<View style={styles.modernInputContainer}>
<TextInput
style={styles.modernNumberInput}
value={fat}
onChangeText={setFat}
keyboardType="numeric"
placeholder="0"
placeholderTextColor="#A0A0A0"
placeholderTextColor="#94A3B8"
/>
<Text style={styles.unitText}></Text>
<Text style={styles.unitText}>{t('createCustomFood.units.gram')}</Text>
</View>
</View>
</View>
{/* 碳水化合物 */}
<View style={[styles.inputRowContainer, { marginBottom: 0 }]}>
<Text style={styles.inputRowLabel}></Text>
<Text style={styles.inputRowLabel}>
{t('createCustomFood.optionalInfo.carbohydrate')}
</Text>
<View style={styles.inputRowContent}>
<View style={styles.numberInputContainer}>
<View style={styles.modernInputContainer}>
<TextInput
style={styles.modernNumberInput}
value={carbohydrate}
onChangeText={setCarbohydrate}
keyboardType="numeric"
placeholder="0"
placeholderTextColor="#A0A0A0"
placeholderTextColor="#94A3B8"
/>
<Text style={styles.unitText}></Text>
<Text style={styles.unitText}>{t('createCustomFood.units.gram')}</Text>
</View>
</View>
</View>
@@ -398,7 +445,7 @@ export function CreateCustomFoodModal({
</ScrollView>
</View>
</KeyboardAvoidingView>
</View>
</BlurView>
</Modal>
);
}
@@ -408,331 +455,272 @@ const { height: screenHeight } = Dimensions.get('window');
const styles = StyleSheet.create({
overlay: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
},
keyboardAvoidingView: {
flex: 1,
justifyContent: 'flex-end',
},
dismissArea: {
flex: 1,
},
modalContainer: {
flex: 1,
backgroundColor: '#FFFFFF',
marginTop: 50,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
backgroundColor: '#F1F5F9', // Slate 100
borderTopLeftRadius: 32,
borderTopRightRadius: 32,
height: '90%',
maxHeight: '90%',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: -4,
},
shadowOpacity: 0.1,
shadowRadius: 12,
elevation: 20,
overflow: 'hidden',
},
modalHeaderBar: {
width: '100%',
height: 24,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#F1F5F9',
},
dragIndicator: {
width: 40,
height: 4,
backgroundColor: '#CBD5E1',
borderRadius: 2,
},
scrollView: {
flex: 1,
backgroundColor: '#F1F5F9',
},
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: 16,
paddingVertical: 16,
paddingHorizontal: 20,
paddingBottom: 20,
},
backButton: {
padding: 4,
marginLeft: -8,
},
headerTitle: {
fontSize: 18,
fontWeight: '600',
color: '#333',
flex: 1,
fontSize: 20,
fontWeight: '800',
color: '#1E293B',
textAlign: 'center',
marginHorizontal: 20,
fontFamily: 'AliBold',
},
saveButton: {
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 16,
borderRadius: 20,
overflow: 'hidden',
},
saveButtonDisabled: {
opacity: 0.5,
opacity: 0.6,
},
saveButtonGradient: {
paddingHorizontal: 16,
paddingVertical: 8,
borderRadius: 20,
},
saveButtonText: {
fontSize: 16,
color: Colors.light.primary,
fontWeight: '500',
},
saveButtonTextDisabled: {
color: Colors.light.textMuted,
fontSize: 14,
color: '#FFFFFF',
fontWeight: '700',
fontFamily: 'AliBold',
},
previewSection: {
paddingHorizontal: 16,
paddingBottom: 16,
paddingHorizontal: 20,
marginBottom: 24,
},
previewCard: {
backgroundColor: '#F8F9FA',
borderRadius: 12,
padding: 16,
marginTop: 8,
borderRadius: 24,
padding: 20,
overflow: 'hidden',
backgroundColor: '#FFFFFF',
shadowColor: 'rgba(30, 41, 59, 0.08)',
shadowOffset: { width: 0, height: 8 },
shadowOpacity: 0.4,
shadowRadius: 12,
elevation: 4,
borderWidth: 1,
borderColor: 'rgba(255,255,255,0.6)',
},
previewHeader: {
marginBottom: 16,
},
previewContent: {
flexDirection: 'row',
alignItems: 'center',
},
imageWrapper: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 4,
},
previewImage: {
width: 32,
height: 32,
borderRadius: 4,
width: 56,
height: 56,
borderRadius: 16,
backgroundColor: '#F8FAFC',
},
previewImagePlaceholder: {
width: 32,
height: 32,
borderRadius: 4,
backgroundColor: '#E5E5E5',
width: 56,
height: 56,
borderRadius: 16,
backgroundColor: '#F1F5F9',
alignItems: 'center',
justifyContent: 'center',
borderWidth: 1,
borderColor: '#E2E8F0',
},
previewInfo: {
flex: 1,
marginLeft: 12,
marginLeft: 16,
justifyContent: 'center',
},
previewName: {
fontSize: 16,
fontWeight: '500',
color: '#333',
marginBottom: 2,
fontSize: 18,
fontWeight: '700',
color: '#1E293B',
marginBottom: 6,
fontFamily: 'AliBold',
},
previewBadge: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#FFFBEB',
paddingHorizontal: 8,
paddingVertical: 4,
borderRadius: 8,
alignSelf: 'flex-start',
gap: 4,
},
previewCalories: {
fontSize: 14,
color: '#666',
fontSize: 13,
color: '#D97706',
fontWeight: '600',
fontFamily: 'AliRegular',
},
section: {
paddingHorizontal: 16,
paddingVertical: 12,
paddingHorizontal: 20,
marginBottom: 24,
},
sectionHeader: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 4,
marginBottom: 12,
paddingHorizontal: 4,
},
sectionTitle: {
fontSize: 14,
color: '#333',
marginLeft: 8
fontWeight: '700',
color: '#64748B',
fontFamily: 'AliBold',
textTransform: 'uppercase',
letterSpacing: 0.5,
},
requiredIndicator: {
fontSize: 16,
color: '#FF4444',
fontSize: 14,
color: '#EF4444',
marginLeft: 4,
},
inputGroup: {
marginBottom: 20,
},
inputRowGroup: {
flexDirection: 'row',
gap: 12,
marginBottom: 20,
},
inputRowItem: {
flex: 1,
},
inputLabel: {
fontSize: 14,
color: '#666',
fontWeight: '500',
},
modernTextInput: {
flex: 1,
borderRadius: 12,
paddingHorizontal: 12,
paddingVertical: 8,
fontSize: 16,
marginLeft: 20,
color: '#333',
backgroundColor: '#FFFFFF',
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.05,
shadowRadius: 2,
elevation: 1,
},
numberInputContainer: {
flexDirection: 'row',
alignItems: 'center',
borderRadius: 12,
backgroundColor: '#FFFFFF',
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.05,
shadowRadius: 2,
elevation: 1,
},
modernNumberInput: {
flex: 1,
paddingHorizontal: 12,
paddingVertical: 8,
fontSize: 16,
color: '#333',
textAlign: 'right',
},
unitText: {
fontSize: 14,
color: '#666',
paddingRight: 16,
minWidth: 40,
textAlign: 'center',
},
modernSelectButton: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
borderWidth: 1.5,
borderColor: '#E8E8E8',
borderRadius: 12,
paddingHorizontal: 16,
paddingVertical: 14,
backgroundColor: '#FFFFFF',
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.05,
shadowRadius: 2,
elevation: 1,
},
selectButtonText: {
fontSize: 14,
color: 'gray',
fontWeight: '500',
},
modernImageSelector: {
alignSelf: 'flex-end',
borderRadius: 16,
overflow: 'hidden',
},
selectedImage: {
width: 80,
height: 80,
borderRadius: 16,
},
modernImagePlaceholder: {
width: 80,
height: 80,
borderRadius: 16,
backgroundColor: '#F8F8F8',
alignItems: 'center',
justifyContent: 'center',
borderWidth: 1.5,
borderColor: '#E8E8E8',
borderStyle: 'dashed',
},
imagePlaceholderText: {
fontSize: 12,
color: '#A0A0A0',
marginTop: 4,
fontWeight: '500',
},
nutritionRow: {
flexDirection: 'row',
gap: 12,
marginBottom: 20,
},
nutritionItem: {
flex: 1,
},
// 保留旧样式以防兼容性问题
textInput: {
borderWidth: 1,
borderColor: '#E5E5E5',
borderRadius: 8,
paddingHorizontal: 12,
paddingVertical: 12,
fontSize: 16,
color: '#333',
backgroundColor: '#FFFFFF',
},
numberInput: {
flex: 1,
borderWidth: 1,
borderColor: '#E5E5E5',
borderRadius: 8,
paddingHorizontal: 12,
paddingVertical: 12,
fontSize: 16,
color: '#333',
backgroundColor: '#FFFFFF',
textAlign: 'right',
},
inputWithUnit: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
inputUnit: {
fontSize: 16,
color: '#666',
minWidth: 30,
},
selectButton: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
borderWidth: 1,
borderColor: '#E5E5E5',
borderRadius: 8,
paddingHorizontal: 12,
paddingVertical: 12,
backgroundColor: '#FFFFFF',
},
imageSelector: {
alignSelf: 'flex-end',
borderRadius: 12,
overflow: 'hidden',
},
imagePlaceholder: {
width: 60,
height: 60,
borderRadius: 12,
backgroundColor: '#F0F0F0',
alignItems: 'center',
justifyContent: 'center',
borderWidth: 1,
borderColor: '#E5E5E5',
},
disclaimer: {
paddingHorizontal: 16,
paddingVertical: 20,
paddingBottom: 40,
},
disclaimerText: {
fontSize: 12,
color: '#999',
lineHeight: 18,
fontWeight: '700',
},
sectionCard: {
backgroundColor: '#F8F9FA',
borderRadius: 12,
padding: 16,
marginTop: 8,
backgroundColor: '#FFFFFF',
borderRadius: 24,
padding: 20,
shadowColor: 'rgba(30, 41, 59, 0.05)',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.5,
shadowRadius: 10,
elevation: 2,
},
// 新增行布局样式
inputRowContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 20,
marginBottom: 16,
},
inputRowLabel: {
fontSize: 14,
color: '#666',
fontWeight: '500',
width: 80,
fontSize: 15,
color: '#475569',
fontWeight: '600',
width: 90,
marginRight: 12,
fontFamily: 'AliRegular',
},
inputRowContent: {
flex: 1,
},
imageLoadingOverlay: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
modernInputContainer: {
flexDirection: 'row',
alignItems: 'center',
borderRadius: 16,
backgroundColor: '#F8FAFC',
borderWidth: 1,
borderColor: '#E2E8F0',
overflow: 'hidden',
},
modernNumberInput: {
flex: 1,
paddingHorizontal: 16,
paddingVertical: 12,
fontSize: 16,
color: '#1E293B',
textAlign: 'right',
fontFamily: 'AliRegular',
},
unitText: {
fontSize: 14,
color: '#94A3B8',
paddingRight: 16,
minWidth: 40,
textAlign: 'center',
fontWeight: '500',
},
modernImageSelector: {
alignSelf: 'flex-end',
borderRadius: 20,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.05,
shadowRadius: 4,
elevation: 2,
},
selectedImage: {
width: 72,
height: 72,
borderRadius: 20,
},
modernImagePlaceholder: {
width: 72,
height: 72,
borderRadius: 20,
backgroundColor: '#F8FAFC',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgba(0,0,0,0.5)',
borderRadius: 16,
borderWidth: 1,
borderColor: '#E2E8F0',
borderStyle: 'dashed',
},
imagePlaceholderText: {
fontSize: 11,
color: '#94A3B8',
marginTop: 4,
fontWeight: '600',
textAlign: 'center',
},
imageLoadingOverlay: {
...StyleSheet.absoluteFillObject,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgba(0,0,0,0.3)',
borderRadius: 20,
},
});