diff --git a/assets/images/icons/icon-bell.png b/assets/images/icons/icon-bell.png new file mode 100644 index 0000000..37d044c Binary files /dev/null and b/assets/images/icons/icon-bell.png differ diff --git a/assets/images/icons/icon-calender.png b/assets/images/icons/icon-calender.png new file mode 100644 index 0000000..2e263f6 Binary files /dev/null and b/assets/images/icons/icon-calender.png differ diff --git a/assets/images/icons/icon-clock.png b/assets/images/icons/icon-clock.png new file mode 100644 index 0000000..d8cbc51 Binary files /dev/null and b/assets/images/icons/icon-clock.png differ diff --git a/assets/images/icons/icon-fire.png b/assets/images/icons/icon-fire.png new file mode 100644 index 0000000..865bbb3 Binary files /dev/null and b/assets/images/icons/icon-fire.png differ diff --git a/assets/images/icons/icon-remind.png b/assets/images/icons/icon-remind.png new file mode 100644 index 0000000..03d32bb Binary files /dev/null and b/assets/images/icons/icon-remind.png differ diff --git a/components/CreateGoalModal.tsx b/components/CreateGoalModal.tsx index f70b7c8..43541e4 100644 --- a/components/CreateGoalModal.tsx +++ b/components/CreateGoalModal.tsx @@ -6,16 +6,17 @@ import DateTimePicker from '@react-native-community/datetimepicker'; import { LinearGradient } from 'expo-linear-gradient'; import React, { useState } from 'react'; import { - Alert, - Modal, - Platform, - ScrollView, - StyleSheet, - Switch, - Text, - TextInput, - TouchableOpacity, - View, + Alert, + Image, + Modal, + Platform, + ScrollView, + StyleSheet, + Switch, + Text, + TextInput, + TouchableOpacity, + View, } from 'react-native'; import WheelPickerExpo from 'react-native-wheel-picker-expo'; @@ -31,7 +32,6 @@ const REPEAT_TYPE_OPTIONS: { value: RepeatType; label: string }[] = [ { value: 'daily', label: '每日' }, { value: 'weekly', label: '每周' }, { value: 'monthly', label: '每月' }, - { value: 'custom', label: '自定义' }, ]; const FREQUENCY_OPTIONS = Array.from({ length: 30 }, (_, i) => i + 1); @@ -59,6 +59,11 @@ export const CreateGoalModal: React.FC = ({ const [priority, setPriority] = useState(5); const [showTimePicker, setShowTimePicker] = useState(false); const [tempSelectedTime, setTempSelectedTime] = useState(null); + + // 周几选择状态 + const [selectedWeekdays, setSelectedWeekdays] = useState([1, 2, 3, 4, 5]); // 默认周一到周五 + // 每月日期选择状态 + const [selectedMonthDays, setSelectedMonthDays] = useState([1, 15]); // 默认1号和15号 // 重置表单 const resetForm = () => { @@ -70,6 +75,8 @@ export const CreateGoalModal: React.FC = ({ setReminderTime('20:00'); setCategory(''); setPriority(5); + setSelectedWeekdays([1, 2, 3, 4, 5]); + setSelectedMonthDays([1, 15]); }; // 处理关闭 @@ -105,10 +112,10 @@ export const CreateGoalModal: React.FC = ({ priority, hasReminder, reminderTime: hasReminder ? reminderTime : undefined, - reminderSettings: hasReminder ? { - enabled: true, - weekdays: [1, 2, 3, 4, 5, 6, 0], // 默认每天 - } : undefined, + customRepeatRule: { + weekdays: repeatType === 'weekly' ? selectedWeekdays : [1, 2, 3, 4, 5, 6, 0], // 根据重复类型设置周几 + dayOfMonth: repeatType === 'monthly' ? selectedMonthDays : undefined, // 根据重复类型设置月几 + }, startTime, }; @@ -225,13 +232,25 @@ export const CreateGoalModal: React.FC = ({ setShowRepeatTypePicker(true)}> - 🔄 + - 目标重复周期 + 重复周期 - {REPEAT_TYPE_OPTIONS.find(opt => opt.value === repeatType)?.label} + {repeatType === 'weekly' && selectedWeekdays.length > 0 + ? selectedWeekdays.length <= 3 + ? `${REPEAT_TYPE_OPTIONS.find(opt => opt.value === repeatType)?.label} ${selectedWeekdays.map(day => ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][day]).join(' ')}` + : `${REPEAT_TYPE_OPTIONS.find(opt => opt.value === repeatType)?.label} ${selectedWeekdays.slice(0, 2).map(day => ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][day]).join(' ')}等${selectedWeekdays.length}天` + : repeatType === 'monthly' && selectedMonthDays.length > 0 + ? selectedMonthDays.length <= 3 + ? `${REPEAT_TYPE_OPTIONS.find(opt => opt.value === repeatType)?.label} ${selectedMonthDays.map(day => `${day}号`).join(' ')}` + : `${REPEAT_TYPE_OPTIONS.find(opt => opt.value === repeatType)?.label} ${selectedMonthDays.slice(0, 2).map(day => `${day}号`).join(' ')}等${selectedMonthDays.length}天` + : REPEAT_TYPE_OPTIONS.find(opt => opt.value === repeatType)?.label + } › @@ -252,34 +271,117 @@ export const CreateGoalModal: React.FC = ({ activeOpacity={1} onPress={() => setShowRepeatTypePicker(false)} /> - - - opt.value === repeatType)} - items={REPEAT_TYPE_OPTIONS.map(opt => ({ label: opt.label, value: opt.value }))} - onChange={({ item }) => setRepeatType(item.value)} - backgroundColor={colorTokens.card} - haptics - /> + + {/* 关闭按钮 */} + setShowRepeatTypePicker(false)} + > + × + + + {/* 标题 */} + 目标重复周期 + + {/* 重复类型选择 */} + + {REPEAT_TYPE_OPTIONS.map((option) => ( + setRepeatType(option.value)} + > + + {option.label} + + + ))} - {Platform.OS === 'ios' && ( - - setShowRepeatTypePicker(false)} - > - 取消 - - setShowRepeatTypePicker(false)} - > - 确定 - + + {/* 周几选择 - 仅在选择每周时显示 */} + {repeatType === 'weekly' && ( + + + {[ + { value: 0, label: '周日' }, + { value: 1, label: '周一' }, + { value: 2, label: '周二' }, + { value: 3, label: '周三' }, + { value: 4, label: '周四' }, + { value: 5, label: '周五' }, + { value: 6, label: '周六' }, + ].map((weekday) => ( + { + if (selectedWeekdays.includes(weekday.value)) { + setSelectedWeekdays(selectedWeekdays.filter(day => day !== weekday.value)); + } else { + setSelectedWeekdays([...selectedWeekdays, weekday.value]); + } + }} + > + + {weekday.label} + + + ))} + )} + + {/* 每月日期选择 - 仅在选择每月时显示 */} + {repeatType === 'monthly' && ( + + + {Array.from({ length: 31 }, (_, i) => i + 1).map((day) => ( + { + if (selectedMonthDays.includes(day)) { + setSelectedMonthDays(selectedMonthDays.filter(d => d !== day)); + } else { + setSelectedMonthDays([...selectedMonthDays, day]); + } + }} + activeOpacity={0.8} + > + + {day} + + + ))} + + + )} + + {/* 完成按钮 */} + setShowRepeatTypePicker(false)} + > + 完成 + @@ -289,7 +391,10 @@ export const CreateGoalModal: React.FC = ({ - 📊 + 频率 @@ -352,7 +457,10 @@ export const CreateGoalModal: React.FC = ({ - 🔔 + 提醒 @@ -370,7 +478,10 @@ export const CreateGoalModal: React.FC = ({ - + 时间 @@ -577,6 +688,11 @@ const styles = StyleSheet.create({ optionIconText: { fontSize: 16, }, + optionIconImage: { + width: 20, + height: 20, + resizeMode: 'contain', + }, optionLabel: { flex: 1, fontSize: 16, @@ -655,6 +771,146 @@ const styles = StyleSheet.create({ color: '#FFFFFF', fontWeight: '700', }, + // 重复类型选择器弹窗样式 + repeatTypeModalSheet: { + position: 'absolute', + left: 20, + right: 20, + top: '50%', + transform: [{ translateY: -300 }], + backgroundColor: '#FFFFFF', + borderRadius: 16, + padding: 24, + alignItems: 'center', + maxHeight: 500, + }, + modalCloseButton: { + position: 'absolute', + top: 16, + left: 16, + width: 24, + height: 24, + alignItems: 'center', + justifyContent: 'center', + }, + modalCloseButtonText: { + fontSize: 20, + color: '#666666', + fontWeight: '300', + }, + repeatTypeModalTitle: { + fontSize: 18, + fontWeight: '600', + color: '#333333', + marginBottom: 20, + textAlign: 'center', + }, + repeatTypeOptions: { + flexDirection: 'row', + flexWrap: 'wrap', + justifyContent: 'center', + gap: 8, + marginBottom: 20, + }, + repeatTypeButton: { + paddingHorizontal: 16, + paddingVertical: 10, + borderRadius: 20, + backgroundColor: '#F5F5F5', + borderWidth: 1, + borderColor: '#E5E5E5', + marginHorizontal: 4, + }, + repeatTypeButtonSelected: { + backgroundColor: '#E6E6FA', + borderColor: '#8A2BE2', + }, + repeatTypeButtonText: { + fontSize: 14, + color: '#666666', + fontWeight: '500', + }, + repeatTypeButtonTextSelected: { + color: '#8A2BE2', + fontWeight: '600', + }, + weekdaySelection: { + width: '100%', + marginBottom: 20, + }, + weekdayOptions: { + flexDirection: 'row', + flexWrap: 'wrap', + justifyContent: 'center', + gap: 6, + }, + weekdayButton: { + paddingHorizontal: 12, + paddingVertical: 8, + borderRadius: 16, + backgroundColor: '#F5F5F5', + borderWidth: 1, + borderColor: '#E5E5E5', + marginHorizontal: 2, + }, + weekdayButtonSelected: { + backgroundColor: '#8A2BE2', + borderColor: '#8A2BE2', + }, + weekdayButtonText: { + fontSize: 12, + color: '#666666', + fontWeight: '500', + }, + weekdayButtonTextSelected: { + color: '#FFFFFF', + fontWeight: '600', + }, + // 每月日期选择样式 - 日历网格布局 + monthDaySelection: { + width: '100%', + marginBottom: 20, + }, + monthDayGrid: { + flexDirection: 'row', + flexWrap: 'wrap', + justifyContent: 'flex-start', + paddingHorizontal: 8, + }, + monthDayGridItem: { + width: 36, + height: 36, + borderRadius: 18, + backgroundColor: '#F5F5F5', + alignItems: 'center', + justifyContent: 'center', + marginBottom: 10, + marginRight: 8, + }, + monthDayGridItemSelected: { + backgroundColor: '#8A2BE2', + }, + monthDayGridText: { + fontSize: 12, + fontWeight: '600', + color: '#666666', + }, + monthDayGridTextSelected: { + color: '#FFFFFF', + }, + repeatTypeCompleteButton: { + width: '100%', + backgroundColor: '#8A2BE2', + borderRadius: 20, + paddingVertical: 14, + alignItems: 'center', + marginTop: 10, + }, + repeatTypeCompleteButtonText: { + color: '#FFFFFF', + fontSize: 16, + fontWeight: '600', + }, }); export default CreateGoalModal; \ No newline at end of file diff --git a/types/goals.ts b/types/goals.ts index 3fbcb23..e241f97 100644 --- a/types/goals.ts +++ b/types/goals.ts @@ -1,6 +1,6 @@ // 目标管理相关类型定义 -export type RepeatType = 'daily' | 'weekly' | 'monthly' | 'custom'; +export type RepeatType = 'daily' | 'weekly' | 'monthly'; export type GoalStatus = 'active' | 'paused' | 'completed' | 'cancelled'; @@ -8,16 +8,15 @@ export type GoalPriority = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10; // 自定义重复规则 export interface CustomRepeatRule { - type: 'weekly' | 'monthly'; weekdays?: number[]; // 0-6,0为周日 - monthDays?: number[]; // 1-31 - interval?: number; // 间隔周数或月数 + dayOfMonth?: number[]; // 1-31 } // 提醒设置 export interface ReminderSettings { enabled: boolean; weekdays?: number[]; // 0-6,0为周日 + monthDays?: number[]; // 1-31,每月几号 sound?: string; vibration?: boolean; }