Files
KisaniCal/KisaniCal/Views/TaskContextMenu.swift
kutesir d0d982f4f5 Add unified task menu, Live Activity, and calendar event actions
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>
2026-06-06 19:29:25 +03:00

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")
}
}
}