import SwiftUI struct GymsView: View { @EnvironmentObject var dataManager: ClimbingDataManager @State private var showingAddGym = false var body: some View { NavigationView { VStack { if dataManager.gyms.isEmpty { EmptyGymsView() } else { GymsList() } } .navigationTitle("Gyms") .toolbar { ToolbarItemGroup(placement: .navigationBarTrailing) { if dataManager.isSyncing { HStack(spacing: 2) { ProgressView() .progressViewStyle(CircularProgressViewStyle(tint: .blue)) .scaleEffect(0.6) } .padding(.horizontal, 6) .padding(.vertical, 3) .background( Circle() .fill(.regularMaterial) ) .transition(.scale.combined(with: .opacity)) .animation( .easeInOut(duration: 0.2), value: dataManager.isSyncing ) } Button("Add") { showingAddGym = true } } } .sheet(isPresented: $showingAddGym) { AddEditGymView() } } } } struct GymsList: View { @EnvironmentObject var dataManager: ClimbingDataManager @State private var gymToDelete: Gym? @State private var gymToEdit: Gym? var body: some View { List(dataManager.gyms, id: \.id) { gym in NavigationLink(destination: GymDetailView(gymId: gym.id)) { GymRow(gym: gym) } .swipeActions(edge: .trailing, allowsFullSwipe: false) { Button(role: .destructive) { gymToDelete = gym } label: { Label("Delete", systemImage: "trash") } Button { gymToEdit = gym } label: { HStack { Image(systemName: "pencil") Text("Edit") } } .tint(.blue) } } .alert("Delete Gym", isPresented: .constant(gymToDelete != nil)) { Button("Cancel", role: .cancel) { gymToDelete = nil } Button("Delete", role: .destructive) { if let gym = gymToDelete { dataManager.deleteGym(gym) gymToDelete = nil } } } message: { Text( "Are you sure you want to delete this gym? This will also delete all associated problems and sessions." ) } .sheet(item: $gymToEdit) { gym in AddEditGymView(gymId: gym.id) } } } struct GymRow: View { let gym: Gym @EnvironmentObject var dataManager: ClimbingDataManager private var problemCount: Int { dataManager.problems(forGym: gym.id).count } private var sessionCount: Int { dataManager.sessions(forGym: gym.id).count } var body: some View { VStack(alignment: .leading, spacing: 12) { // Header VStack(alignment: .leading, spacing: 4) { Text(gym.name) .font(.headline) .fontWeight(.bold) if let location = gym.location, !location.isEmpty { Text(location) .font(.subheadline) .foregroundColor(.secondary) } } // Climb Types if !gym.supportedClimbTypes.isEmpty { ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: 8) { ForEach(gym.supportedClimbTypes, id: \.self) { climbType in Text(climbType.displayName) .font(.caption) .padding(.horizontal, 8) .padding(.vertical, 4) .background( RoundedRectangle(cornerRadius: 8) .fill(.blue.opacity(0.1)) ) .foregroundColor(.blue) } } } } // Difficulty Systems if !gym.difficultySystems.isEmpty { Text( "Systems: \(gym.difficultySystems.map { $0.displayName }.joined(separator: ", "))" ) .font(.caption) .foregroundColor(.secondary) } // Stats HStack { Label("\(problemCount)", systemImage: "star.fill") .font(.caption) .foregroundColor(.orange) Label("\(sessionCount)", systemImage: "play.fill") .font(.caption) .foregroundColor(.green) Spacer() } // Notes preview if let notes = gym.notes, !notes.isEmpty { Text(notes) .font(.caption) .foregroundColor(.secondary) .lineLimit(2) } } .padding(.vertical, 8) } } struct EmptyGymsView: View { @State private var showingAddGym = false var body: some View { VStack(spacing: 20) { Spacer() Image(systemName: "location.fill") .font(.system(size: 60)) .foregroundColor(.secondary) VStack(spacing: 8) { Text("No Gyms Added") .font(.title2) .fontWeight(.bold) Text("Add your favorite climbing gyms to start tracking your progress!") .font(.body) .foregroundColor(.secondary) .multilineTextAlignment(.center) .padding(.horizontal) } Button("Add Gym") { showingAddGym = true } .buttonStyle(.borderedProminent) .controlSize(.large) Spacer() } .sheet(isPresented: $showingAddGym) { AddEditGymView() } } } #Preview { GymsView() .environmentObject(ClimbingDataManager.preview) }