feat(ui): 添加设置弹窗功能并重构水摄入设置界面
- 添加设置弹窗状态管理 - 实现设置按钮点击处理函数 - 在头部添加设置图标按钮 - 移除原有的设置行界面,改为弹窗形式展示 - 添加新的样式定义支持设置弹窗布局 - 优化设置项的展示和交互体验
This commit is contained in:
@@ -37,7 +37,8 @@ const WaterSettings: React.FC<WaterSettingsProps> = () => {
|
|||||||
const [dailyGoal, setDailyGoal] = useState<string>('2000');
|
const [dailyGoal, setDailyGoal] = useState<string>('2000');
|
||||||
const [quickAddAmount, setQuickAddAmount] = useState<string>('250');
|
const [quickAddAmount, setQuickAddAmount] = useState<string>('250');
|
||||||
|
|
||||||
// 编辑弹窗状态
|
// 设置弹窗状态
|
||||||
|
const [settingsModalVisible, setSettingsModalVisible] = useState(false);
|
||||||
const [goalModalVisible, setGoalModalVisible] = useState(false);
|
const [goalModalVisible, setGoalModalVisible] = useState(false);
|
||||||
const [quickAddModalVisible, setQuickAddModalVisible] = useState(false);
|
const [quickAddModalVisible, setQuickAddModalVisible] = useState(false);
|
||||||
|
|
||||||
@@ -49,19 +50,24 @@ const WaterSettings: React.FC<WaterSettingsProps> = () => {
|
|||||||
const { waterRecords, dailyWaterGoal, updateWaterGoal, removeWaterRecord } = useWaterDataByDate(selectedDate);
|
const { waterRecords, dailyWaterGoal, updateWaterGoal, removeWaterRecord } = useWaterDataByDate(selectedDate);
|
||||||
|
|
||||||
|
|
||||||
const goalPresets = [1500, 2000, 2500, 3000, 3500, 4000];
|
|
||||||
const quickAddPresets = [100, 150, 200, 250, 300, 350, 400, 500];
|
|
||||||
|
|
||||||
|
|
||||||
|
// 处理设置按钮点击
|
||||||
|
const handleSettingsPress = () => {
|
||||||
|
setSettingsModalVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
// 打开饮水目标弹窗时初始化临时值
|
// 打开饮水目标弹窗时初始化临时值
|
||||||
const openGoalModal = () => {
|
const openGoalModal = () => {
|
||||||
setTempGoal(parseInt(dailyGoal));
|
setTempGoal(parseInt(dailyGoal));
|
||||||
|
setSettingsModalVisible(false);
|
||||||
setGoalModalVisible(true);
|
setGoalModalVisible(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 打开快速添加弹窗时初始化临时值
|
// 打开快速添加弹窗时初始化临时值
|
||||||
const openQuickAddModal = () => {
|
const openQuickAddModal = () => {
|
||||||
setTempQuickAdd(parseInt(quickAddAmount));
|
setTempQuickAdd(parseInt(quickAddAmount));
|
||||||
|
setSettingsModalVisible(false);
|
||||||
setQuickAddModalVisible(true);
|
setQuickAddModalVisible(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -224,6 +230,15 @@ const WaterSettings: React.FC<WaterSettingsProps> = () => {
|
|||||||
// 这里会通过路由自动处理返回
|
// 这里会通过路由自动处理返回
|
||||||
router.back();
|
router.back();
|
||||||
}}
|
}}
|
||||||
|
right={
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.settingsButton}
|
||||||
|
onPress={handleSettingsPress}
|
||||||
|
activeOpacity={0.7}
|
||||||
|
>
|
||||||
|
<Ionicons name="settings-outline" size={24} color={colorTokens.text} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<KeyboardAvoidingView
|
<KeyboardAvoidingView
|
||||||
@@ -235,44 +250,6 @@ const WaterSettings: React.FC<WaterSettingsProps> = () => {
|
|||||||
contentContainerStyle={styles.scrollContent}
|
contentContainerStyle={styles.scrollContent}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
>
|
>
|
||||||
{/* 第一部分:饮水配置 */}
|
|
||||||
<View style={styles.section}>
|
|
||||||
<Text style={[styles.sectionTitle, { color: colorTokens.text }]}>饮水配置</Text>
|
|
||||||
|
|
||||||
{/* 设置目标部分 */}
|
|
||||||
<TouchableOpacity
|
|
||||||
style={[styles.settingRow, { backgroundColor: colorTokens.pageBackgroundEmphasis }]}
|
|
||||||
onPress={openGoalModal}
|
|
||||||
activeOpacity={0.8}
|
|
||||||
>
|
|
||||||
<View style={styles.settingLeft}>
|
|
||||||
<Text style={[styles.settingTitle, { color: colorTokens.text }]}>每日饮水目标</Text>
|
|
||||||
<Text style={[styles.settingValue, { color: colorTokens.textSecondary }]}>{dailyGoal}ml</Text>
|
|
||||||
</View>
|
|
||||||
<View style={styles.settingRight}>
|
|
||||||
<Ionicons name="chevron-forward" size={16} color={colorTokens.icon} />
|
|
||||||
</View>
|
|
||||||
</TouchableOpacity>
|
|
||||||
|
|
||||||
{/* 快速添加默认值设置部分 */}
|
|
||||||
<TouchableOpacity
|
|
||||||
style={[styles.settingRow, { backgroundColor: colorTokens.pageBackgroundEmphasis, marginTop: 24 }]}
|
|
||||||
onPress={openQuickAddModal}
|
|
||||||
activeOpacity={0.8}
|
|
||||||
>
|
|
||||||
<View style={styles.settingLeft}>
|
|
||||||
<Text style={[styles.settingTitle, { color: colorTokens.text }]}>快速添加默认值</Text>
|
|
||||||
<Text style={[styles.settingSubtitle, { color: colorTokens.textSecondary }]}>
|
|
||||||
{`设置点击右上角"+"按钮时添加的默认饮水量`}
|
|
||||||
</Text>
|
|
||||||
<Text style={[styles.settingValue, { color: colorTokens.textSecondary }]}>{quickAddAmount}ml</Text>
|
|
||||||
</View>
|
|
||||||
<View style={styles.settingRight}>
|
|
||||||
<Ionicons name="chevron-forward" size={16} color={colorTokens.icon} />
|
|
||||||
</View>
|
|
||||||
</TouchableOpacity>
|
|
||||||
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* 第二部分:饮水记录 */}
|
{/* 第二部分:饮水记录 */}
|
||||||
<View style={styles.section}>
|
<View style={styles.section}>
|
||||||
@@ -311,6 +288,52 @@ const WaterSettings: React.FC<WaterSettingsProps> = () => {
|
|||||||
</ScrollView>
|
</ScrollView>
|
||||||
</KeyboardAvoidingView>
|
</KeyboardAvoidingView>
|
||||||
|
|
||||||
|
{/* 设置主弹窗 */}
|
||||||
|
<Modal
|
||||||
|
visible={settingsModalVisible}
|
||||||
|
transparent
|
||||||
|
animationType="fade"
|
||||||
|
onRequestClose={() => setSettingsModalVisible(false)}
|
||||||
|
>
|
||||||
|
<Pressable style={styles.modalBackdrop} onPress={() => setSettingsModalVisible(false)} />
|
||||||
|
<View style={styles.settingsModalSheet}>
|
||||||
|
<View style={styles.modalHandle} />
|
||||||
|
<Text style={[styles.settingsModalTitle, { color: colorTokens.text }]}>饮水设置</Text>
|
||||||
|
|
||||||
|
{/* 菜单项 */}
|
||||||
|
<View style={styles.settingsMenuContainer}>
|
||||||
|
<TouchableOpacity style={styles.settingsMenuItem} onPress={openGoalModal}>
|
||||||
|
<View style={styles.settingsMenuItemLeft}>
|
||||||
|
<View style={[styles.settingsIconContainer, { backgroundColor: 'rgba(147, 112, 219, 0.1)' }]}>
|
||||||
|
<Ionicons name="flag-outline" size={20} color="#9370DB" />
|
||||||
|
</View>
|
||||||
|
<View style={styles.settingsMenuItemContent}>
|
||||||
|
<Text style={[styles.settingsMenuItemTitle, { color: colorTokens.text }]}>每日饮水目标</Text>
|
||||||
|
<Text style={[styles.settingsMenuItemValue, { color: colorTokens.textSecondary }]}>{dailyWaterGoal || dailyGoal}ml</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<Ionicons name="chevron-forward" size={20} color="#CCCCCC" />
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
<TouchableOpacity style={[styles.settingsMenuItem, { borderBottomWidth: 0 }]} onPress={openQuickAddModal}>
|
||||||
|
<View style={styles.settingsMenuItemLeft}>
|
||||||
|
<View style={[styles.settingsIconContainer, { backgroundColor: 'rgba(147, 112, 219, 0.1)' }]}>
|
||||||
|
<Ionicons name="add-outline" size={20} color="#9370DB" />
|
||||||
|
</View>
|
||||||
|
<View style={styles.settingsMenuItemContent}>
|
||||||
|
<Text style={[styles.settingsMenuItemTitle, { color: colorTokens.text }]}>快速添加默认值</Text>
|
||||||
|
<Text style={[styles.settingsMenuItemSubtitle, { color: colorTokens.textSecondary }]}>
|
||||||
|
设置点击"+"按钮时添加的默认饮水量
|
||||||
|
</Text>
|
||||||
|
<Text style={[styles.settingsMenuItemValue, { color: colorTokens.textSecondary }]}>{quickAddAmount}ml</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<Ionicons name="chevron-forward" size={20} color="#CCCCCC" />
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
{/* 饮水目标编辑弹窗 */}
|
{/* 饮水目标编辑弹窗 */}
|
||||||
<Modal
|
<Modal
|
||||||
visible={goalModalVisible}
|
visible={goalModalVisible}
|
||||||
@@ -452,79 +475,6 @@ const styles = StyleSheet.create({
|
|||||||
fontWeight: '400',
|
fontWeight: '400',
|
||||||
lineHeight: 18,
|
lineHeight: 18,
|
||||||
},
|
},
|
||||||
input: {
|
|
||||||
borderRadius: 12,
|
|
||||||
paddingHorizontal: 16,
|
|
||||||
paddingVertical: 14,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: '500',
|
|
||||||
marginBottom: 16,
|
|
||||||
},
|
|
||||||
settingRow: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
paddingVertical: 16,
|
|
||||||
paddingHorizontal: 16,
|
|
||||||
borderRadius: 12,
|
|
||||||
marginBottom: 16,
|
|
||||||
},
|
|
||||||
settingLeft: {
|
|
||||||
flex: 1,
|
|
||||||
},
|
|
||||||
settingTitle: {
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: '500',
|
|
||||||
marginBottom: 4,
|
|
||||||
},
|
|
||||||
settingSubtitle: {
|
|
||||||
fontSize: 14,
|
|
||||||
marginBottom: 8,
|
|
||||||
},
|
|
||||||
settingValue: {
|
|
||||||
fontSize: 16,
|
|
||||||
},
|
|
||||||
settingRight: {
|
|
||||||
marginLeft: 12,
|
|
||||||
},
|
|
||||||
quickAmountsContainer: {
|
|
||||||
marginBottom: 15,
|
|
||||||
},
|
|
||||||
quickAmountsWrapper: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
gap: 10,
|
|
||||||
paddingRight: 10,
|
|
||||||
},
|
|
||||||
quickAmountButton: {
|
|
||||||
paddingHorizontal: 20,
|
|
||||||
paddingVertical: 8,
|
|
||||||
borderRadius: 20,
|
|
||||||
minWidth: 70,
|
|
||||||
alignItems: 'center',
|
|
||||||
shadowColor: '#000',
|
|
||||||
shadowOffset: { width: 0, height: 1 },
|
|
||||||
shadowOpacity: 0.05,
|
|
||||||
shadowRadius: 2,
|
|
||||||
elevation: 1,
|
|
||||||
},
|
|
||||||
quickAmountText: {
|
|
||||||
fontSize: 15,
|
|
||||||
fontWeight: '500',
|
|
||||||
},
|
|
||||||
saveButton: {
|
|
||||||
paddingVertical: 14,
|
|
||||||
borderRadius: 12,
|
|
||||||
alignItems: 'center',
|
|
||||||
marginTop: 24,
|
|
||||||
shadowOffset: { width: 0, height: 2 },
|
|
||||||
shadowOpacity: 0.25,
|
|
||||||
shadowRadius: 4,
|
|
||||||
elevation: 3,
|
|
||||||
},
|
|
||||||
saveButtonText: {
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: '700',
|
|
||||||
},
|
|
||||||
// 饮水记录相关样式
|
// 饮水记录相关样式
|
||||||
recordsList: {
|
recordsList: {
|
||||||
gap: 12,
|
gap: 12,
|
||||||
@@ -700,6 +650,80 @@ const styles = StyleSheet.create({
|
|||||||
modalBtnTextPrimary: {
|
modalBtnTextPrimary: {
|
||||||
// color will be set dynamically
|
// color will be set dynamically
|
||||||
},
|
},
|
||||||
|
settingsButton: {
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
settingsModalSheet: {
|
||||||
|
position: 'absolute',
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
padding: 16,
|
||||||
|
backgroundColor: '#FFFFFF',
|
||||||
|
borderTopLeftRadius: 16,
|
||||||
|
borderTopRightRadius: 16,
|
||||||
|
shadowColor: '#000000',
|
||||||
|
shadowOffset: { width: 0, height: -2 },
|
||||||
|
shadowOpacity: 0.1,
|
||||||
|
shadowRadius: 8,
|
||||||
|
elevation: 16,
|
||||||
|
},
|
||||||
|
settingsModalTitle: {
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: '600',
|
||||||
|
textAlign: 'center',
|
||||||
|
marginBottom: 20,
|
||||||
|
},
|
||||||
|
settingsMenuContainer: {
|
||||||
|
backgroundColor: '#FFFFFF',
|
||||||
|
borderRadius: 12,
|
||||||
|
shadowColor: '#000',
|
||||||
|
shadowOffset: { width: 0, height: 1 },
|
||||||
|
shadowOpacity: 0.05,
|
||||||
|
shadowRadius: 4,
|
||||||
|
elevation: 2,
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
settingsMenuItem: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
paddingVertical: 14,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: '#F1F3F4',
|
||||||
|
},
|
||||||
|
settingsMenuItemLeft: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
settingsIconContainer: {
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
borderRadius: 6,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
marginRight: 12,
|
||||||
|
},
|
||||||
|
settingsMenuItemContent: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
settingsMenuItemTitle: {
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: '500',
|
||||||
|
marginBottom: 2,
|
||||||
|
},
|
||||||
|
settingsMenuItemSubtitle: {
|
||||||
|
fontSize: 12,
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
|
settingsMenuItemValue: {
|
||||||
|
fontSize: 14,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default WaterSettings;
|
export default WaterSettings;
|
||||||
|
|||||||
@@ -150,6 +150,7 @@ const WaterIntakeCard: React.FC<WaterIntakeCardProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.container, style]}
|
style={[styles.container, style]}
|
||||||
@@ -260,6 +261,7 @@ const WaterIntakeCard: React.FC<WaterIntakeCardProps> = ({
|
|||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user