import SwiftData import SwiftUI extension TaskGroupListView { /// View model for managing the logic for the task group list view. /// /// This observable class encapsulates the state and business logic for the task group list view. /// It follows the MVVM pattern to separate presentation logic from the view layer. /// /// ## Responsibilities /// - Providing access to all task groups for iteration /// - Efficiently counting tasks per group using SwiftData fetch descriptors /// - Managing date calculations for group categorization @Observable final class ViewModel { // MARK: Properties /// The calendar used for date calculations. /// /// This calendar is used to determine day boundaries for categorizing tasks into date groups: today, upcoming, overdue. /// Defaults to the current calendar. private let calendar: Calendar // MARK: Initialization /// Initializes a new view model instance. /// /// - Parameter calendar: The calendar to use for date calculations. Defaults to `.current`. init(calendar: Calendar = .current) { self.calendar = calendar } // MARK: Computed /// Returns all available task groups in an predetermined order. /// /// This computed property provides access to all task group cases for iteration in the view. /// /// - Returns: An array of all `TodoGroup` cases in a predetermined order. var groups: [TodoGroup] { TodoGroup.allCases } // MARK: Functions /// Calculates the number of tasks for a given task group from an in-memory collection. /// /// This method filters the provided tasks array to count only those tasks that belong /// to the specified group based on their due date and completion status. Tasks are /// categorized as follows: /// /// - **Completed**: Tasks with a non-nil `completed` date /// - **Overdue**: Incomplete tasks due before today /// - **Today**: Incomplete tasks due today (from start of day to end of day) /// - **Upcoming**: Incomplete tasks due tomorrow or later /// /// - Parameters: /// - tasks: The array of tasks to filter and count. /// - group: The task group to count tasks for. /// - Returns: The number of tasks in the specified group. func count( _ tasks: [Todo], for group: TodoGroup ) -> Int { let today = calendar.startOfDay(for: .now) let tomorrow = calendar.date(byAdding: .day, value: 1, to: today) ?? .now return tasks .filter { task in switch group { case .completed: task.completed != nil case .overdue: task.completed == nil && task.due < today case .today: task.completed == nil && task.due >= today && task.due < tomorrow case .upcoming: task.completed == nil && task.due >= tomorrow } } .count } } }