import SwiftUI
struct TaskItem: Identifiable {
let id = UUID()
let name: String
let done: Bool
}
struct TaskGroupData: Identifiable {
let id = UUID()
let category: String
let tasks: [TaskItem]
}
struct TaskManagerView: View {
@State private var taskGroups: [TaskGroupData] = []
@State private var isLoading = true
var body: some View {
NavigationView {
Group {
if isLoading {
ProgressView("Loading tasks...")
.progressViewStyle(CircularProgressViewStyle())
} else {
List {
ForEach(taskGroups) { group in
Section(header: Text(group.category)) {
ForEach(group.tasks) { task in
HStack {
Text(task.name)
Spacer()
Image(systemName: task.done ? "checkmark.square" : "square")
.foregroundColor(task.done ? .green : .secondary)
.accessibilityLabel(task.done ? "Done" : "Not done")
}
.padding(.vertical, 4)
}
}
}
}
.listStyle(GroupedListStyle())
}
}
.navigationTitle("Task Manager")
.task {
await loadTasks()
}
}
}
func loadTasks() async {
isLoading = true
var loadedGroups: [TaskGroupData] = []
await withTaskGroup(of: TaskGroupData?.self) { group in
let categories = ["Work", "Home"]
for category in categories {
group.addTask {
// Simulate network delay
try? await Task.sleep(nanoseconds: 1_000_000_000) // 1 second
switch category {
case "Work":
let tasks = [
TaskItem(name: "Email client", done: false),
TaskItem(name: "Prepare report", done: true)
]
return TaskGroupData(category: category, tasks: tasks)
case "Home":
let tasks = [
TaskItem(name: "Clean kitchen", done: false),
TaskItem(name: "Fix sink", done: false)
]
return TaskGroupData(category: category, tasks: tasks)
default:
return nil
}
}
}
for await result in group {
if let groupData = result {
loadedGroups.append(groupData)
}
}
}
// Sort groups by category name
taskGroups = loadedGroups.sorted { $0.category < $1.category }
isLoading = false
}
}
struct TaskManagerView_Previews: PreviewProvider {
static var previews: some View {
TaskManagerView()
}
}
This solution uses Swift concurrency's withTaskGroup to load task groups asynchronously. Each category is loaded in its own child task with a simulated 1-second delay to mimic network loading.
After all tasks complete, the results are collected and sorted alphabetically by category. The UI shows a loading spinner while loading, then displays the tasks grouped by category in a List with sections.
Each task row shows the task name and a checkbox icon that is green if done, or gray if not. Accessibility labels describe the checkbox state for screen readers.
This approach teaches how to use TaskGroup to run multiple async tasks concurrently and update UI state when all finish.