From 0a816b20e15b4178fdaba52fa60952ec29549d0c Mon Sep 17 00:00:00 2001 From: Raz Date: Wed, 25 Sep 2024 11:27:39 +0200 Subject: [PATCH] minor updates --- PadelClub/Data/PlayerRegistration.swift | 5 ++ PadelClub/Data/Tournament.swift | 4 +- PadelClub/PadelClubApp.swift | 2 +- PadelClub/Utils/LocationManager.swift | 15 ++++- PadelClub/Utils/Tips.swift | 23 +++++++ PadelClub/ViewModel/AgendaDestination.swift | 10 ++++ PadelClub/ViewModel/Selectable.swift | 33 ++++++++++ .../GenericDestinationPickerView.swift | 4 ++ .../Agenda/TournamentLookUpView.swift | 60 +++++++++++-------- .../Views/Planning/PlanningSettingsView.swift | 2 +- .../Views/Tournament/TournamentView.swift | 2 +- 11 files changed, 128 insertions(+), 32 deletions(-) diff --git a/PadelClub/Data/PlayerRegistration.swift b/PadelClub/Data/PlayerRegistration.swift index da256cf..28c1cff 100644 --- a/PadelClub/Data/PlayerRegistration.swift +++ b/PadelClub/Data/PlayerRegistration.swift @@ -283,6 +283,11 @@ final class PlayerRegistration: ModelObject, Storable { } func setComputedRank(in tournament: Tournament) { + if tournament.isAnimation() { + computedRank = rank ?? 0 + return + } + let currentRank = rank ?? tournament.unrankValue(for: isMalePlayer()) ?? 70_000 switch tournament.tournamentCategory { case .men: diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index deb4f64..bff7b30 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -1430,7 +1430,9 @@ defer { func formattedDate(_ displayStyle: DisplayStyle = .wide) -> String { switch displayStyle { - case .wide, .title: + case .title: + startDate.formatted(.dateTime.weekday(.abbreviated).day().month(.abbreviated).year()) + case .wide: startDate.formatted(date: Date.FormatStyle.DateStyle.complete, time: Date.FormatStyle.TimeStyle.omitted) case .short: startDate.formatted(date: .numeric, time: .omitted) diff --git a/PadelClub/PadelClubApp.swift b/PadelClub/PadelClubApp.swift index befb5d3..ccf8660 100644 --- a/PadelClub/PadelClubApp.swift +++ b/PadelClub/PadelClubApp.swift @@ -100,7 +100,7 @@ print("Running in Release mode") //try? Tips.resetDatastore() try? Tips.configure([ - .displayFrequency(.immediate), + .displayFrequency(.daily), .datastoreLocation(.applicationDefault) ]) } diff --git a/PadelClub/Utils/LocationManager.swift b/PadelClub/Utils/LocationManager.swift index 3961bf6..0af0e36 100644 --- a/PadelClub/Utils/LocationManager.swift +++ b/PadelClub/Utils/LocationManager.swift @@ -16,7 +16,18 @@ class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate { @Published var postalCode: String? @Published var requestStarted: Bool = false @Published var userReadableCityOrZipcode: String = "" - @Published var lastError: Error? = nil + @Published var lastError: LocalizedError? = nil + + enum LocationError: LocalizedError { + case unknownError(error: Error) + + var errorDescription: String? { + switch self { + case .unknownError(let error): + return "Padel Club n'a pas réussi à vous localiser." + } + } + } override init() { super.init() @@ -49,7 +60,7 @@ class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate { func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { print("locationManager didFailWithError", error) requestStarted = false - self.lastError = error + self.lastError = LocationError.unknownError(error: error) } func geocodeCity(cityOrZipcode: String, completion: @escaping (_ placemark: [CLPlacemark]?, _ error: Error?) -> Void) { diff --git a/PadelClub/Utils/Tips.swift b/PadelClub/Utils/Tips.swift index 1366b39..bb136dd 100644 --- a/PadelClub/Utils/Tips.swift +++ b/PadelClub/Utils/Tips.swift @@ -549,6 +549,29 @@ struct TeamsExportTip: Tip { } } +struct PlayerTournamentSearchTip: Tip { + var title: Text { + Text("Cherchez un tournoi autour de vous !") + } + + var message: Text? { + Text("Padel Club facilite la recherche de tournois et l'inscription !") + } + + var image: Image? { + Image(systemName: "trophy.circle") + } + + var actions: [Action] { + Action(id: ActionKey.selectAction.rawValue, title: "Éssayer") + } + + enum ActionKey: String { + case selectAction = "selectAction" + } + +} + struct TipStyleModifier: ViewModifier { @Environment(\.colorScheme) var colorScheme var tint: Color? diff --git a/PadelClub/ViewModel/AgendaDestination.swift b/PadelClub/ViewModel/AgendaDestination.swift index abe2126..96aff9d 100644 --- a/PadelClub/ViewModel/AgendaDestination.swift +++ b/PadelClub/ViewModel/AgendaDestination.swift @@ -7,6 +7,7 @@ import Foundation import SwiftUI +import TipKit enum AgendaDestination: Int, CaseIterable, Identifiable, Selectable, Equatable { var id: Int { self.rawValue } @@ -33,6 +34,15 @@ enum AgendaDestination: Int, CaseIterable, Identifiable, Selectable, Equatable { } } + func associatedTip() -> (any Tip)? { + switch self { + case .around: + return PlayerTournamentSearchTip() + default: + return nil + } + } + func selectionLabel(index: Int) -> String { localizedTitleKey } diff --git a/PadelClub/ViewModel/Selectable.swift b/PadelClub/ViewModel/Selectable.swift index 6734828..66309f9 100644 --- a/PadelClub/ViewModel/Selectable.swift +++ b/PadelClub/ViewModel/Selectable.swift @@ -7,6 +7,7 @@ import Foundation import SwiftUI +import TipKit protocol Selectable { func selectionLabel(index: Int) -> String @@ -15,9 +16,14 @@ protocol Selectable { func badgeValueColor() -> Color? func displayImageIfValueZero() -> Bool func systemImage() -> String? + func associatedTip() -> (any Tip)? } extension Selectable { + func associatedTip() -> (any Tip)? { + return nil + } + func systemImage() -> String? { return nil } @@ -54,3 +60,30 @@ enum Badge { } } } + +struct SelectionTipViewModifier: ViewModifier { + let selectable: Selectable + let action: () -> Void + func body(content: Content) -> some View { + if let tip = selectable.associatedTip() { + if #available(iOS 18.0, *) { + content + .popoverTip(tip, arrowEdge: .top) { _ in + action() + tip.invalidate(reason: .tipClosed) + } + } else { + content + } + } else { + content + } + } +} + +extension View { + func selectableTipViewModifier(selectable: Selectable, action: @escaping () -> Void) -> some View { + modifier(SelectionTipViewModifier(selectable: selectable, action: action)) + } +} + diff --git a/PadelClub/Views/Components/GenericDestinationPickerView.swift b/PadelClub/Views/Components/GenericDestinationPickerView.swift index a7f4871..59079c5 100644 --- a/PadelClub/Views/Components/GenericDestinationPickerView.swift +++ b/PadelClub/Views/Components/GenericDestinationPickerView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import TipKit struct GenericDestinationPickerView: View { @EnvironmentObject var dataStore: DataStore @@ -49,6 +50,9 @@ struct GenericDestinationPickerView: .contentShape(Capsule()) } } + .selectableTipViewModifier(selectable: destination) { + selectedDestination = destination + } .padding() .background { Capsule() diff --git a/PadelClub/Views/Navigation/Agenda/TournamentLookUpView.swift b/PadelClub/Views/Navigation/Agenda/TournamentLookUpView.swift index ede4f2d..2426cf5 100644 --- a/PadelClub/Views/Navigation/Agenda/TournamentLookUpView.swift +++ b/PadelClub/Views/Navigation/Agenda/TournamentLookUpView.swift @@ -23,15 +23,44 @@ struct TournamentLookUpView: View { @State private var requestedToGetAllPages: Bool = false @State private var revealSearchParameters: Bool = true @State private var presentAlert: Bool = false + @State private var confirmSearch: Bool = false var tournaments: [FederalTournament] { federalDataViewModel.searchedFederalTournaments } + + var showLastError: Binding { + Binding { + locationManager.lastError != nil + } set: { value in + if value == false { + locationManager.lastError = nil + } + } + + } var body: some View { List { searchParametersView } + .alert(isPresented: showLastError, error: locationManager.lastError as? LocationManager.LocationError, actions: { + Button("Annuler", role: .cancel) { + + } + }) + .confirmationDialog("Attention", isPresented: $confirmSearch, titleVisibility: .visible) { + Button("Cherchez quand même") { + requestedToGetAllPages = true + runSearch() + } + + Button("Annuler", role: .cancel) { + + } + } message: { + Text("Aucune ville n'a été indiqué, il est préférable de se localiser ou d'indiquer une ville pour réduire le nombre de résultat.") + } .alert("Attention", isPresented: $presentAlert, actions: { Button { presentAlert = false @@ -70,7 +99,11 @@ struct TournamentLookUpView: View { ToolbarItem(placement: .bottomBar) { if revealSearchParameters { FooterButtonView("Lancer la recherche") { - runSearch() + if dataStore.appSettings.city.isEmpty { + confirmSearch = true + } else { + runSearch() + } } .disabled(searching) } else if searching { @@ -230,31 +263,6 @@ struct TournamentLookUpView: View { } } - @ViewBuilder - var searchContollerView: some View { - Section { - Button { - runSearch() - } label: { - HStack { - Label("Chercher un tournoi", systemImage: "magnifyingglass") - if searching { - Spacer() - ProgressView() - } - } - } - Button { - dataStore.appSettings.resetSearch() - locationManager.location = nil - locationManager.city = nil - revealSearchParameters = true - } label: { - Label("Ré-initialiser la recherche", systemImage: "xmark.circle") - } - } - } - @ViewBuilder var searchParametersView: some View { @Bindable var appSettings = dataStore.appSettings diff --git a/PadelClub/Views/Planning/PlanningSettingsView.swift b/PadelClub/Views/Planning/PlanningSettingsView.swift index 1286f4d..645faf0 100644 --- a/PadelClub/Views/Planning/PlanningSettingsView.swift +++ b/PadelClub/Views/Planning/PlanningSettingsView.swift @@ -52,7 +52,7 @@ struct PlanningSettingsView: View { Section { DatePicker(selection: $tournament.startDate) { - Text(tournament.startDate.formatted(.dateTime.weekday(.wide)).capitalized) + Text(tournament.startDate.formatted(.dateTime.weekday(.wide)).capitalized).lineLimit(1) } LabeledContent { StepperView(count: $tournament.dayDuration, minimum: 1) diff --git a/PadelClub/Views/Tournament/TournamentView.swift b/PadelClub/Views/Tournament/TournamentView.swift index 7dbe23b..e12017a 100644 --- a/PadelClub/Views/Tournament/TournamentView.swift +++ b/PadelClub/Views/Tournament/TournamentView.swift @@ -141,7 +141,7 @@ struct TournamentView: View { ToolbarItem(placement: .principal) { VStack(spacing: -4.0) { Text(tournament.tournamentTitle(.title)).font(.headline) - Text(tournament.formattedDate()) + Text(tournament.formattedDate(.title)) .font(.subheadline).foregroundStyle(.secondary) } .popoverTip(tournamentSelectionTip)