Files
todos/App/Sources/Views/TaskGroupListView.swift
T
javier dd6f453466 App layout improvements (#10)
This PR contains the work done to improve the app layout for max iPhones and iPads by levering on the navigation split view. Plus, the floating button to add todo tasks was improved and integrated better into the layout and a critical bug occurring on max iPhones and iPads was fixed.

Reviewed-on: rock-n-code/todos-app#10
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>
2026-02-12 03:55:17 +00:00

110 lines
3.1 KiB
Swift

import SwiftData
import SwiftUI
/// A view that displays todo tasks grouped by date and completion categories.
///
/// This view serves as the main interface for browsing tasks organized into four groups:
/// - **Today**: Tasks due today that are not yet completed
/// - **Upcoming**: Tasks due in the future that are not yet completed
/// - **Overdue**: Tasks due in the past that are not yet completed
/// - **Completed**: Tasks that have been marked as done
struct TaskGroupListView: View {
// MARK: Properties
/// Binding to the currently selected todo task group.
///
/// When provided, the view will use this binding for navigation split view selection.
@Binding
private var group: TodoGroup?
/// Query to monitor all todo tasks for changes.
///
/// This query triggers view updates whenever todo tasks are inserted, updated, or deleted,
/// ensuring the task counts displayed in the view remain accurate.
@Query
private var todos: [Todo]
/// The view model managing the state and logic for this view.
///
/// Handles task counting and provides access to all task groups.
/// Initialized with the default calendar for date calculations.
@State
private var viewModel = ViewModel()
// MARK: Initializers
/// Creates a task group list view with a binding to the selected group.
///
/// This initializer configures the view for use in a navigation split view,
/// where the binding tracks which task group is currently selected in the sidebar.
///
/// - Parameter group: A binding to the currently selected task group.
init(_ group: Binding<TodoGroup?>) {
self._group = group
}
// MARK: Body
/// The content and behavior of the view.
///
/// Displays a scrollable vertical list of task group cards. Each card shows:
/// - The group's icon in its associated color
/// - The group's title
/// - The current count of tasks in that group
///
/// Cards are tappable and update the selected group binding for navigation split view.
/// Task counts are fetched on-demand from the model context for each render.
var body: some View {
List(
viewModel.groups,
selection: $group
) { group in
Card(
group: group,
count: viewModel.count(
todos,
for: group
)
)
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
.tag(group)
}
.listStyle(.plain)
.navigationTitle("view.task-group-list.navigation.title")
.sensoryFeedback(
.selection,
trigger: group
)
}
}
// MARK: - Previews
#Preview(
"Task group list with empty tasks",
traits: .emptyContainer
) {
@Previewable
@State
var group: TodoGroup?
NavigationStack {
TaskGroupListView($group)
}
}
#Preview(
"Task group list with sample tasks",
traits: .sampleTasks
) {
@Previewable
@State
var group: TodoGroup?
NavigationStack {
TaskGroupListView($group)
}
}