Task context menu (new shared TaskMenuItems) consistent across Today, Matrix, and Calendar: Pin · Date · Move · Priority · Tags · Add to Live Activity · Delete. Adds TaskViewModel.setPriority. Live Activity (ActivityKit): - TaskActivityAttributes shared between app and widget targets - LiveActivityManager (start/update/end/toggle, iOS 16.1+) - TaskLiveActivity widget: lock-screen banner + Dynamic Island - NSSupportsLiveActivities via project.yml; project regenerated Calendar events (non-subscription, writable only): - Edit via system EKEventEditViewController (EventEditView wrapper) - Delete via new CalendarStore.deleteEvent Also sweeps in prior in-progress edits already present in the working tree (AuthManager, NotificationManager, TaskItem, task views) and the updated ISSUES.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
81 lines
3.2 KiB
Swift
81 lines
3.2 KiB
Swift
import SwiftUI
|
|
|
|
/// The unified long-press menu for a task, shared across Today, Matrix, and Calendar.
|
|
/// Pass only the closures a given screen needs; the rest default to no-ops.
|
|
struct TaskMenuItems: View {
|
|
let task: TaskItem
|
|
/// The quadrant the row currently lives in (so "Move" hides the current one).
|
|
var currentQuadrant: Quadrant? = nil
|
|
|
|
var onPin: (TaskItem) -> Void = { _ in }
|
|
var onSetDate: (TaskItem, Date?) -> Void = { _, _ in }
|
|
var onMove: (TaskItem, Quadrant) -> Void = { _, _ in }
|
|
var onSetPriority: (TaskItem, Priority) -> Void = { _, _ in }
|
|
var onSetCategory: (TaskItem, TaskCategory) -> Void = { _, _ in }
|
|
var onLiveActivity:(TaskItem) -> Void = { LiveActivityManager.toggle(for: $0) }
|
|
var onEdit: ((TaskItem) -> Void)? = nil
|
|
var onDelete: (TaskItem) -> Void = { _ in }
|
|
|
|
private var cal: Calendar { .current }
|
|
|
|
var body: some View {
|
|
Button { onPin(task) } label: {
|
|
Label(task.isPinned ? "Unpin" : "Pin", systemImage: task.isPinned ? "pin.slash" : "pin")
|
|
}
|
|
|
|
Menu {
|
|
Button { onSetDate(task, cal.startOfDay(for: Date())) } label: {
|
|
Label("Today", systemImage: "sun.max")
|
|
}
|
|
Button {
|
|
let d = cal.date(byAdding: .day, value: 1, to: Date())!
|
|
onSetDate(task, cal.startOfDay(for: d))
|
|
} label: { Label("Tomorrow", systemImage: "sunrise") }
|
|
Button {
|
|
let d = cal.date(byAdding: .weekOfYear, value: 1, to: Date())!
|
|
onSetDate(task, cal.startOfDay(for: d))
|
|
} label: { Label("Next Week", systemImage: "calendar") }
|
|
Divider()
|
|
Button { onSetDate(task, nil) } label: {
|
|
Label("Remove Date", systemImage: "xmark.circle")
|
|
}
|
|
} label: { Label("Date", systemImage: "calendar.badge.clock") }
|
|
|
|
Menu {
|
|
ForEach(Quadrant.allCases.filter { $0 != (currentQuadrant ?? task.quadrant) }) { q in
|
|
Button { onMove(task, q) } label: { Text(q.rawValue) }
|
|
}
|
|
} label: { Label("Move", systemImage: "arrow.right.square") }
|
|
|
|
Menu {
|
|
ForEach(Priority.allCases) { p in
|
|
Button { onSetPriority(task, p) } label: {
|
|
Label(p.label, systemImage: task.priority == p ? "checkmark" : "flag")
|
|
}
|
|
}
|
|
} label: { Label("Priority", systemImage: "flag") }
|
|
|
|
Menu {
|
|
ForEach([TaskCategory.reminder, .birthday, .domain, .annual, .custom], id: \.rawValue) { cat in
|
|
Button { onSetCategory(task, cat) } label: {
|
|
Label(cat.rawValue, systemImage: task.category == cat ? "checkmark" : "tag")
|
|
}
|
|
}
|
|
} label: { Label("Tags", systemImage: "tag") }
|
|
|
|
Button { onLiveActivity(task) } label: {
|
|
Label("Add to Live Activity", systemImage: "pin.circle")
|
|
}
|
|
|
|
if let onEdit {
|
|
Button { onEdit(task) } label: { Label("Edit", systemImage: "pencil") }
|
|
}
|
|
|
|
Divider()
|
|
|
|
Button(role: .destructive) { onDelete(task) } label: {
|
|
Label("Delete", systemImage: "trash")
|
|
}
|
|
}
|
|
}
|