import SwiftData import SwiftUI extension TaskListView { /// Internal content view that manages the dynamic SwiftData query for tasks. /// /// This view is responsible for querying and displaying the list of tasks based on the specified /// group and completion status filter. It exists as a separate view to enable dynamic query /// updates when filter parameters change. /// /// Task reordering is enabled based on the ``TodoGroup/canReorder`` property. /// Groups that support reordering (``TodoGroup/today``, ``TodoGroup/upcoming``, /// ``TodoGroup/overdue``) allow users to drag and drop tasks to change their order. /// The ``TodoGroup/completed`` group does not support reordering as tasks are /// displayed in chronological order by completion date. struct Content: View { // MARK: Type aliases /// Closure type for handling task reorder operations. /// /// - Parameters: /// - tasks: The current array of tasks. /// - source: The index set of items being moved. /// - destination: The destination index for the moved items. typealias ReorderClosure = ([Todo], IndexSet, Int) -> Void // MARK: Properties /// Query to fetch todos filtered by group and completion status. /// /// This query is initialized with a todo fetch descriptor that applies predicates /// based on the group type and completion filter. SwiftData automatically /// monitors changes and updates the view when the underlying data changes. /// /// Tasks are sorted by their `order` property first, then by date-based criteria /// specific to each group, enabling both manual and automatic ordering. @Query private var tasks: [Todo] /// Indicates whether tasks in this view can be reordered through drag and drop. /// /// This value is derived from the ``TodoGroup/canReorder`` property and /// determines whether the `.onMove` modifier is applied to the task list. private let canReorder: Bool /// Closure called when tasks are reordered through drag and drop. /// /// This closure is invoked by the `.onMove` modifier and is responsible for /// updating the `order` property of affected tasks to reflect their new positions. private let onReorder: ReorderClosure // MARK: Initializers /// Creates a content view with a configured task query and reorder handler. /// /// This initializer sets up a query with a fetch descriptor that filters /// tasks based on the specified group and completion status. When these parameters /// change, SwiftUI recreates the view with new values, causing the query to update. /// /// The reordering capability is automatically determined based on the /// ``TodoGroup/canReorder`` property. For groups that support reordering, /// the provided closure will be called when users drag and drop tasks to new positions. /// /// - Parameters: /// - group: The todo group category to filter by (today, upcoming, overdue, or completed). /// - showCompleted: Whether to include completed tasks in the results. Only applies to groups other than `.completed`. /// - onReorder: A closure called when tasks are reordered. init( group: TodoGroup, showCompleted: Bool, onReorder: @escaping ReorderClosure ) { self._tasks = .init( FetchDescriptor( group: group, showCompleted: showCompleted ) ) self.canReorder = group.canReorder self.onReorder = onReorder } // MARK: Body /// The content and behavior of the view. /// /// Displays either a content unavailable state or a list of tasks /// based on whether any tasks match the current filters. /// /// When tasks are present, displays them in a grouped list. The list supports /// drag and drop reordering for groups where `canReorder` is true, allowing /// users to manually prioritize tasks within the group. For groups where /// reordering is disabled (such as completed tasks), the list is displayed /// in read-only mode with chronological sorting. var body: some View { Group { if tasks.isEmpty { ContentUnavailableView( "view.task-list-content.content-unavailable.title", systemImage: "checkmark.circle" ) } else { List { if canReorder { ForEach(tasks) { TaskListView.Item($0) } .onMove { source, destination in onReorder(tasks, source, destination) } } else { ForEach(tasks) { TaskListView.Item($0) } } } .listStyle(.grouped) } } } } } // MARK: - Previews #Preview( "Task list content when there are no tasks", traits: .emptyContainer ) { TaskListView.Content( group: .today, showCompleted: .random() ) { _, _, _ in // On reorder closure } } #Preview( "Task list content when completed tasks not shown", traits: .sampleTasks ) { TaskListView.Content( group: .today, showCompleted: false ) { _, _, _ in // On reorder closure } } #Preview( "Task list content when completed tasks shown", traits: .sampleTasks ) { TaskListView.Content( group: .today, showCompleted: true ) { _, _, _ in // On reorder closure } } #Preview( "Task list content when only completed tasks shown", traits: .sampleTasks ) { TaskListView.Content( group: .completed, showCompleted: .random() ) { _, _, _ in // On reorder closure } }