Files
PlantGuide/PlantGuide/Presentation/Scenes/PlantDetail/PlantEditView.swift
Trey t 681476a499 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>
2026-01-31 22:50:04 -06:00

151 lines
4.3 KiB
Swift

//
// PlantEditView.swift
// PlantGuide
//
// Created on 2026-01-31.
//
import SwiftUI
// MARK: - PlantEditView
/// A view for editing plant details like custom name and notes.
@MainActor
struct PlantEditView: View {
// MARK: - Properties
/// The plant being edited
let plant: Plant
/// Callback when save is tapped
let onSave: (String?, String?) async -> Void
@Environment(\.dismiss) private var dismiss
@State private var customName: String
@State private var notes: String
@State private var isSaving = false
// MARK: - Initialization
init(plant: Plant, onSave: @escaping (String?, String?) async -> Void) {
self.plant = plant
self.onSave = onSave
_customName = State(initialValue: plant.customName ?? plant.commonNames.first ?? plant.scientificName)
_notes = State(initialValue: plant.notes ?? "")
}
// MARK: - Computed Properties
private var isValid: Bool {
!customName.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
}
// MARK: - Body
var body: some View {
NavigationStack {
Form {
Section {
TextField("Plant Name", text: $customName)
.autocorrectionDisabled()
} header: {
Text("Name")
} footer: {
Text("Give your plant a custom name to easily identify it.")
}
Section {
TextEditor(text: $notes)
.frame(minHeight: 100)
} header: {
Text("Notes")
} footer: {
Text("Add any notes about your plant, such as where you got it or special care instructions.")
}
Section {
plantInfoRow
} header: {
Text("Plant Info")
}
}
.navigationTitle("Edit Plant")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") {
dismiss()
}
}
ToolbarItem(placement: .confirmationAction) {
Button("Save") {
isSaving = true
Task {
let trimmedName = customName.trimmingCharacters(in: .whitespacesAndNewlines)
let trimmedNotes = notes.trimmingCharacters(in: .whitespacesAndNewlines)
await onSave(
trimmedName.isEmpty ? nil : trimmedName,
trimmedNotes.isEmpty ? nil : trimmedNotes
)
dismiss()
}
}
.disabled(!isValid || isSaving)
}
}
.interactiveDismissDisabled(isSaving)
}
}
// MARK: - Plant Info Row
private var plantInfoRow: some View {
VStack(alignment: .leading, spacing: 8) {
HStack {
Text("Scientific Name")
Spacer()
Text(plant.scientificName)
.foregroundStyle(.secondary)
.italic()
}
if !plant.commonNames.isEmpty {
HStack {
Text("Common Name")
Spacer()
Text(plant.commonNames.first ?? "")
.foregroundStyle(.secondary)
}
}
HStack {
Text("Family")
Spacer()
Text(plant.family)
.foregroundStyle(.secondary)
}
}
}
}
// MARK: - Preview
#Preview {
PlantEditView(
plant: Plant(
scientificName: "Monstera deliciosa",
commonNames: ["Swiss Cheese Plant"],
family: "Araceae",
genus: "Monstera",
imageURLs: [],
identificationSource: .onDeviceML,
notes: "Got this from the local nursery",
customName: "My Monstera"
)
) { name, notes in
print("Save: \(name ?? "nil"), \(notes ?? "nil")")
}
}