feat(ui): 添加设置弹窗功能并重构水摄入设置界面

- 添加设置弹窗状态管理
- 实现设置按钮点击处理函数
- 在头部添加设置图标按钮
- 移除原有的设置行界面,改为弹窗形式展示
- 添加新的样式定义支持设置弹窗布局
- 优化设置项的展示和交互体验
This commit is contained in:
richarjiang
2025-09-25 18:56:01 +08:00
parent 0f289fcae7
commit 94899fbc5c
2 changed files with 140 additions and 114 deletions

View File

@@ -37,7 +37,8 @@ const WaterSettings: React.FC<WaterSettingsProps> = () => {
const [dailyGoal, setDailyGoal] = useState<string>('2000');
const [quickAddAmount, setQuickAddAmount] = useState<string>('250');
// 编辑弹窗状态
// 设置弹窗状态
const [settingsModalVisible, setSettingsModalVisible] = useState(false);
const [goalModalVisible, setGoalModalVisible] = useState(false);
const [quickAddModalVisible, setQuickAddModalVisible] = useState(false);
@@ -49,19 +50,24 @@ const WaterSettings: React.FC<WaterSettingsProps> = () => {
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 = () => {
setTempGoal(parseInt(dailyGoal));
setSettingsModalVisible(false);
setGoalModalVisible(true);
};
// 打开快速添加弹窗时初始化临时值
const openQuickAddModal = () => {
setTempQuickAdd(parseInt(quickAddAmount));
setSettingsModalVisible(false);
setQuickAddModalVisible(true);
};
@@ -224,6 +230,15 @@ const WaterSettings: React.FC<WaterSettingsProps> = () => {
// 这里会通过路由自动处理返回
router.back();
}}
right={
<TouchableOpacity
style={styles.settingsButton}
onPress={handleSettingsPress}
activeOpacity={0.7}
>
<Ionicons name="settings-outline" size={24} color={colorTokens.text} />
</TouchableOpacity>
}
/>
<KeyboardAvoidingView
@@ -235,44 +250,6 @@ const WaterSettings: React.FC<WaterSettingsProps> = () => {
contentContainerStyle={styles.scrollContent}
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}>
@@ -311,6 +288,52 @@ const WaterSettings: React.FC<WaterSettingsProps> = () => {
</ScrollView>
</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
visible={goalModalVisible}
@@ -452,79 +475,6 @@ const styles = StyleSheet.create({
fontWeight: '400',
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: {
gap: 12,
@@ -700,6 +650,80 @@ const styles = StyleSheet.create({
modalBtnTextPrimary: {
// 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;

View File

@@ -150,6 +150,7 @@ const WaterIntakeCard: React.FC<WaterIntakeCardProps> = ({
};
return (
<TouchableOpacity
style={[styles.container, style]}
@@ -260,6 +261,7 @@ const WaterIntakeCard: React.FC<WaterIntakeCardProps> = ({
</Text>
</View>
</TouchableOpacity>
);
};