1.5.0 Initial run as iOS in a monorepo
This commit is contained in:
143
ios/OpenClimb/Views/AddEdit/AddEditSessionView.swift
Normal file
143
ios/OpenClimb/Views/AddEdit/AddEditSessionView.swift
Normal file
@@ -0,0 +1,143 @@
|
||||
//
|
||||
// AddEditSessionView.swift
|
||||
// OpenClimb
|
||||
//
|
||||
// Created by OpenClimb on 2025-01-17.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct AddEditSessionView: View {
|
||||
let sessionId: UUID?
|
||||
@EnvironmentObject var dataManager: ClimbingDataManager
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
@State private var selectedGym: Gym?
|
||||
@State private var sessionDate = Date()
|
||||
@State private var notes = ""
|
||||
@State private var isEditing = false
|
||||
|
||||
private var existingSession: ClimbSession? {
|
||||
guard let sessionId = sessionId else { return nil }
|
||||
return dataManager.session(withId: sessionId)
|
||||
}
|
||||
|
||||
init(sessionId: UUID? = nil) {
|
||||
self.sessionId = sessionId
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
Form {
|
||||
GymSelectionSection()
|
||||
SessionDetailsSection()
|
||||
}
|
||||
.navigationTitle(isEditing ? "Edit Session" : "New Session")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
Button("Cancel") {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button("Save") {
|
||||
saveSession()
|
||||
}
|
||||
.disabled(selectedGym == nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
loadExistingSession()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func GymSelectionSection() -> some View {
|
||||
Section("Select Gym") {
|
||||
if dataManager.gyms.isEmpty {
|
||||
Text("No gyms available. Add a gym first.")
|
||||
.foregroundColor(.secondary)
|
||||
} else {
|
||||
ForEach(dataManager.gyms, id: \.id) { gym in
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(gym.name)
|
||||
.font(.headline)
|
||||
|
||||
if let location = gym.location, !location.isEmpty {
|
||||
Text(location)
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
if selectedGym?.id == gym.id {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundColor(.blue)
|
||||
}
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
selectedGym = gym
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func SessionDetailsSection() -> some View {
|
||||
Section("Session Details") {
|
||||
DatePicker(
|
||||
"Date",
|
||||
selection: $sessionDate,
|
||||
displayedComponents: [.date]
|
||||
)
|
||||
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("Notes (Optional)")
|
||||
.font(.headline)
|
||||
|
||||
TextEditor(text: $notes)
|
||||
.frame(minHeight: 100)
|
||||
.padding(8)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.fill(.quaternary)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func loadExistingSession() {
|
||||
if let session = existingSession {
|
||||
isEditing = true
|
||||
selectedGym = dataManager.gym(withId: session.gymId)
|
||||
sessionDate = session.date
|
||||
notes = session.notes ?? ""
|
||||
}
|
||||
}
|
||||
|
||||
private func saveSession() {
|
||||
guard let gym = selectedGym else { return }
|
||||
|
||||
if isEditing, let session = existingSession {
|
||||
let updatedSession = session.updated(notes: notes.isEmpty ? nil : notes)
|
||||
dataManager.updateSession(updatedSession)
|
||||
} else {
|
||||
dataManager.startSession(gymId: gym.id, notes: notes.isEmpty ? nil : notes)
|
||||
}
|
||||
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
AddEditSessionView()
|
||||
.environmentObject(ClimbingDataManager.preview)
|
||||
}
|
||||
Reference in New Issue
Block a user