From 8e301a4f2418b0c43edb699103123c22d94f1ad4 Mon Sep 17 00:00:00 2001 From: Raz Date: Mon, 9 Sep 2024 13:30:11 +0200 Subject: [PATCH] update tournament search feature --- .../Data/Federal/FederalTournament.swift | 15 +- .../Federal/FederalTournamentHolder.swift | 1 + PadelClub/Data/Tournament.swift | 10 + .../ViewModel/FederalDataViewModel.swift | 28 +- .../GenericDestinationPickerView.swift | 3 + .../Navigation/Agenda/ActivityView.swift | 352 ++++++++++-------- .../Agenda/TournamentLookUpView.swift | 256 +++---------- .../Views/Shared/TournamentFilterView.swift | 20 + 8 files changed, 319 insertions(+), 366 deletions(-) diff --git a/PadelClub/Data/Federal/FederalTournament.swift b/PadelClub/Data/Federal/FederalTournament.swift index bd7e342..0cce922 100644 --- a/PadelClub/Data/Federal/FederalTournament.swift +++ b/PadelClub/Data/Federal/FederalTournament.swift @@ -7,10 +7,23 @@ import Foundation import CoreLocation import LeStorage -enum DayPeriod { +enum DayPeriod: CaseIterable, Identifiable { + var id: Self { self } + case all case weekend case week + + func localizedDayPeriodLabel() -> String { + switch self { + case .all: + return "n'importe" + case .week: + return "la semaine" + case .weekend: + return "le week-end" + } + } } // MARK: - FederalTournament diff --git a/PadelClub/Data/Federal/FederalTournamentHolder.swift b/PadelClub/Data/Federal/FederalTournamentHolder.swift index c5181a2..b2e3890 100644 --- a/PadelClub/Data/Federal/FederalTournamentHolder.swift +++ b/PadelClub/Data/Federal/FederalTournamentHolder.swift @@ -16,6 +16,7 @@ protocol FederalTournamentHolder { func clubLabel() -> String func subtitleLabel() -> String var dayDuration: Int { get } + var dayPeriod: DayPeriod { get } } extension FederalTournamentHolder { diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index a3aa857..abb008c 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -2134,6 +2134,16 @@ extension Tournament: FederalTournamentHolder { self ] } + + var dayPeriod: DayPeriod { + let day = startDate.get(.weekday) + switch day { + case 2...6: + return .week + default: + return .weekend + } + } } extension Tournament: TournamentBuildHolder { diff --git a/PadelClub/ViewModel/FederalDataViewModel.swift b/PadelClub/ViewModel/FederalDataViewModel.swift index 0c3b349..e83dc5b 100644 --- a/PadelClub/ViewModel/FederalDataViewModel.swift +++ b/PadelClub/ViewModel/FederalDataViewModel.swift @@ -20,7 +20,9 @@ class FederalDataViewModel { var selectedClubs: Set = Set() var id: UUID = UUID() var searchAttemptCount: Int = 0 - + var dayDuration: Int? + var dayPeriod: DayPeriod = .all + func filterStatus() -> String { var labels: [String] = [] labels.append(contentsOf: levels.map { $0.localizedLabel() }) @@ -32,6 +34,12 @@ class FederalDataViewModel { } labels.append(contentsOf: clubNames) + if dayPeriod != .all { + labels.append(dayPeriod.localizedDayPeriodLabel()) + } + if let dayDuration { + labels.append("max " + dayDuration.formatted() + " jour" + dayDuration.pluralSuffix) + } return labels.joined(separator: ", ") } @@ -56,11 +64,13 @@ class FederalDataViewModel { categories.removeAll() ageCategories.removeAll() selectedClubs.removeAll() + dayPeriod = .all + dayDuration = nil id = UUID() } func areFiltersEnabled() -> Bool { - (levels.isEmpty && categories.isEmpty && ageCategories.isEmpty && selectedClubs.isEmpty) == false + (levels.isEmpty && categories.isEmpty && ageCategories.isEmpty && selectedClubs.isEmpty && dayPeriod == .all && dayDuration == nil) == false } var filteredFederalTournaments: [FederalTournamentHolder] { @@ -80,6 +90,10 @@ class FederalDataViewModel { (ageCategories.isEmpty || tournament.tournaments.anySatisfy({ ageCategories.contains($0.age) })) && (selectedClubs.isEmpty || selectedClubs.contains(tournament.codeClub!)) + && + (dayPeriod == .all || (dayPeriod != .all && dayPeriod == tournament.dayPeriod)) + && + (dayDuration == nil || (dayDuration != nil && dayDuration == tournament.dayDuration)) }) } @@ -90,7 +104,11 @@ class FederalDataViewModel { (categories.isEmpty || categories.contains(tournament.category)) && (ageCategories.isEmpty || ageCategories.contains(tournament.age)) - + && + (dayPeriod == .all || (dayPeriod != .all && dayPeriod == tournament.dayPeriod)) + && + (dayDuration == nil || (dayDuration != nil && dayDuration == tournament.dayDuration)) + if let codeClub = tournament.club()?.code { return firstPart && (selectedClubs.isEmpty || selectedClubs.contains(codeClub)) } else { @@ -106,6 +124,10 @@ class FederalDataViewModel { (ageCategories.isEmpty || ageCategories.contains(build.age)) && (selectedClubs.isEmpty || selectedClubs.contains(tournament.codeClub!)) + && + (dayPeriod == .all || (dayPeriod != .all && dayPeriod == tournament.dayPeriod)) + && + (dayDuration == nil || (dayDuration != nil && dayDuration == tournament.dayDuration)) } func gatherTournaments(clubs: [Club], startDate: Date, endDate: Date? = nil) async throws { diff --git a/PadelClub/Views/Components/GenericDestinationPickerView.swift b/PadelClub/Views/Components/GenericDestinationPickerView.swift index 7002dc9..a7f4871 100644 --- a/PadelClub/Views/Components/GenericDestinationPickerView.swift +++ b/PadelClub/Views/Components/GenericDestinationPickerView.swift @@ -23,6 +23,7 @@ struct GenericDestinationPickerView: } label: { Image(systemName: "wrench.and.screwdriver") .foregroundColor(selectedDestination == nil ? .white : .black) + .contentShape(Capsule()) } .padding() .background { @@ -41,9 +42,11 @@ struct GenericDestinationPickerView: if let systemImage = destination.systemImage() { Image(systemName: systemImage) .foregroundStyle(selectedDestination?.id == destination.id ? .white : .black) + .contentShape(Capsule()) } else { Text(destination.selectionLabel(index: index)) .foregroundStyle(selectedDestination?.id == destination.id ? .white : .black) + .contentShape(Capsule()) } } .padding() diff --git a/PadelClub/Views/Navigation/Agenda/ActivityView.swift b/PadelClub/Views/Navigation/Agenda/ActivityView.swift index 41d96d6..e6085f7 100644 --- a/PadelClub/Views/Navigation/Agenda/ActivityView.swift +++ b/PadelClub/Views/Navigation/Agenda/ActivityView.swift @@ -84,39 +84,26 @@ struct ActivityView: View { .buttonBorderShape(.capsule) } - @ViewBuilder - func _listView() -> some View { - switch navigation.agendaDestination! { - case .activity: - List { - EventListView(tournaments: runningTournaments, sortAscending: true) - } - case .history: - List { - EventListView(tournaments: endedTournaments, sortAscending: false) - } - case .tenup: - List { - EventListView(tournaments: federalDataViewModel.federalTournaments, sortAscending: true) - .id(uuid) - } - case .around: - List { - EventListView(tournaments: federalDataViewModel.searchedFederalTournaments, sortAscending: true) - .id(uuid) - } - } - } - - var body: some View { @Bindable var navigation = navigation NavigationStack(path: $navigation.path) { VStack(spacing: 0) { GenericDestinationPickerView(selectedDestination: $navigation.agendaDestination, destinations: AgendaDestination.allCases, nilDestinationIsValid: false) - _listView() - .environment(\.viewStyle, viewStyle) + List { + switch navigation.agendaDestination! { + case .activity: + EventListView(tournaments: runningTournaments, sortAscending: true) + case .history: + EventListView(tournaments: endedTournaments, sortAscending: false) + case .tenup: + EventListView(tournaments: federalDataViewModel.federalTournaments, sortAscending: true) + .id(uuid) + case .around: + EventListView(tournaments: federalDataViewModel.searchedFederalTournaments, sortAscending: true) + } + } + .environment(\.viewStyle, viewStyle) .environment(federalDataViewModel) .overlay { if let error, navigation.agendaDestination == .tenup { @@ -142,10 +129,14 @@ struct ActivityView: View { } description: { Text("Aucun tournoi ne correspond aux fitres que vous avez choisis : \(federalDataViewModel.filterStatus())") } actions: { - RowButtonView("modifier vos filtres") { + FooterButtonView("supprimer vos filtres") { federalDataViewModel.removeFilters() } .padding(.horizontal) + FooterButtonView("modifier vos filtres") { + presentFilterView = true + } + .padding(.horizontal) } } else { _dataEmptyView() @@ -153,166 +144,213 @@ struct ActivityView: View { } } } - //.searchable(text: $searchText) - .onAppear { presentToolbar = true } - .onDisappear { presentToolbar = false } - .sheet(isPresented: $displaySearchView) { - NavigationStack { - TournamentLookUpView() - .environment(federalDataViewModel) - } + } + //.searchable(text: $searchText) + .onAppear { presentToolbar = true } + .onDisappear { presentToolbar = false } + .refreshable { + if navigation.agendaDestination == .tenup { + federalDataViewModel.federalTournaments.removeAll() + NetworkFederalService.shared.formId = "" + _gatherFederalTournaments() } - .sheet(item: $newTournament) { tournament in - EventCreationView(tournaments: [tournament], selectedClub: federalDataViewModel.selectedClub()) - .environment(navigation) - .tint(.master) + } + .task { + if navigation.agendaDestination == .tenup + && dataStore.user.hasTenupClubs() == true + && federalDataViewModel.federalTournaments.isEmpty { + _gatherFederalTournaments() } - .refreshable { - if navigation.agendaDestination == .tenup { - federalDataViewModel.federalTournaments.removeAll() - NetworkFederalService.shared.formId = "" - _gatherFederalTournaments() - } + } + .onChange(of: navigation.agendaDestination) { + if tournaments.isEmpty, viewStyle == .calendar { + viewStyle = .list } - .task { - if navigation.agendaDestination == .tenup - && dataStore.user.hasTenupClubs() == true - && federalDataViewModel.federalTournaments.isEmpty { - _gatherFederalTournaments() - } + + if navigation.agendaDestination == .tenup + && dataStore.user.hasTenupClubs() == true + && federalDataViewModel.federalTournaments.isEmpty { + _gatherFederalTournaments() } - .onChange(of: navigation.agendaDestination) { - if navigation.agendaDestination == .tenup - && dataStore.user.hasTenupClubs() == true - && federalDataViewModel.federalTournaments.isEmpty { - _gatherFederalTournaments() + } + .onChange(of: presentFilterView, { old, new in + if old == true, new == false { //closing filter view + if tournaments.isEmpty, viewStyle == .calendar { + viewStyle = .list } } - .toolbar { - ToolbarItemGroup(placement: .topBarLeading) { - Button { - switch viewStyle { - case .list: - viewStyle = .calendar - case .calendar: - viewStyle = .list - } - } label: { - Image(systemName: "calendar.circle") - .resizable() - .scaledToFit() - .frame(minHeight: 28) - } - .symbolVariant(viewStyle == .calendar ? .fill : .none) - - Button { - presentFilterView.toggle() - } label: { - Image(systemName: "line.3.horizontal.decrease.circle") - .resizable() - .scaledToFit() - .frame(minHeight: 28) + }) + .toolbarTitleDisplayMode(.large) + .navigationTitle(TabDestination.activity.title) + .navigationDestination(for: Tournament.self) { tournament in + TournamentView(tournament: tournament) + } + .toolbar { + ToolbarItemGroup(placement: .topBarLeading) { + Button { + switch viewStyle { + case .list: + viewStyle = .calendar + case .calendar: + viewStyle = .list } - .symbolVariant(federalDataViewModel.areFiltersEnabled() ? .fill : .none) - - _pasteView() + } label: { + Image(systemName: "calendar.circle") + .resizable() + .scaledToFit() + .frame(minHeight: 32) } - - ToolbarItem(placement: .topBarTrailing) { - Button { - newTournament = Tournament.newEmptyInstance() - - } label: { - Image(systemName: "plus.circle.fill") - .resizable() - .scaledToFit() - .frame(minHeight: 28) - } + .symbolVariant(viewStyle == .calendar ? .fill : .none) + + Button { + presentFilterView.toggle() + } label: { + Image(systemName: "line.3.horizontal.decrease.circle") + .resizable() + .scaledToFit() + .frame(minHeight: 32) } + .symbolVariant(federalDataViewModel.areFiltersEnabled() ? .fill : .none) - if presentToolbar { - if navigation.agendaDestination == .around, federalDataViewModel.searchedFederalTournaments.isEmpty == false { - let filteredSearchedFederalTournaments = federalDataViewModel.filteredSearchedFederalTournaments - - let status : String = filteredSearchedFederalTournaments.count.formatted() + " tournoi" + filteredSearchedFederalTournaments.count.pluralSuffix - - ToolbarItem(placement: .bottomBar) { - VStack { - Text(status) - FooterButtonView("modifier les critères de recherche") { + _pasteView() + } + + ToolbarItem(placement: .topBarTrailing) { + Button { + newTournament = Tournament.newEmptyInstance() + + } label: { + Image(systemName: "plus.circle.fill") + .resizable() + .scaledToFit() + .frame(minHeight: 32) + } + } + + if presentToolbar, tournaments.isEmpty == false { + ToolbarItemGroup(placement: .bottomBar) { + VStack(spacing: 0) { + let searchStatus = _searchStatus() + if searchStatus.isEmpty == false { + Text(_searchStatus()) + .font(.footnote) + .foregroundStyle(.secondary) + } + + HStack { + if navigation.agendaDestination == .around { + FooterButtonView("modifier votre recherche") { displaySearchView = true } + + if federalDataViewModel.areFiltersEnabled() { + Text("ou") + } + } + + if federalDataViewModel.areFiltersEnabled() { + FooterButtonView(_filterButtonTitle()) { + presentFilterView = true + } + } - .font(.footnote) - } - } else if federalDataViewModel.areFiltersEnabled() { - ToolbarItem(placement: .status) { - Text(federalDataViewModel.filterStatus()) } + .padding(.bottom, 8) } } } - .navigationTitle(TabDestination.activity.title) - .navigationDestination(for: Tournament.self) { tournament in - TournamentView(tournament: tournament) - } - .sheet(isPresented: $presentFilterView) { - TournamentFilterView(federalDataViewModel: federalDataViewModel) - .environment(navigation) - .tint(.master) - } - .sheet(isPresented: $presentClubSearchView, onDismiss: { - if dataStore.user.hasTenupClubs() == true { - federalDataViewModel.federalTournaments.removeAll() - navigation.agendaDestination = .tenup - } - }) { - ClubImportView() - .tint(.master) + } + .sheet(isPresented: $presentFilterView) { + TournamentFilterView(federalDataViewModel: federalDataViewModel) + .environment(navigation) + .tint(.master) + } + .sheet(isPresented: $presentClubSearchView, onDismiss: { + if dataStore.user.hasTenupClubs() == true { + federalDataViewModel.federalTournaments.removeAll() + navigation.agendaDestination = .tenup } + }) { + ClubImportView() + .tint(.master) } - } - .sheet(item: $quickAccessScreen) { screen in - switch screen { - case .inscription(let pasteString): + .sheet(isPresented: $displaySearchView) { NavigationStack { - List { - Section { - Text(pasteString) - } header: { - Text("Contenu du presse-papier") - } - - Section { - ForEach(getRunningTournaments()) { tournament in - NavigationLink { - AddTeamView(tournament: tournament, pasteString: pasteString, editedTeam: nil) - } label: { - VStack(alignment: .leading) { - Text(tournament.tournamentTitle()) - Text(tournament.formattedDate()).foregroundStyle(.secondary) + TournamentLookUpView() + .environment(federalDataViewModel) + } + } + .sheet(item: $newTournament) { tournament in + EventCreationView(tournaments: [tournament], selectedClub: federalDataViewModel.selectedClub()) + .environment(navigation) + .tint(.master) + } + .sheet(item: $quickAccessScreen) { screen in + switch screen { + case .inscription(let pasteString): + NavigationStack { + List { + Section { + Text(pasteString) + } header: { + Text("Contenu du presse-papier") + } + + Section { + ForEach(getRunningTournaments()) { tournament in + NavigationLink { + AddTeamView(tournament: tournament, pasteString: pasteString, editedTeam: nil) + } label: { + VStack(alignment: .leading) { + Text(tournament.tournamentTitle()) + Text(tournament.formattedDate()).foregroundStyle(.secondary) + } } } + } header: { + Text("À coller dans la liste d'inscription") } - } header: { - Text("À coller dans la liste d'inscription") } - } - .toolbar { - ToolbarItem(placement: .topBarLeading) { - Button("Fermer") { - self.quickAccessScreen = nil + .toolbar { + ToolbarItem(placement: .topBarLeading) { + Button("Fermer") { + self.quickAccessScreen = nil + } } } + .navigationTitle("Choix du tournoi") + .navigationBarTitleDisplayMode(.inline) + .toolbarBackground(.visible, for: .navigationBar) } - .navigationTitle("Choix du tournoi") - .navigationBarTitleDisplayMode(.inline) - .toolbarBackground(.visible, for: .navigationBar) } } } } + private func _searchStatus() -> String { + var searchStatus : [String] = [] + if navigation.agendaDestination == .around, federalDataViewModel.searchedFederalTournaments.isEmpty == false { + let filteredSearchedFederalTournaments = federalDataViewModel.filteredSearchedFederalTournaments + + let status : String = filteredSearchedFederalTournaments.count.formatted() + " tournoi" + filteredSearchedFederalTournaments.count.pluralSuffix + searchStatus.append(status) + } + + if federalDataViewModel.areFiltersEnabled(), tournaments.isEmpty == false { + searchStatus.append(federalDataViewModel.filterStatus()) + } + + return searchStatus.joined(separator: " ") + } + + private func _filterButtonTitle() -> String { + var prefix = "modifier " + if navigation.agendaDestination == .around, federalDataViewModel.searchedFederalTournaments.isEmpty == false { + prefix = "" + } + return prefix + "vos filtres" + } + private func _gatherFederalTournaments() { isGatheringFederalTournaments = true Task { @@ -422,7 +460,7 @@ struct ActivityView: View { } description: { Text("Aucun tournoi ne correspond aux critères sélectionnés.") } actions: { - RowButtonView("Modifier vos critères de recherche") { + FooterButtonView("modifier vos critères de recherche") { displaySearchView = true } .padding() diff --git a/PadelClub/Views/Navigation/Agenda/TournamentLookUpView.swift b/PadelClub/Views/Navigation/Agenda/TournamentLookUpView.swift index 188f08e..f622231 100644 --- a/PadelClub/Views/Navigation/Agenda/TournamentLookUpView.swift +++ b/PadelClub/Views/Navigation/Agenda/TournamentLookUpView.swift @@ -15,10 +15,6 @@ struct TournamentLookUpView: View { @Environment(\.dismiss) private var dismiss @State private var searchField: String = "" - @State private var sectionedTournaments: [String: [FederalTournament]] = [:] - @State private var dayPeriod: DayPeriod = .all - @State private var duration: Int = 3 - @State var page: Int = 0 @State var total: Int = 0 @@ -32,56 +28,49 @@ struct TournamentLookUpView: View { @AppStorage("lastCity") private var city: String = "" @State private var ligue: String = "" @AppStorage("lastDistance") private var distance: Double = 30 - @AppStorage("lastSortingOption") private var sortingOption: String = "_DIST_" + @AppStorage("lastSortingOption") private var sortingOption: String = "dateDebut+asc" @State private var requestedToGetAllPages: Bool = false @AppStorage("lastNationalCup") private var nationalCup: Bool = false @State private var revealSearchParameters: Bool = true - @State private var searchScope = FederalTournamentSearchScope.all + @State private var presentAlert: Bool = false var tournaments: [FederalTournament] { federalDataViewModel.searchedFederalTournaments } - - func canShowTournament(_ tournament: FederalTournament) -> Bool { - guard tournament.dayDuration <= duration else { return false } - guard (tournament.dayPeriod == dayPeriod && dayPeriod != .all) || dayPeriod == .all else { return false } - if searchField.isEmpty { - return true - } else { - return tournament.validForSearch(searchField, scope: searchScope) - } - } - + var body: some View { List { searchParametersView - - if tournaments.isEmpty == false && tournaments.count < total && total >= 200 && requestedToGetAllPages == false { - Section { - Text("Il y a beacoup de tournois pour cette requête, êtes-vous sûr de vouloir tout récupérer ? Sinon essayez d'affiner votre recherche.") - Button { - requestedToGetAllPages = true - page += 1 - searching = true - Task { - await getNewPage() - searching = false - buildSectionedData() - } - } label: { - Label("Tout voir", systemImage: "arrow.down.circle") - } + } + .alert("Attention", isPresented: $presentAlert, actions: { + Button { + presentAlert = false + requestedToGetAllPages = true + page += 1 + searching = true + Task { + await getNewPage() + searching = false + dismiss() } + } label: { + Label("Tout voir", systemImage: "arrow.down.circle") } - } + Button("Annuler") { + revealSearchParameters = true + presentAlert = false + } + }, message: { + Text("Il y a beacoup de tournois pour cette requête, êtes-vous sûr de vouloir tout récupérer ? Sinon essayez d'affiner votre recherche.") + }) .toolbarBackground(.visible, for: .bottomBar, .navigationBar) .navigationTitle("Chercher un tournoi") .navigationBarTitleDisplayMode(.inline) - .onChange(of: locationManager.city, perform: { newValue in - if let newValue, city.isEmpty { + .onChange(of: locationManager.city) { + if let newValue = locationManager.city, city.isEmpty { city = newValue } - }) + } .toolbarTitleDisplayMode(.large) .toolbar { ToolbarItem(placement: .bottomBar) { @@ -90,14 +79,6 @@ struct TournamentLookUpView: View { runSearch() } .disabled(searching) - } else if searchField.isEmpty == false && searchScope != .all { - let count = _totalVisibleEpreuves().count - VStack { - Text(searchField) - .foregroundStyle(.secondary) - Text(count.formatted() + " tournoi" + count.pluralSuffix) - } - .font(.caption) } else if searching { HStack(spacing: 20) { Spacer() @@ -109,25 +90,13 @@ struct TournamentLookUpView: View { } Spacer() } - } else { - let count = _totalVisibleEpreuves().count - Text(count.formatted() + " tournoi" + count.pluralSuffix) - .font(.caption) } } ToolbarItem(placement: .topBarTrailing) { Menu { +#if DEBUG if tournaments.isEmpty == false { Section { - let preview = SharePreview(Text("Ma recherche de tournois"), icon: Image("PadelClub_logo_fondclair_transparent")) - ShareLink(item: renderedImage ?? Image(systemName: "photo"), preview: preview) { - if renderedImage == nil { - ProgressView() - } else { - Label("Par image (20max)", systemImage: "square.and.arrow.up") - .labelStyle(.titleAndIcon) - } - } ShareLink(item: pastedTournaments) { Label("Par texte", systemImage: "square.and.arrow.up") .labelStyle(.titleAndIcon) @@ -141,7 +110,9 @@ struct TournamentLookUpView: View { } } Divider() - Button { +#endif + + Button(role: .destructive) { tournamentLevels = Set() tournamentCategories = Set() city = "" @@ -150,8 +121,10 @@ struct TournamentLookUpView: View { distance = 30 startDate = Date() endDate = Calendar.current.date(byAdding: .month, value: 3, to: Date())! - sortingOption = "_DIST_" + sortingOption = "dateDebut+asc" revealSearchParameters = true + federalDataViewModel.searchedFederalTournaments = [] + federalDataViewModel.searchAttemptCount = 0 } label: { Text("Ré-initialiser la recherche") } @@ -169,75 +142,6 @@ struct TournamentLookUpView: View { Set(tournaments.map { $0.japMessage }).joined(separator: "\n") } - private func isTypeLookedAfter(_ type: any TournamentBuildHolder) -> Bool { - if levels.contains(where: { level in - type.level == level - }) || levels.isEmpty { - if categories.contains(where: { category in - type.category == category - }) || categories.isEmpty { - - return true - } - } - return false - } - - - @Environment(\.displayScale) var displayScale - @State private var renderedImage: Image? - - @MainActor - func render() { - let renderer = ImageRenderer(content: tournamentsView) - renderer.scale = displayScale - renderer.isOpaque = true - if let uiImage = renderer.uiImage { - renderedImage = Image(uiImage: uiImage) - } - } - - @ViewBuilder - private var tournamentsView: some View { - let tournaments = tournaments.prefix(20) - VStack { - ForEach(tournaments.indices, id: \.self) { tournamentIndex in - let tournament = tournaments[tournamentIndex] - HStack(alignment: .center) { - VStack(alignment: .leading) { - Text(tournament.libelle ?? "unknown").font(.headline) - if let club = tournament.nomClub { - Text(club) - .font(.footnote) - .lineLimit(1) - } - } - Spacer() - VStack(alignment: .trailing) { - if let startDate = tournament.dateDebut { - Text(startDate.monthYearFormatted) - HStack { - Text(startDate.formatted(.dateTime.weekday())) - Text(startDate.formatted(.dateTime.day())).font(.largeTitle) - } - } - if let distance = tournament.distanceEnMetres { - let measurement = Measurement(value: distance / 1000, unit: UnitLength.kilometers) - Text(measurement.formatted()).font(.caption) - } - } - } - .padding() - .foregroundColor(Color.black) - .background { - tournamentIndex%2 == 0 ? Color.mint : Color.cyan - } - } - } - .padding() - } - - private var clubsFound: [String] { Set(tournaments.compactMap { $0.nomClub }).sorted() } @@ -253,18 +157,17 @@ struct TournamentLookUpView: View { federalDataViewModel.searchedFederalTournaments = [] searching = true requestedToGetAllPages = false - renderedImage = nil federalDataViewModel.searchAttemptCount += 1 Task { await getNewPage() searching = false - dismiss() + if tournaments.isEmpty == false && tournaments.count < total && total >= 200 && requestedToGetAllPages == false { + presentAlert = true + } else { + dismiss() + } } } - - func buildSectionedData() { - sectionedTournaments = FederalTournament.sectionedData(from: tournaments) - } private var distanceLimit: Measurement { distanceLimit(distance: distance) @@ -308,15 +211,9 @@ struct TournamentLookUpView: View { print("count", count, total, tournaments.count, page) total = count - if renderedImage == nil { - render() - } if tournaments.count < count && page < total / 30 { if total < 200 || requestedToGetAllPages { page += 1 - await MainActor.run() { - buildSectionedData() - } await getNewPage() } } else { @@ -361,12 +258,10 @@ struct TournamentLookUpView: View { city = "" locationManager.location = nil locationManager.city = nil - dayPeriod = .all - duration = 3 distance = 30 startDate = Date() endDate = Calendar.current.date(byAdding: .month, value: 3, to: Date())! - sortingOption = "_DIST_" + sortingOption = "dateDebut+asc" revealSearchParameters = true } label: { Label("Ré-initialiser la recherche", systemImage: "xmark.circle") @@ -376,27 +271,27 @@ struct TournamentLookUpView: View { @ViewBuilder var searchParametersView: some View { + @Bindable var federalDataViewModel = federalDataViewModel Section { DatePicker("Début", selection: $startDate, displayedComponents: .date) DatePicker("Fin", selection: $endDate, displayedComponents: .date) - - Picker(selection: $duration) { - Text("Aucune").tag(7) - Text(1.formatted()).tag(1) - Text(2.formatted()).tag(2) - Text(3.formatted()).tag(3) + Picker(selection: $federalDataViewModel.dayDuration) { + Text("aucune").tag(nil as Int?) + Text(1.formatted()).tag(1 as Int?) + Text(2.formatted()).tag(2 as Int?) + Text(3.formatted()).tag(3 as Int?) } label: { Text("Durée max (en jours)") } - - Picker(selection: $dayPeriod) { - Text("N'importe").tag(DayPeriod.all) - Text("le weekend").tag(DayPeriod.weekend) - Text("la semaine").tag(DayPeriod.week) + + Picker(selection: $federalDataViewModel.dayPeriod) { + ForEach(DayPeriod.allCases) { + Text($0.localizedDayPeriodLabel()).tag($0) + } } label: { Text("En semaine ou week-end") } - + HStack { TextField("Ville", text: $city) if let city = locationManager.city { @@ -585,53 +480,4 @@ struct TournamentLookUpView: View { return "Distance" } } - - - func _totalVisibleTournaments(_ date: Date? = nil) -> [FederalTournament] { - if let date { - if let tournaments = sectionedTournaments[URL.importDateFormatter.string(from: date)] { - let allTournaments = tournaments.filter({ canShowTournament($0) }).filter({ tournament in - if tournament.tournaments.count > 1 { - return tournament.tournaments.anySatisfy { isTypeLookedAfter($0) } - } else { - return true - } - }) - return allTournaments - } else { - return [] - } - } else { - let allTournaments = sectionedTournaments.values.flatMap({ $0 }).filter({ canShowTournament($0) }).filter({ tournament in - if tournament.tournaments.count > 1 { - return tournament.tournaments.anySatisfy { isTypeLookedAfter($0) } - } else { - return true - } - }) - return allTournaments - } - } - - func _totalVisibleEpreuves(_ date: Date? = nil) -> [any TournamentBuildHolder] { - if let date { - if let tournaments = sectionedTournaments[URL.importDateFormatter.string(from: date)] { - let allTournaments = tournaments - .filter({ canShowTournament($0) }) - .compactMap({ $0.tournaments }) - .flatMap({ $0 }) - .filter({ isTypeLookedAfter($0) }) - return allTournaments - } else { - return [] - } - } else { - let allTournaments = sectionedTournaments.values.flatMap({ $0 }) - .filter({ canShowTournament($0) }) - .compactMap({ $0.tournaments }) - .flatMap({ $0 }) - .filter({ isTypeLookedAfter($0) }) - return allTournaments - } - } } diff --git a/PadelClub/Views/Shared/TournamentFilterView.swift b/PadelClub/Views/Shared/TournamentFilterView.swift index e72377c..a312db0 100644 --- a/PadelClub/Views/Shared/TournamentFilterView.swift +++ b/PadelClub/Views/Shared/TournamentFilterView.swift @@ -28,6 +28,26 @@ struct TournamentFilterView: View { var body: some View { NavigationView { Form { + + Section { + Picker(selection: $federalDataViewModel.dayDuration) { + Text("aucune").tag(nil as Int?) + Text(1.formatted()).tag(1 as Int?) + Text(2.formatted()).tag(2 as Int?) + Text(3.formatted()).tag(3 as Int?) + } label: { + Text("Durée max (en jours)") + } + + Picker(selection: $federalDataViewModel.dayPeriod) { + ForEach(DayPeriod.allCases) { + Text($0.localizedDayPeriodLabel()).tag($0) + } + } label: { + Text("En semaine ou week-end") + } + } + Section { ForEach(TournamentLevel.allCases) { level in LabeledContent {