Files
todos/App/Sources/Views/TaskListView.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

127 lines
3.3 KiB
Swift

import SwiftData
import SwiftUI
/// A view that displays filtered todo tasks for a specific task group.
///
/// This view provides the presentation layer for displaying and managing tasks within a specific group category.
struct TaskListView: View {
// MARK: Properties
/// The SwiftData model context for performing data operations.
@Environment(\.modelContext)
private var modelContext
/// The view model managing the state and business logic for this view.
///
/// This view model holds the group configuration and completion filter state.
@State
private var viewModel: ViewModel
// MARK: Initialization
/// Creates a new task list view for a specific group.
///
/// Initializes the view with a view model configured for the specified group.
/// The view model manages the state for completion filtering and task reordering,
/// while the view handles the presentation layer including navigation and toolbar.
///
/// - Parameter group: The todo group category to display tasks for.
/// - Note: The group determines which tasks are fetched, whether
/// completion filtering is available, and whether drag and drop reordering is enabled.
init(group: TodoGroup) {
_viewModel = .init(initialValue: ViewModel(group: group))
}
// MARK: Body
/// The content and behavior of the view.
///
/// Displays the task list content with navigation title and toolbar controls.
/// The toolbar includes a completion filter toggle for groups that support it.
var body: some View {
Content(
group: viewModel.group,
showCompleted: viewModel.showCompleted
) { tasks, offsets in
viewModel.delete(
tasks,
at: offsets,
from: modelContext
)
} onReorder: { tasks, source, destination in
viewModel.reorderTasks(
tasks,
from: source,
to: destination
)
}
.navigationTitle(viewModel.navigationTitle)
.toolbar {
if viewModel.canShowCompleted {
Menu {
Button.init(
viewModel.buttonCompleted.title,
systemImage: viewModel.buttonCompleted.icon
) {
viewModel.toggleCompletedVisibility()
}
} label: {
Label(
"view.task-list.label.actions",
systemImage: "ellipsis"
)
}
}
}
}
}
// MARK: - Previews
#Preview(
"Task list with empty tasks",
traits: .emptyContainer
) {
NavigationStack {
TaskListView(group: .today)
}
}
#Preview(
"Task list - today",
traits: .sampleTasks
) {
NavigationStack {
TaskListView(group: .today)
}
}
#Preview(
"Task list - upcoming",
traits: .sampleTasks
) {
NavigationStack {
TaskListView(group: .upcoming)
}
}
#Preview(
"Task list - overdue",
traits: .sampleTasks
) {
NavigationStack {
TaskListView(group: .overdue)
}
}
#Preview(
"Task list - completed",
traits: .sampleTasks
) {
NavigationStack {
TaskListView(group: .completed)
}
}