import SwiftUI import SwiftData /// 自由周期提醒的创建 / 编辑表单。 /// `reminder == nil` 为新建;否则为编辑(多一个删除按钮)。 /// 本地 @State 暂存,保存时才写 SwiftData + 调度通知;取消即丢弃。 struct CustomReminderEditSheet: View { @Environment(\.modelContext) private var ctx @Environment(\.dismiss) private var dismiss /// nil = 新建模式。 let reminder: CustomReminder? @State private var title = "" @State private var note = "" @State private var pickedTime: Date = .now @State private var weekdays: Set = Set(1...7) @State private var hydrated = false @State private var showAuthDeniedAlert = false init(reminder: CustomReminder? = nil) { self.reminder = reminder } private var isEditing: Bool { reminder != nil } private var trimmedTitle: String { title.trimmingCharacters(in: .whitespacesAndNewlines) } private var canSave: Bool { !trimmedTitle.isEmpty && !weekdays.isEmpty } var body: some View { NavigationStack { Form { Section { TextField(String(appLoc: "做点什么?例:跑步5公里 / 吃2片护肝片"), text: $title, axis: .vertical) .lineLimit(1...3) TextField(String(appLoc: "备注(可选)"), text: $note, axis: .vertical) .lineLimit(1...3) .foregroundStyle(Tj.Palette.text2) } Section { DatePicker(String(appLoc: "时间"), selection: $pickedTime, displayedComponents: .hourAndMinute) } Section { weekdayRow } header: { Text("重复") } if isEditing { Section { Button(role: .destructive) { deleteReminder() } label: { Label(String(appLoc: "删除提醒"), systemImage: "trash") } } } } .scrollContentBackground(.hidden) .background(Tj.Palette.sand.ignoresSafeArea()) .navigationTitle(isEditing ? String(appLoc: "编辑提醒") : String(appLoc: "新建提醒")) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .topBarLeading) { Button(String(appLoc: "取消")) { dismiss() } } ToolbarItem(placement: .topBarTrailing) { Button(String(appLoc: "保存")) { save() } .fontWeight(.semibold) .disabled(!canSave) } } .onAppear(perform: hydrate) .alert(String(appLoc: "通知未开启"), isPresented: $showAuthDeniedAlert) { Button(String(appLoc: "好")) { dismiss() } } message: { Text("提醒已保存,但系统通知权限未开启,到点不会弹出。请在「设置 · 通知 · 康康」中允许。") } } } // MARK: - 周几选择(与 RemindersListView 同款) private var weekdayRow: some View { let names = [ String(appLoc: "一"), String(appLoc: "二"), String(appLoc: "三"), String(appLoc: "四"), String(appLoc: "五"), String(appLoc: "六"), String(appLoc: "日"), ] let values = [2, 3, 4, 5, 6, 7, 1] return HStack(spacing: 6) { ForEach(Array(values.enumerated()), id: \.offset) { idx, w in let on = weekdays.contains(w) Button { if on { weekdays.remove(w) } else { weekdays.insert(w) } } label: { Text(names[idx]) .font(.system(size: 13, weight: on ? .semibold : .regular)) .foregroundStyle(on ? Tj.Palette.paper : Tj.Palette.text) .frame(maxWidth: .infinity, minHeight: 30) .background( RoundedRectangle(cornerRadius: 8, style: .continuous) .fill(on ? Tj.Palette.ink : Tj.Palette.paper) ) .overlay( RoundedRectangle(cornerRadius: 8, style: .continuous) .strokeBorder(Tj.Palette.line, lineWidth: on ? 0 : 1) ) } .buttonStyle(.plain) } } .listRowBackground(Color.clear) } // MARK: - 数据 private func hydrate() { guard !hydrated else { return } hydrated = true if let r = reminder { title = r.title note = r.note weekdays = Set(r.weekdays) pickedTime = Calendar.current.date( bySettingHour: r.hour, minute: r.minute, second: 0, of: .now ) ?? .now } } private func save() { guard canSave else { return } let cal = Calendar.current let hour = cal.component(.hour, from: pickedTime) let minute = cal.component(.minute, from: pickedTime) let sortedDays = weekdays.sorted() let target: CustomReminder if let r = reminder { r.title = trimmedTitle r.note = note.trimmingCharacters(in: .whitespacesAndNewlines) r.hour = hour r.minute = minute r.weekdays = sortedDays r.updatedAt = .now target = r } else { let new = CustomReminder( title: trimmedTitle, note: note.trimmingCharacters(in: .whitespacesAndNewlines), hour: hour, minute: minute, weekdays: sortedDays ) ctx.insert(new) target = new } try? ctx.save() Task { @MainActor in let state = await ReminderService.requestAuthorization() await ReminderService.sync(target) if state == .denied { showAuthDeniedAlert = true } else { dismiss() } } } private func deleteReminder() { guard let r = reminder else { return } ReminderService.cancel(customId: r.id) ctx.delete(r) try? ctx.save() dismiss() } } #Preview("新建") { CustomReminderEditSheet() .modelContainer(for: [CustomReminder.self], inMemory: true) }