91 lines
3.3 KiB
Swift
91 lines
3.3 KiB
Swift
import SwiftUI
|
|
|
|
struct ContentView: View {
|
|
@State private var viewModel = TodoViewModel()
|
|
@State private var showingAddSheet = false
|
|
@State private var editingTodo: Todo? = nil
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
VStack(spacing: 0) {
|
|
// Filter bar
|
|
FilterBar(
|
|
currentFilter: viewModel.currentFilter,
|
|
countForFilter: { viewModel.count(for: $0) },
|
|
onFilterSelected: { viewModel.setFilter($0) }
|
|
)
|
|
|
|
Divider()
|
|
|
|
// Todo list or empty state
|
|
if viewModel.filteredTodos.isEmpty {
|
|
EmptyStateView()
|
|
} else {
|
|
List {
|
|
ForEach(viewModel.filteredTodos) { todo in
|
|
TodoItemView(
|
|
todo: todo,
|
|
onToggle: {
|
|
viewModel.toggleTodo(id: todo.id)
|
|
},
|
|
onTap: {
|
|
editingTodo = todo
|
|
}
|
|
)
|
|
.listRowInsets(EdgeInsets())
|
|
.listRowSeparator(.visible)
|
|
}
|
|
.onDelete { indexSet in
|
|
let filtered = viewModel.filteredTodos
|
|
for index in indexSet {
|
|
let todo = filtered[index]
|
|
viewModel.deleteTodo(id: todo.id)
|
|
}
|
|
}
|
|
}
|
|
.listStyle(.plain)
|
|
}
|
|
}
|
|
.navigationTitle("Todos \u{2013} SwiftUI")
|
|
.navigationBarTitleDisplayMode(.large)
|
|
.toolbar {
|
|
ToolbarItem(placement: .primaryAction) {
|
|
Button {
|
|
showingAddSheet = true
|
|
} label: {
|
|
Image(systemName: "plus")
|
|
.fontWeight(.semibold)
|
|
}
|
|
}
|
|
}
|
|
.sheet(isPresented: $showingAddSheet) {
|
|
TodoFormView(
|
|
editingTodo: nil,
|
|
onSave: { title, category, priority in
|
|
viewModel.addTodo(title: title, category: category, priority: priority)
|
|
showingAddSheet = false
|
|
},
|
|
onCancel: {
|
|
showingAddSheet = false
|
|
}
|
|
)
|
|
.presentationDetents([.medium, .large])
|
|
}
|
|
.sheet(item: $editingTodo) { todo in
|
|
TodoFormView(
|
|
editingTodo: todo,
|
|
onSave: { title, category, priority in
|
|
viewModel.updateTodo(id: todo.id, title: title, category: category, priority: priority)
|
|
editingTodo = nil
|
|
},
|
|
onCancel: {
|
|
editingTodo = nil
|
|
}
|
|
)
|
|
.presentationDetents([.medium, .large])
|
|
}
|
|
}
|
|
.tint(Color(red: 0x62/255.0, green: 0x00/255.0, blue: 0xEE/255.0))
|
|
}
|
|
}
|