feat: floating tab bar, NLP date parsing, and task date picker
- Tab bar: TickTick-style floating pill (cornerRadius 28, shadow, systemGray5 active highlight) - NLP: month+day parsing (8th June, June 8), recurrence (every year/week/etc), intent stripping (remind me of) - Recurrence chip in add-task toolbar; isRecurring saved with task - Date chip defaults to Today on new tasks; tapping opens full date picker - Date picker: calendar grid, inline time wheel, Repeat menu (Date tab) - Duration tab: Start/End column selector, live duration counter, All Day toggle - TaskItem: added endDate and isAllDay fields - Fixed hidden Unicode character corrupting + operator in TodayView Co-Authored-By: Kutesir <tqwyy79vzn@privaterelay.appleid.com>
This commit is contained in:
@@ -12,6 +12,9 @@ struct TaskItem: Identifiable, Codable, Equatable {
|
||||
var category: TaskCategory = .reminder
|
||||
var taskColor: TaskColor = .orange
|
||||
var isRecurring: Bool = false
|
||||
var isPinned: Bool = false
|
||||
var endDate: Date? = nil
|
||||
var isAllDay: Bool = false
|
||||
}
|
||||
|
||||
enum Quadrant: String, CaseIterable, Identifiable, Codable {
|
||||
@@ -84,12 +87,26 @@ class TaskViewModel: ObservableObject {
|
||||
.sorted { ($0.dueDate ?? .distantFuture) < ($1.dueDate ?? .distantFuture) }
|
||||
}
|
||||
var upcomingTasks: [TaskItem] {
|
||||
let tomorrow = Calendar.current.date(byAdding: .day, value: 1,
|
||||
to: Calendar.current.startOfDay(for: Date()))!
|
||||
let cal = Calendar.current
|
||||
let fourDays = cal.date(byAdding: .day, value: 4, to: cal.startOfDay(for: Date()))!
|
||||
return tasks
|
||||
.filter { !$0.isComplete && ($0.dueDate ?? .distantFuture) >= tomorrow }
|
||||
.filter { !$0.isComplete && ($0.dueDate ?? .distantFuture) >= fourDays }
|
||||
.sorted { ($0.dueDate ?? .distantFuture) < ($1.dueDate ?? .distantFuture) }
|
||||
}
|
||||
var next3DaysTasks: [(date: Date, tasks: [TaskItem])] {
|
||||
let cal = Calendar.current
|
||||
let today = cal.startOfDay(for: Date())
|
||||
return (1...3).compactMap { offset -> (Date, [TaskItem])? in
|
||||
guard let day = cal.date(byAdding: .day, value: offset, to: today),
|
||||
let nextDay = cal.date(byAdding: .day, value: 1, to: day) else { return nil }
|
||||
let dayTasks = tasks.filter {
|
||||
!$0.isComplete &&
|
||||
($0.dueDate ?? .distantFuture) >= day &&
|
||||
($0.dueDate ?? .distantFuture) < nextDay
|
||||
}.sorted { ($0.dueDate ?? .distantFuture) < ($1.dueDate ?? .distantFuture) }
|
||||
return dayTasks.isEmpty ? nil : (day, dayTasks)
|
||||
}
|
||||
}
|
||||
var completedTodayTasks: [TaskItem] {
|
||||
let startOfDay = Calendar.current.startOfDay(for: Date())
|
||||
return tasks
|
||||
@@ -104,15 +121,42 @@ class TaskViewModel: ObservableObject {
|
||||
save()
|
||||
}
|
||||
func tasks(for quadrant: Quadrant) -> [TaskItem] {
|
||||
tasks.filter { $0.quadrant == quadrant }
|
||||
tasks
|
||||
.filter { $0.quadrant == quadrant }
|
||||
.sorted { $0.isPinned && !$1.isPinned }
|
||||
}
|
||||
|
||||
func pin(_ task: TaskItem) {
|
||||
guard let idx = tasks.firstIndex(where: { $0.id == task.id }) else { return }
|
||||
tasks[idx].isPinned.toggle()
|
||||
save()
|
||||
}
|
||||
|
||||
func setDate(_ task: TaskItem, date: Date?) {
|
||||
guard let idx = tasks.firstIndex(where: { $0.id == task.id }) else { return }
|
||||
tasks[idx].dueDate = date
|
||||
save()
|
||||
}
|
||||
|
||||
func setCategory(_ task: TaskItem, category: TaskCategory) {
|
||||
guard let idx = tasks.firstIndex(where: { $0.id == task.id }) else { return }
|
||||
tasks[idx].category = category
|
||||
save()
|
||||
}
|
||||
func moveToQuadrant(taskID: UUID, quadrant: Quadrant) {
|
||||
guard let idx = tasks.firstIndex(where: { $0.id == taskID }) else { return }
|
||||
tasks[idx].quadrant = quadrant
|
||||
save()
|
||||
}
|
||||
|
||||
func addTask(title: String, dueDate: Date?, hasTime: Bool = false,
|
||||
quadrant: Quadrant = .urgent, category: TaskCategory = .reminder,
|
||||
taskColor: TaskColor = .orange, isRecurring: Bool = false) {
|
||||
taskColor: TaskColor = .orange, isRecurring: Bool = false,
|
||||
endDate: Date? = nil, isAllDay: Bool = false) {
|
||||
tasks.append(TaskItem(title: title, dueDate: dueDate, hasTime: hasTime,
|
||||
quadrant: quadrant, category: category,
|
||||
taskColor: taskColor, isRecurring: isRecurring))
|
||||
taskColor: taskColor, isRecurring: isRecurring,
|
||||
endDate: endDate, isAllDay: isAllDay))
|
||||
save()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user