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 todo task groups for iteration /// - Efficiently counting todo 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 the todo group cases in a predetermined order. var groups: [TodoGroup] { TodoGroup.allCases } // MARK: Functions /// Calculates the number of todo tasks for a given todo group from an in-memory collection. /// /// This method filters the provided todo tasks array to count only those todo tasks that belong /// to the specified group based on their due date and completion status. Todo tasks are /// categorized as follows: /// /// - **Completed**: Todo tasks with a non-nil `completed` date /// - **Overdue**: Incomplete todo tasks due before today /// - **Today**: Incomplete todo tasks due today (from start of day to end of day) /// - **Upcoming**: Incomplete todo tasks due tomorrow or later /// /// - Parameters: /// - todos: The array of todo tasks to filter and count. /// - group: The task group to count tasks for. /// - Returns: The number of tasks in the specified group. func count( _ todos: [Todo], for group: TodoGroup ) -> Int { let today = calendar.startOfDay(for: .now) let tomorrow = calendar.date(byAdding: .day, value: 1, to: today) ?? .now return todos .filter { todo in switch group { case .completed: todo.completed != nil case .overdue: todo.completed == nil && todo.due < today case .today: todo.completed == nil && todo.due >= today && todo.due < tomorrow case .upcoming: todo.completed == nil && todo.due >= tomorrow } } .count } } }