App layout improvements #10

Merged
javier merged 5 commits from app/app-layout into main 2026-02-12 03:55:17 +00:00
Showing only changes of commit aefdb12561 - Show all commits
+46 -14
View File
@@ -12,12 +12,18 @@ struct TaskGroupListView: View {
// MARK: Properties // 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. /// Query to monitor all todo tasks for changes.
/// ///
/// This query triggers view updates whenever todo tasks are inserted, updated, or deleted, /// This query triggers view updates whenever todo tasks are inserted, updated, or deleted,
/// ensuring the task counts displayed in the view remain accurate. /// ensuring the task counts displayed in the view remain accurate.
@Query @Query
private var tasks: [Todo] private var todos: [Todo]
/// The view model managing the state and logic for this view. /// The view model managing the state and logic for this view.
/// ///
@@ -26,6 +32,18 @@ struct TaskGroupListView: View {
@State @State
private var viewModel = ViewModel() 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 // MARK: Body
/// The content and behavior of the view. /// The content and behavior of the view.
@@ -35,24 +53,30 @@ struct TaskGroupListView: View {
/// - The group's title /// - The group's title
/// - The current count of tasks in that group /// - The current count of tasks in that group
/// ///
/// Cards are tappable and navigate to a detailed task list for the selected 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. /// Task counts are fetched on-demand from the model context for each render.
var body: some View { var body: some View {
ScrollView { List(
VStack(spacing: 16) { viewModel.groups,
ForEach(viewModel.groups) { group in selection: $group
NavigationLink(destination: TaskListView(group: group)) { ) { group in
Card( Card(
group: group, group: group,
count: viewModel.count(tasks, for: group) count: viewModel.count(
todos,
for: group
) )
)
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
.tag(group)
} }
.buttonStyle(.plain) .listStyle(.plain)
}
}
.padding(.horizontal)
}
.navigationTitle("view.task-group-list.navigation.title") .navigationTitle("view.task-group-list.navigation.title")
.sensoryFeedback(
.selection,
trigger: group
)
} }
} }
@@ -62,8 +86,12 @@ struct TaskGroupListView: View {
"Task group list with empty tasks", "Task group list with empty tasks",
traits: .emptyContainer traits: .emptyContainer
) { ) {
@Previewable
@State
var group: TodoGroup?
NavigationStack { NavigationStack {
TaskGroupListView() TaskGroupListView($group)
} }
} }
@@ -71,7 +99,11 @@ struct TaskGroupListView: View {
"Task group list with sample tasks", "Task group list with sample tasks",
traits: .sampleTasks traits: .sampleTasks
) { ) {
@Previewable
@State
var group: TodoGroup?
NavigationStack { NavigationStack {
TaskGroupListView() TaskGroupListView($group)
} }
} }