New builds for iOS 1.0.3 and Android 1.5.1

This commit is contained in:
2025-09-27 18:47:09 -06:00
parent 298ba6149b
commit 5d1748765f
19 changed files with 1157 additions and 1034 deletions

View File

@@ -635,12 +635,6 @@ struct ProblemExpandedView: View {
.foregroundColor(.secondary)
}
if let setter = problem.setter, !setter.isEmpty {
Label(setter, systemImage: "person")
.font(.subheadline)
.foregroundColor(.secondary)
}
if let description = problem.description, !description.isEmpty {
Text(description)
.font(.body)

View File

@@ -13,7 +13,6 @@ struct AddEditProblemView: View {
@State private var selectedClimbType: ClimbType = .boulder
@State private var selectedDifficultySystem: DifficultySystem = .vScale
@State private var difficultyGrade = ""
@State private var setter = ""
@State private var location = ""
@State private var tags = ""
@State private var notes = ""
@@ -63,7 +62,7 @@ struct AddEditProblemView: View {
PhotosSection()
ClimbTypeSection()
DifficultySection()
LocationAndSetterSection()
LocationSection()
TagsSection()
AdditionalInfoSection()
}
@@ -158,7 +157,6 @@ struct AddEditProblemView: View {
)
}
TextField("Route Setter (Optional)", text: $setter)
}
}
@@ -281,7 +279,7 @@ struct AddEditProblemView: View {
}
@ViewBuilder
private func LocationAndSetterSection() -> some View {
private func LocationSection() -> some View {
Section("Location & Details") {
TextField(
"Location (Optional)", text: $location, prompt: Text("e.g., 'Cave area', 'Wall 3'"))
@@ -334,25 +332,28 @@ struct AddEditProblemView: View {
HStack(spacing: 12) {
ForEach(imageData.indices, id: \.self) { index in
if let uiImage = UIImage(data: imageData[index]) {
Image(uiImage: uiImage)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 80, height: 80)
.clipped()
.cornerRadius(8)
.overlay(alignment: .topTrailing) {
Button(action: {
imageData.remove(at: index)
if index < imagePaths.count {
imagePaths.remove(at: index)
}
}) {
Image(systemName: "xmark.circle.fill")
.foregroundColor(.red)
.background(Circle().fill(.white))
ZStack(alignment: .topTrailing) {
Image(uiImage: uiImage)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 80, height: 80)
.clipped()
.cornerRadius(8)
Button(action: {
imageData.remove(at: index)
if index < imagePaths.count {
imagePaths.remove(at: index)
}
.offset(x: 8, y: -8)
}) {
Image(systemName: "xmark.circle.fill")
.foregroundColor(.red)
.background(Circle().fill(.white))
.font(.system(size: 18))
}
.offset(x: 4, y: -4)
}
.frame(width: 88, height: 88) // Extra space for button
} else {
RoundedRectangle(cornerRadius: 8)
.fill(.gray.opacity(0.3))
@@ -365,6 +366,7 @@ struct AddEditProblemView: View {
}
}
.padding(.horizontal, 1)
.padding(.vertical, 8)
}
}
}
@@ -410,7 +412,7 @@ struct AddEditProblemView: View {
selectedClimbType = problem.climbType
selectedDifficultySystem = problem.difficulty.system
difficultyGrade = problem.difficulty.grade
setter = problem.setter ?? ""
location = problem.location ?? ""
tags = problem.tags.joined(separator: ", ")
notes = problem.notes ?? ""
@@ -420,7 +422,7 @@ struct AddEditProblemView: View {
// Load image data for preview
imageData = []
for imagePath in problem.imagePaths {
if let data = try? Data(contentsOf: URL(fileURLWithPath: imagePath)) {
if let data = ImageManager.shared.loadImageData(fromPath: imagePath) {
imageData.append(data)
}
}
@@ -479,7 +481,7 @@ struct AddEditProblemView: View {
let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines)
let trimmedDescription = description.trimmingCharacters(in: .whitespacesAndNewlines)
let trimmedSetter = setter.trimmingCharacters(in: .whitespacesAndNewlines)
let trimmedLocation = location.trimmingCharacters(in: .whitespacesAndNewlines)
let trimmedNotes = notes.trimmingCharacters(in: .whitespacesAndNewlines)
let trimmedTags = tags.split(separator: ",").map {
@@ -494,7 +496,7 @@ struct AddEditProblemView: View {
description: trimmedDescription.isEmpty ? nil : trimmedDescription,
climbType: selectedClimbType,
difficulty: difficulty,
setter: trimmedSetter.isEmpty ? nil : trimmedSetter,
tags: trimmedTags,
location: trimmedLocation.isEmpty ? nil : trimmedLocation,
imagePaths: imagePaths,
@@ -510,7 +512,7 @@ struct AddEditProblemView: View {
description: trimmedDescription.isEmpty ? nil : trimmedDescription,
climbType: selectedClimbType,
difficulty: difficulty,
setter: trimmedSetter.isEmpty ? nil : trimmedSetter,
tags: trimmedTags,
location: trimmedLocation.isEmpty ? nil : trimmedLocation,
imagePaths: imagePaths,

View File

@@ -1,4 +1,3 @@
import SwiftUI
struct GymDetailView: View {
@@ -60,8 +59,10 @@ struct GymDetailView: View {
ToolbarItemGroup(placement: .navigationBarTrailing) {
if gym != nil {
Menu {
Button("Edit Gym") {
Button {
// Navigate to edit view
} label: {
Label("Edit Gym", systemImage: "pencil")
}
Button(role: .destructive) {

View File

@@ -1,4 +1,3 @@
import SwiftUI
struct ProblemDetailView: View {
@@ -64,8 +63,10 @@ struct ProblemDetailView: View {
ToolbarItemGroup(placement: .navigationBarTrailing) {
if problem != nil {
Menu {
Button("Edit Problem") {
Button {
showingEditProblem = true
} label: {
Label("Edit Problem", systemImage: "pencil")
}
Button(role: .destructive) {
@@ -167,12 +168,6 @@ struct ProblemHeaderCard: View {
.font(.body)
}
if let setter = problem.setter, !setter.isEmpty {
Text("Set by: \(setter)")
.font(.subheadline)
.foregroundColor(.secondary)
}
if !problem.tags.isEmpty {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 8) {

View File

@@ -280,7 +280,6 @@ struct SessionStatsCard: View {
LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 2), spacing: 16) {
StatItem(label: "Total Attempts", value: "\(stats.totalAttempts)")
StatItem(label: "Problems", value: "\(stats.uniqueProblemsAttempted)")
StatItem(label: "Successful", value: "\(stats.successfulAttempts)")
StatItem(label: "Completed", value: "\(stats.uniqueProblemsCompleted)")
}
}

View File

@@ -1,4 +1,3 @@
import SwiftUI
struct GymsView: View {
@@ -49,7 +48,10 @@ struct GymsList: View {
Button {
gymToEdit = gym
} label: {
Label("Edit", systemImage: "pencil")
HStack {
Image(systemName: "pencil")
Text("Edit")
}
}
.tint(.blue)
}

View File

@@ -13,10 +13,9 @@ struct ProblemsView: View {
// Apply search filter
if !searchText.isEmpty {
filtered = filtered.filter { problem in
(problem.name?.localizedCaseInsensitiveContains(searchText) ?? false)
return problem.name?.localizedCaseInsensitiveContains(searchText) ?? false
|| (problem.description?.localizedCaseInsensitiveContains(searchText) ?? false)
|| (problem.location?.localizedCaseInsensitiveContains(searchText) ?? false)
|| (problem.setter?.localizedCaseInsensitiveContains(searchText) ?? false)
|| problem.tags.contains { $0.localizedCaseInsensitiveContains(searchText) }
}
}
@@ -31,7 +30,11 @@ struct ProblemsView: View {
filtered = filtered.filter { $0.gymId == gym.id }
}
return filtered.sorted { $0.updatedAt > $1.updatedAt }
// Separate active and inactive problems
let active = filtered.filter { $0.isActive }.sorted { $0.updatedAt > $1.updatedAt }
let inactive = filtered.filter { !$0.isActive }.sorted { $0.updatedAt > $1.updatedAt }
return active + inactive
}
var body: some View {
@@ -195,10 +198,23 @@ struct ProblemsList: View {
Label("Delete", systemImage: "trash")
}
Button {
let updatedProblem = problem.updated(isActive: !problem.isActive)
dataManager.updateProblem(updatedProblem)
} label: {
Label(
problem.isActive ? "Mark as Reset" : "Mark as Active",
systemImage: problem.isActive ? "xmark.circle" : "checkmark.circle")
}
.tint(.orange)
Button {
problemToEdit = problem
} label: {
Label("Edit", systemImage: "pencil")
HStack {
Image(systemName: "pencil")
Text("Edit")
}
}
.tint(.blue)
}
@@ -239,6 +255,7 @@ struct ProblemRow: View {
Text(problem.name ?? "Unnamed Problem")
.font(.headline)
.fontWeight(.semibold)
.foregroundColor(problem.isActive ? .primary : .secondary)
Text(gym?.name ?? "Unknown Gym")
.font(.subheadline)
@@ -295,9 +312,9 @@ struct ProblemRow: View {
}
if !problem.isActive {
Text("Inactive")
Text("Reset / No Longer Set")
.font(.caption)
.foregroundColor(.red)
.foregroundColor(.orange)
.fontWeight(.medium)
}
}