filter.go

 1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4
 5package lunatask
 6
 7import "time"
 8
 9// TaskFilterOptions configures task list filtering.
10type TaskFilterOptions struct {
11	AreaID           *string
12	GoalID           *string
13	Status           *TaskStatus
14	IncludeCompleted bool      // If false, excludes completed tasks older than Today
15	Today            time.Time // Reference date for "old completed" check
16}
17
18// FilterTasks returns tasks matching the given filter options.
19// If opts is nil, returns all tasks unchanged.
20func FilterTasks(tasks []Task, opts *TaskFilterOptions) []Task {
21	if opts == nil {
22		return tasks
23	}
24
25	filtered := make([]Task, 0, len(tasks))
26
27	for _, task := range tasks {
28		if matchesFilter(task, opts) {
29			filtered = append(filtered, task)
30		}
31	}
32
33	return filtered
34}
35
36func matchesFilter(task Task, opts *TaskFilterOptions) bool {
37	if !matchesAreaFilter(task, opts.AreaID) {
38		return false
39	}
40
41	if !matchesGoalFilter(task, opts.GoalID) {
42		return false
43	}
44
45	if !matchesStatusFilter(task, opts.Status) {
46		return false
47	}
48
49	if !opts.IncludeCompleted && opts.Status == nil && IsOldCompleted(task, opts.Today) {
50		return false
51	}
52
53	return true
54}
55
56func matchesAreaFilter(task Task, areaID *string) bool {
57	if areaID == nil {
58		return true
59	}
60
61	return task.AreaID != nil && *task.AreaID == *areaID
62}
63
64func matchesGoalFilter(task Task, goalID *string) bool {
65	if goalID == nil {
66		return true
67	}
68
69	return task.GoalID != nil && *task.GoalID == *goalID
70}
71
72func matchesStatusFilter(task Task, status *TaskStatus) bool {
73	if status == nil {
74		return true
75	}
76
77	return task.Status != nil && *task.Status == *status
78}
79
80// IsOldCompleted returns true if the task was completed before the given date.
81// Returns false for non-completed tasks or tasks with no CompletedAt timestamp.
82func IsOldCompleted(task Task, today time.Time) bool {
83	if task.Status == nil || *task.Status != StatusCompleted {
84		return false
85	}
86
87	return task.CompletedAt == nil || task.CompletedAt.Before(today)
88}