filters.go

  1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2//
  3// SPDX-License-Identifier: AGPL-3.0-or-later
  4
  5package tasks
  6
  7import (
  8	"time"
  9
 10	"git.secluded.site/go-lunatask"
 11)
 12
 13// FilterFunc filters a slice of tasks.
 14type FilterFunc func([]lunatask.Task) []lunatask.Task
 15
 16// FilterToday returns tasks scheduled for today.
 17func FilterToday(tasks []lunatask.Task) []lunatask.Task {
 18	today := lunatask.Today()
 19	result := make([]lunatask.Task, 0)
 20
 21	for _, task := range tasks {
 22		if task.ScheduledOn != nil && sameDay(task.ScheduledOn.Time, today.Time) {
 23			result = append(result, task)
 24		}
 25	}
 26
 27	return result
 28}
 29
 30// FilterOverdue returns tasks scheduled before today that are not completed.
 31func FilterOverdue(tasks []lunatask.Task) []lunatask.Task {
 32	today := lunatask.Today()
 33	result := make([]lunatask.Task, 0)
 34
 35	for _, task := range tasks {
 36		if task.ScheduledOn == nil {
 37			continue
 38		}
 39
 40		if task.ScheduledOn.Before(today.Time) && !isCompleted(&task) {
 41			result = append(result, task)
 42		}
 43	}
 44
 45	return result
 46}
 47
 48// Next7DaysWindow is the number of days to look ahead for the next 7 days filter.
 49const Next7DaysWindow = 7
 50
 51// FilterNext7Days returns tasks scheduled within the next 7 days.
 52func FilterNext7Days(tasks []lunatask.Task) []lunatask.Task {
 53	today := lunatask.Today()
 54	weekFromNow := lunatask.NewDate(time.Now().AddDate(0, 0, Next7DaysWindow))
 55	result := make([]lunatask.Task, 0)
 56
 57	for _, task := range tasks {
 58		if task.ScheduledOn == nil {
 59			continue
 60		}
 61
 62		// Include today through 7 days from now
 63		if !task.ScheduledOn.Before(today.Time) && !task.ScheduledOn.After(weekFromNow.Time) {
 64			result = append(result, task)
 65		}
 66	}
 67
 68	return result
 69}
 70
 71// FilterHighPriority returns tasks with highest priority.
 72func FilterHighPriority(tasks []lunatask.Task) []lunatask.Task {
 73	result := make([]lunatask.Task, 0)
 74
 75	for _, task := range tasks {
 76		if task.Priority != nil && *task.Priority == lunatask.PriorityHighest {
 77			result = append(result, task)
 78		}
 79	}
 80
 81	return result
 82}
 83
 84// FilterNow returns tasks that need attention now.
 85// Matches tasks where ANY of:
 86// - Status = in-progress
 87// - Priority = highest
 88// - Motivation = "must"
 89// - Eisenhower = urgent AND important.
 90func FilterNow(tasks []lunatask.Task) []lunatask.Task {
 91	result := make([]lunatask.Task, 0)
 92
 93	for _, task := range tasks {
 94		if isNow(&task) {
 95			result = append(result, task)
 96		}
 97	}
 98
 99	return result
100}
101
102//nolint:cyclop // Multiple independent conditions are inherently complex.
103func isNow(task *lunatask.Task) bool {
104	// Exclude completed tasks
105	if isCompleted(task) {
106		return false
107	}
108
109	// Status = in-progress
110	if task.Status != nil && *task.Status == lunatask.StatusInProgress {
111		return true
112	}
113
114	// Priority = highest
115	if task.Priority != nil && *task.Priority == lunatask.PriorityHighest {
116		return true
117	}
118
119	// Motivation = must
120	if task.Motivation != nil && *task.Motivation == lunatask.MotivationMust {
121		return true
122	}
123
124	// Eisenhower = urgent AND important
125	if task.Eisenhower != nil && task.Eisenhower.IsUrgent() && task.Eisenhower.IsImportant() {
126		return true
127	}
128
129	return false
130}
131
132// RecentCompletionsWindow is the time window for recent completions.
133const RecentCompletionsWindow = 72 * time.Hour
134
135// FilterRecentCompletions returns tasks completed in the last 72 hours.
136func FilterRecentCompletions(tasks []lunatask.Task) []lunatask.Task {
137	cutoff := time.Now().Add(-RecentCompletionsWindow)
138	result := make([]lunatask.Task, 0)
139
140	for _, task := range tasks {
141		if task.CompletedAt != nil && task.CompletedAt.After(cutoff) {
142			result = append(result, task)
143		}
144	}
145
146	return result
147}
148
149// FilterByArea returns tasks in a specific area.
150func FilterByArea(tasks []lunatask.Task, areaID string) []lunatask.Task {
151	result := make([]lunatask.Task, 0)
152
153	for _, task := range tasks {
154		if task.AreaID != nil && *task.AreaID == areaID {
155			result = append(result, task)
156		}
157	}
158
159	return result
160}
161
162func isCompleted(task *lunatask.Task) bool {
163	return task.Status != nil && *task.Status == lunatask.StatusCompleted
164}
165
166func sameDay(a, b time.Time) bool {
167	y1, m1, d1 := a.Date()
168	y2, m2, d2 := b.Date()
169
170	return y1 == y2 && m1 == m2 && d1 == d2
171}