WIP: Various UI and feature improvements
- Add AllTasksView and PlantEditView components - Update CoreDataStack CloudKit container ID - Improve CameraView and IdentificationViewModel - Update MainTabView, RoomsListView, UpcomingTasksSection - Minor fixes to PlantGuideApp and SettingsViewModel Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
//
|
||||
// AllTasksView.swift
|
||||
// PlantGuide
|
||||
//
|
||||
// Created on 2026-01-31.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - AllTasksView
|
||||
|
||||
/// Displays all pending care tasks for a plant
|
||||
struct AllTasksView: View {
|
||||
// MARK: - Properties
|
||||
|
||||
let plantName: String
|
||||
let tasks: [CareTask]
|
||||
var onTaskComplete: ((CareTask) -> Void)?
|
||||
|
||||
// MARK: - Body
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if tasks.isEmpty {
|
||||
emptyStateView
|
||||
} else {
|
||||
taskListView
|
||||
}
|
||||
}
|
||||
.navigationTitle("All Tasks")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.background(Color(.systemGroupedBackground))
|
||||
}
|
||||
|
||||
// MARK: - Task List View
|
||||
|
||||
private var taskListView: some View {
|
||||
ScrollView {
|
||||
VStack(spacing: 16) {
|
||||
// Overdue tasks section
|
||||
let overdueTasks = tasks.filter { $0.isOverdue }
|
||||
if !overdueTasks.isEmpty {
|
||||
taskSection(title: "Overdue", tasks: overdueTasks, tintColor: .red)
|
||||
}
|
||||
|
||||
// Today's tasks
|
||||
let todayTasks = tasks.filter { !$0.isOverdue && Calendar.current.isDateInToday($0.scheduledDate) }
|
||||
if !todayTasks.isEmpty {
|
||||
taskSection(title: "Today", tasks: todayTasks, tintColor: .blue)
|
||||
}
|
||||
|
||||
// Upcoming tasks
|
||||
let upcomingTasks = tasks.filter { !$0.isOverdue && !Calendar.current.isDateInToday($0.scheduledDate) }
|
||||
if !upcomingTasks.isEmpty {
|
||||
taskSection(title: "Upcoming", tasks: upcomingTasks, tintColor: .secondary)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Task Section
|
||||
|
||||
private func taskSection(title: String, tasks: [CareTask], tintColor: Color) -> some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
HStack {
|
||||
Text(title)
|
||||
.font(.headline)
|
||||
.foregroundStyle(tintColor)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("\(tasks.count)")
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
VStack(spacing: 8) {
|
||||
ForEach(tasks) { task in
|
||||
TaskRow(task: task, onComplete: {
|
||||
onTaskComplete?(task)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.background(Color(.systemGray6))
|
||||
.cornerRadius(12)
|
||||
}
|
||||
|
||||
// MARK: - Empty State View
|
||||
|
||||
private var emptyStateView: some View {
|
||||
VStack(spacing: 16) {
|
||||
Spacer()
|
||||
|
||||
Image(systemName: "checkmark.circle")
|
||||
.font(.system(size: 60))
|
||||
.foregroundStyle(.green)
|
||||
|
||||
Text("All Caught Up!")
|
||||
.font(.title2)
|
||||
.fontWeight(.semibold)
|
||||
|
||||
Text("No pending care tasks for \(plantName)")
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.secondary)
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
#Preview("All Tasks - With Tasks") {
|
||||
let samplePlantID = UUID()
|
||||
let sampleTasks = [
|
||||
CareTask(
|
||||
plantID: samplePlantID,
|
||||
type: .watering,
|
||||
scheduledDate: Date().addingTimeInterval(-86400), // 1 day ago (overdue)
|
||||
notes: "Check soil moisture"
|
||||
),
|
||||
CareTask(
|
||||
plantID: samplePlantID,
|
||||
type: .fertilizing,
|
||||
scheduledDate: Date(), // Today
|
||||
notes: ""
|
||||
),
|
||||
CareTask(
|
||||
plantID: samplePlantID,
|
||||
type: .pruning,
|
||||
scheduledDate: Date().addingTimeInterval(86400 * 3), // 3 days from now
|
||||
notes: "Remove dead leaves"
|
||||
),
|
||||
CareTask(
|
||||
plantID: samplePlantID,
|
||||
type: .watering,
|
||||
scheduledDate: Date().addingTimeInterval(86400 * 7), // 7 days from now
|
||||
notes: ""
|
||||
)
|
||||
]
|
||||
|
||||
return NavigationStack {
|
||||
AllTasksView(plantName: "Monstera", tasks: sampleTasks) { task in
|
||||
print("Completed task: \(task.type)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview("All Tasks - Empty") {
|
||||
NavigationStack {
|
||||
AllTasksView(plantName: "Monstera", tasks: [])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user