1.5.0 Initial run as iOS in a monorepo
This commit is contained in:
171
ios/OpenClimb/Views/GymsView.swift
Normal file
171
ios/OpenClimb/Views/GymsView.swift
Normal file
@@ -0,0 +1,171 @@
|
||||
//
|
||||
// GymsView.swift
|
||||
// OpenClimb
|
||||
//
|
||||
// Created by OpenClimb on 2025-01-17.
|
||||
//
|
||||
|
||||
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 {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button("Add") {
|
||||
showingAddGym = true
|
||||
}
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showingAddGym) {
|
||||
AddEditGymView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct GymsList: View {
|
||||
@EnvironmentObject var dataManager: ClimbingDataManager
|
||||
|
||||
var body: some View {
|
||||
List(dataManager.gyms, id: \.id) { gym in
|
||||
NavigationLink(destination: GymDetailView(gymId: gym.id)) {
|
||||
GymRow(gym: gym)
|
||||
}
|
||||
}
|
||||
.listStyle(.plain)
|
||||
}
|
||||
}
|
||||
|
||||
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, 4)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user