Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
cacd178817
|
@@ -465,7 +465,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = Ascently/Ascently.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Ascently/Ascently.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 34;
|
CURRENT_PROJECT_VERSION = 35;
|
||||||
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
||||||
DRIVERKIT_DEPLOYMENT_TARGET = 24.6;
|
DRIVERKIT_DEPLOYMENT_TARGET = 24.6;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -487,7 +487,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 15.6;
|
MACOSX_DEPLOYMENT_TARGET = 15.6;
|
||||||
MARKETING_VERSION = 2.4.0;
|
MARKETING_VERSION = 2.4.1;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently;
|
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
@@ -513,7 +513,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = Ascently/Ascently.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Ascently/Ascently.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 34;
|
CURRENT_PROJECT_VERSION = 35;
|
||||||
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
||||||
DRIVERKIT_DEPLOYMENT_TARGET = 24.6;
|
DRIVERKIT_DEPLOYMENT_TARGET = 24.6;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -535,7 +535,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 15.6;
|
MACOSX_DEPLOYMENT_TARGET = 15.6;
|
||||||
MARKETING_VERSION = 2.4.0;
|
MARKETING_VERSION = 2.4.1;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently;
|
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
@@ -602,7 +602,7 @@
|
|||||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||||
CODE_SIGN_ENTITLEMENTS = SessionStatusLiveExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = SessionStatusLiveExtension.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 34;
|
CURRENT_PROJECT_VERSION = 35;
|
||||||
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = SessionStatusLive/Info.plist;
|
INFOPLIST_FILE = SessionStatusLive/Info.plist;
|
||||||
@@ -613,7 +613,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 2.4.0;
|
MARKETING_VERSION = 2.4.1;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently.SessionStatusLive;
|
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently.SessionStatusLive;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
@@ -632,7 +632,7 @@
|
|||||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||||
CODE_SIGN_ENTITLEMENTS = SessionStatusLiveExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = SessionStatusLiveExtension.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 34;
|
CURRENT_PROJECT_VERSION = 35;
|
||||||
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = SessionStatusLive/Info.plist;
|
INFOPLIST_FILE = SessionStatusLive/Info.plist;
|
||||||
@@ -643,7 +643,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 2.4.0;
|
MARKETING_VERSION = 2.4.1;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently.SessionStatusLive;
|
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently.SessionStatusLive;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
|||||||
Binary file not shown.
@@ -8,10 +8,16 @@ struct ProblemsView: View {
|
|||||||
@State private var selectedGym: Gym?
|
@State private var selectedGym: Gym?
|
||||||
@State private var searchText = ""
|
@State private var searchText = ""
|
||||||
@State private var showingSearch = false
|
@State private var showingSearch = false
|
||||||
|
@State private var showingFilters = false
|
||||||
@FocusState private var isSearchFocused: Bool
|
@FocusState private var isSearchFocused: Bool
|
||||||
|
|
||||||
@State private var cachedFilteredProblems: [Problem] = []
|
@State private var cachedFilteredProblems: [Problem] = []
|
||||||
|
|
||||||
|
// State moved from ProblemsList
|
||||||
|
@State private var problemToDelete: Problem?
|
||||||
|
@State private var problemToEdit: Problem?
|
||||||
|
@State private var animationKey = 0
|
||||||
|
|
||||||
private func updateFilteredProblems() {
|
private func updateFilteredProblems() {
|
||||||
Task(priority: .userInitiated) {
|
Task(priority: .userInitiated) {
|
||||||
let result = await computeFilteredProblems()
|
let result = await computeFilteredProblems()
|
||||||
@@ -71,61 +77,67 @@ struct ProblemsView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
Group {
|
Group {
|
||||||
VStack(spacing: 0) {
|
if cachedFilteredProblems.isEmpty {
|
||||||
if showingSearch {
|
VStack(spacing: 0) {
|
||||||
HStack(spacing: 8) {
|
headerContent
|
||||||
Image(systemName: "magnifyingglass")
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
.font(.system(size: 16, weight: .medium))
|
|
||||||
|
|
||||||
TextField("Search problems...", text: $searchText)
|
|
||||||
.textFieldStyle(.plain)
|
|
||||||
.font(.system(size: 16))
|
|
||||||
.focused($isSearchFocused)
|
|
||||||
.submitLabel(.search)
|
|
||||||
}
|
|
||||||
.padding(.horizontal, 12)
|
|
||||||
.padding(.vertical, 10)
|
|
||||||
.background {
|
|
||||||
if #available(iOS 18.0, *) {
|
|
||||||
RoundedRectangle(cornerRadius: 12)
|
|
||||||
.fill(.regularMaterial)
|
|
||||||
.overlay {
|
|
||||||
RoundedRectangle(cornerRadius: 12)
|
|
||||||
.stroke(.quaternary, lineWidth: 0.5)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
RoundedRectangle(cornerRadius: 10)
|
|
||||||
.fill(Color(.systemGray6))
|
|
||||||
.overlay {
|
|
||||||
RoundedRectangle(cornerRadius: 10)
|
|
||||||
.stroke(Color(.systemGray4), lineWidth: 0.5)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(.horizontal)
|
|
||||||
.padding(.top, 8)
|
|
||||||
.animation(.easeInOut(duration: 0.3), value: showingSearch)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !dataManager.problems.isEmpty && !showingSearch {
|
|
||||||
FilterSection(
|
|
||||||
selectedClimbType: $selectedClimbType,
|
|
||||||
selectedGym: $selectedGym,
|
|
||||||
filteredProblems: cachedFilteredProblems
|
|
||||||
)
|
|
||||||
.padding()
|
|
||||||
.background(.regularMaterial)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cachedFilteredProblems.isEmpty {
|
|
||||||
EmptyProblemsView(
|
EmptyProblemsView(
|
||||||
isEmpty: dataManager.problems.isEmpty,
|
isEmpty: dataManager.problems.isEmpty,
|
||||||
isFiltered: !dataManager.problems.isEmpty
|
isFiltered: !dataManager.problems.isEmpty
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
ProblemsList(problems: cachedFilteredProblems)
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
List {
|
||||||
|
if showingSearch {
|
||||||
|
Section {
|
||||||
|
headerContent
|
||||||
|
}
|
||||||
|
.listRowInsets(EdgeInsets())
|
||||||
|
.listRowSeparator(.hidden)
|
||||||
|
.listRowBackground(Color.clear)
|
||||||
|
}
|
||||||
|
|
||||||
|
ForEach(cachedFilteredProblems) { problem in
|
||||||
|
NavigationLink(destination: ProblemDetailView(problemId: problem.id)) {
|
||||||
|
ProblemRow(problem: problem)
|
||||||
|
}
|
||||||
|
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
|
||||||
|
Button(role: .destructive) {
|
||||||
|
problemToDelete = problem
|
||||||
|
} label: {
|
||||||
|
Label("Delete", systemImage: "trash")
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
withAnimation(.spring(response: 0.5, dampingFraction: 0.8, blendDuration: 0.1))
|
||||||
|
{
|
||||||
|
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: {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "pencil")
|
||||||
|
Text("Edit")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tint(themeManager.accentColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.listStyle(.plain)
|
||||||
|
.animation(
|
||||||
|
.spring(response: 0.5, dampingFraction: 0.8, blendDuration: 0.1),
|
||||||
|
value: animationKey
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle("Problems")
|
.navigationTitle("Problems")
|
||||||
@@ -166,6 +178,14 @@ struct ProblemsView: View {
|
|||||||
.foregroundColor(showingSearch ? .secondary : themeManager.accentColor)
|
.foregroundColor(showingSearch ? .secondary : themeManager.accentColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Button(action: {
|
||||||
|
showingFilters = true
|
||||||
|
}) {
|
||||||
|
Image(systemName: (selectedClimbType != nil || selectedGym != nil) ? "line.3.horizontal.decrease.circle.fill" : "line.3.horizontal.decrease.circle")
|
||||||
|
.font(.system(size: 16, weight: .medium))
|
||||||
|
.foregroundColor(themeManager.accentColor)
|
||||||
|
}
|
||||||
|
|
||||||
if !dataManager.gyms.isEmpty {
|
if !dataManager.gyms.isEmpty {
|
||||||
Button("Add") {
|
Button("Add") {
|
||||||
showingAddProblem = true
|
showingAddProblem = true
|
||||||
@@ -176,6 +196,32 @@ struct ProblemsView: View {
|
|||||||
.sheet(isPresented: $showingAddProblem) {
|
.sheet(isPresented: $showingAddProblem) {
|
||||||
AddEditProblemView()
|
AddEditProblemView()
|
||||||
}
|
}
|
||||||
|
.sheet(isPresented: $showingFilters) {
|
||||||
|
FilterSheet(
|
||||||
|
selectedClimbType: $selectedClimbType,
|
||||||
|
selectedGym: $selectedGym,
|
||||||
|
filteredProblems: cachedFilteredProblems
|
||||||
|
)
|
||||||
|
.presentationDetents([.height(320)])
|
||||||
|
}
|
||||||
|
.sheet(item: $problemToEdit) { problem in
|
||||||
|
AddEditProblemView(problemId: problem.id)
|
||||||
|
}
|
||||||
|
.alert("Delete Problem", isPresented: .constant(problemToDelete != nil)) {
|
||||||
|
Button("Cancel", role: .cancel) {
|
||||||
|
problemToDelete = nil
|
||||||
|
}
|
||||||
|
Button("Delete", role: .destructive) {
|
||||||
|
if let problem = problemToDelete {
|
||||||
|
dataManager.deleteProblem(problem)
|
||||||
|
problemToDelete = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} message: {
|
||||||
|
Text(
|
||||||
|
"Are you sure you want to delete this problem? This will also delete all associated attempts."
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
updateFilteredProblems()
|
updateFilteredProblems()
|
||||||
@@ -192,6 +238,51 @@ struct ProblemsView: View {
|
|||||||
.onChange(of: selectedGym) {
|
.onChange(of: selectedGym) {
|
||||||
updateFilteredProblems()
|
updateFilteredProblems()
|
||||||
}
|
}
|
||||||
|
.onChange(of: cachedFilteredProblems) {
|
||||||
|
animationKey += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var headerContent: some View {
|
||||||
|
VStack(spacing: 0) {
|
||||||
|
if showingSearch {
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
Image(systemName: "magnifyingglass")
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.font(.system(size: 16, weight: .medium))
|
||||||
|
|
||||||
|
TextField("Search problems...", text: $searchText)
|
||||||
|
.textFieldStyle(.plain)
|
||||||
|
.font(.system(size: 16))
|
||||||
|
.focused($isSearchFocused)
|
||||||
|
.submitLabel(.search)
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 12)
|
||||||
|
.padding(.vertical, 10)
|
||||||
|
.background {
|
||||||
|
if #available(iOS 18.0, *) {
|
||||||
|
RoundedRectangle(cornerRadius: 12)
|
||||||
|
.fill(.regularMaterial)
|
||||||
|
.overlay {
|
||||||
|
RoundedRectangle(cornerRadius: 12)
|
||||||
|
.stroke(.quaternary, lineWidth: 0.5)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
RoundedRectangle(cornerRadius: 10)
|
||||||
|
.fill(Color(.systemGray6))
|
||||||
|
.overlay {
|
||||||
|
RoundedRectangle(cornerRadius: 10)
|
||||||
|
.stroke(Color(.systemGray4), lineWidth: 0.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.horizontal)
|
||||||
|
.padding(.top, 8)
|
||||||
|
.padding(.bottom, 8)
|
||||||
|
.animation(.easeInOut(duration: 0.3), value: showingSearch)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,81 +391,7 @@ struct FilterChip: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProblemsList: View {
|
|
||||||
let problems: [Problem]
|
|
||||||
@EnvironmentObject var dataManager: ClimbingDataManager
|
|
||||||
@EnvironmentObject var themeManager: ThemeManager
|
|
||||||
@State private var problemToDelete: Problem?
|
|
||||||
@State private var problemToEdit: Problem?
|
|
||||||
@State private var animationKey = 0
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
List(problems, id: \.id) { problem in
|
|
||||||
NavigationLink(destination: ProblemDetailView(problemId: problem.id)) {
|
|
||||||
ProblemRow(problem: problem)
|
|
||||||
}
|
|
||||||
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
|
|
||||||
Button(role: .destructive) {
|
|
||||||
problemToDelete = problem
|
|
||||||
} label: {
|
|
||||||
Label("Delete", systemImage: "trash")
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
withAnimation(.spring(response: 0.5, dampingFraction: 0.8, blendDuration: 0.1))
|
|
||||||
{
|
|
||||||
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: {
|
|
||||||
HStack {
|
|
||||||
Image(systemName: "pencil")
|
|
||||||
Text("Edit")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.tint(themeManager.accentColor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.animation(
|
|
||||||
.spring(response: 0.5, dampingFraction: 0.8, blendDuration: 0.1),
|
|
||||||
value: animationKey
|
|
||||||
)
|
|
||||||
.onChange(of: problems) {
|
|
||||||
animationKey += 1
|
|
||||||
}
|
|
||||||
.listStyle(.plain)
|
|
||||||
.scrollContentBackground(.hidden)
|
|
||||||
.scrollIndicators(.hidden)
|
|
||||||
.clipped()
|
|
||||||
.alert("Delete Problem", isPresented: .constant(problemToDelete != nil)) {
|
|
||||||
Button("Cancel", role: .cancel) {
|
|
||||||
problemToDelete = nil
|
|
||||||
}
|
|
||||||
Button("Delete", role: .destructive) {
|
|
||||||
if let problem = problemToDelete {
|
|
||||||
dataManager.deleteProblem(problem)
|
|
||||||
problemToDelete = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} message: {
|
|
||||||
Text(
|
|
||||||
"Are you sure you want to delete this problem? This will also delete all associated attempts."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.sheet(item: $problemToEdit) { problem in
|
|
||||||
AddEditProblemView(problemId: problem.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ProblemRow: View {
|
struct ProblemRow: View {
|
||||||
let problem: Problem
|
let problem: Problem
|
||||||
@@ -528,6 +545,71 @@ struct EmptyProblemsView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct FilterSheet: View {
|
||||||
|
@Binding var selectedClimbType: ClimbType?
|
||||||
|
@Binding var selectedGym: Gym?
|
||||||
|
let filteredProblems: [Problem]
|
||||||
|
@Environment(\.dismiss) var dismiss
|
||||||
|
@EnvironmentObject var themeManager: ThemeManager
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
NavigationStack {
|
||||||
|
ScrollView {
|
||||||
|
FilterSection(
|
||||||
|
selectedClimbType: $selectedClimbType,
|
||||||
|
selectedGym: $selectedGym,
|
||||||
|
filteredProblems: filteredProblems
|
||||||
|
)
|
||||||
|
.padding()
|
||||||
|
}
|
||||||
|
.navigationTitle("Filters")
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItem(placement: .navigationBarTrailing) {
|
||||||
|
Button(action: {
|
||||||
|
dismiss()
|
||||||
|
}) {
|
||||||
|
Text("Done")
|
||||||
|
.font(.subheadline)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.padding(.horizontal, 16)
|
||||||
|
.padding(.vertical, 6)
|
||||||
|
.background(.ultraThinMaterial)
|
||||||
|
.clipShape(Capsule())
|
||||||
|
.overlay(
|
||||||
|
Capsule()
|
||||||
|
.stroke(Color.secondary.opacity(0.2), lineWidth: 0.5)
|
||||||
|
)
|
||||||
|
.foregroundColor(themeManager.accentColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolbarItem(placement: .navigationBarLeading) {
|
||||||
|
if selectedClimbType != nil || selectedGym != nil {
|
||||||
|
Button(action: {
|
||||||
|
selectedClimbType = nil
|
||||||
|
selectedGym = nil
|
||||||
|
}) {
|
||||||
|
Text("Reset")
|
||||||
|
.font(.subheadline)
|
||||||
|
.fontWeight(.medium)
|
||||||
|
.padding(.horizontal, 16)
|
||||||
|
.padding(.vertical, 6)
|
||||||
|
.background(.ultraThinMaterial)
|
||||||
|
.clipShape(Capsule())
|
||||||
|
.overlay(
|
||||||
|
Capsule()
|
||||||
|
.stroke(Color.secondary.opacity(0.2), lineWidth: 0.5)
|
||||||
|
)
|
||||||
|
.foregroundColor(.red)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
ProblemsView()
|
ProblemsView()
|
||||||
.environmentObject(ClimbingDataManager.preview)
|
.environmentObject(ClimbingDataManager.preview)
|
||||||
|
|||||||
Reference in New Issue
Block a user