From 6f929c44cf0131064d07cd78d46b6ba8dc7a93a5 Mon Sep 17 00:00:00 2001 From: Raz Date: Sat, 28 Sep 2024 19:38:34 +0200 Subject: [PATCH] fix search stuff --- PadelClub.xcodeproj/project.pbxproj | 4 +- PadelClub/Data/PlayerRegistration.swift | 23 +++---- PadelClub/Data/TeamRegistration.swift | 1 + .../Player/Components/PlayerPopoverView.swift | 2 +- .../Shared/SelectablePlayerListView.swift | 2 +- .../Team/Components/TeamWeightView.swift | 17 +++-- .../Views/Tournament/Screen/AddTeamView.swift | 69 +++++++++++-------- 7 files changed, 66 insertions(+), 52 deletions(-) diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index 688bcbc..f7d304a 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -3295,7 +3295,7 @@ CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 12; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; @@ -3337,7 +3337,7 @@ CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 12; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_TEAM = BQ3Y44M3Q6; diff --git a/PadelClub/Data/PlayerRegistration.swift b/PadelClub/Data/PlayerRegistration.swift index 2e966ec..bb46b2d 100644 --- a/PadelClub/Data/PlayerRegistration.swift +++ b/PadelClub/Data/PlayerRegistration.swift @@ -73,6 +73,7 @@ final class PlayerRegistration: ModelObject, Storable { self.ligueName = importedPlayer.ligueName self.assimilation = importedPlayer.assimilation self.source = .frenchFederation + self.birthdate = importedPlayer.birthYear } internal init?(federalData: [String], sex: Int, sexUnknown: Bool) { @@ -123,19 +124,17 @@ final class PlayerRegistration: ModelObject, Storable { var computedAge: Int? { if let birthdate { let components = birthdate.components(separatedBy: "/") - if components.count == 3 { - if let age = components.last, let ageInt = Int(age) { - let year = Calendar.current.getSportAge() - - if age.count == 2 { //si l'année est sur 2 chiffres dans le fichier - if ageInt < 23 { - return year - 2000 - ageInt - } else { - return year - 2000 + 100 - ageInt - } - } else { //si l'année est représenté sur 4 chiffres - return year - ageInt + if let age = components.last, let ageInt = Int(age) { + let year = Calendar.current.getSportAge() + + if age.count == 2 { //si l'année est sur 2 chiffres dans le fichier + if ageInt < 23 { + return year - 2000 - ageInt + } else { + return year - 2000 + 100 - ageInt } + } else { //si l'année est représenté sur 4 chiffres + return year - ageInt } } } diff --git a/PadelClub/Data/TeamRegistration.swift b/PadelClub/Data/TeamRegistration.swift index 67a84e4..ea0f42d 100644 --- a/PadelClub/Data/TeamRegistration.swift +++ b/PadelClub/Data/TeamRegistration.swift @@ -242,6 +242,7 @@ final class TeamRegistration: ModelObject, Storable { let arrayOfIds : [String] = unsortedPlayers().compactMap({ $0.licenceId?.strippedLicense?.canonicalVersion }) let ids : Set = Set(arrayOfIds.sorted()) let searchedIds = Set(playerLicenses.compactMap({ $0?.strippedLicense?.canonicalVersion }).sorted()) + if ids.isEmpty || searchedIds.isEmpty { return false } return ids.hashValue == searchedIds.hashValue } diff --git a/PadelClub/Views/Player/Components/PlayerPopoverView.swift b/PadelClub/Views/Player/Components/PlayerPopoverView.swift index 3e8ddcf..9bd893b 100644 --- a/PadelClub/Views/Player/Components/PlayerPopoverView.swift +++ b/PadelClub/Views/Player/Components/PlayerPopoverView.swift @@ -31,7 +31,7 @@ struct PlayerPopoverView: View { @State private var source: String? - init(source: String?, sex: Int, requiredField: [PlayerCreationField] = [], creationCompletionHandler: @escaping (PlayerRegistration) -> Void) { + init(source: String? = nil, sex: Int, requiredField: [PlayerCreationField] = [], creationCompletionHandler: @escaping (PlayerRegistration) -> Void) { if let source { let words = source.components(separatedBy: .whitespaces) if words.isEmpty == false { diff --git a/PadelClub/Views/Shared/SelectablePlayerListView.swift b/PadelClub/Views/Shared/SelectablePlayerListView.swift index 8ecd8cc..c555a1a 100644 --- a/PadelClub/Views/Shared/SelectablePlayerListView.swift +++ b/PadelClub/Views/Shared/SelectablePlayerListView.swift @@ -1033,7 +1033,7 @@ struct MySearchView: View { Text(searchViewModel.contentUnavailableMessage) } actions: { - RowButtonView("Lancer une nouvelle recherche") { + RowButtonView("Nouvelle recherche") { searchViewModel.debouncableText = "" } .padding() diff --git a/PadelClub/Views/Team/Components/TeamWeightView.swift b/PadelClub/Views/Team/Components/TeamWeightView.swift index e74226c..f19b6e6 100644 --- a/PadelClub/Views/Team/Components/TeamWeightView.swift +++ b/PadelClub/Views/Team/Components/TeamWeightView.swift @@ -8,17 +8,16 @@ import SwiftUI struct TeamWeightView: View { - var team: TeamRegistration + @EnvironmentObject var dataStore: DataStore + let team: TeamRegistration var teamPosition: TeamPosition? = nil - var teamIndex: Int? - var displayWeight: Bool = true + + var teamIndex: Int? { + team.tournamentObject()?.indexOf(team: team) + } - init(team: TeamRegistration, teamPosition: TeamPosition? = nil) { - self.team = team - self.teamPosition = teamPosition - let tournament = team.tournamentObject() - self.teamIndex = tournament?.indexOf(team: team) - self.displayWeight = tournament?.hideWeight() == false + var displayWeight: Bool { + team.tournamentObject()?.hideWeight() == false } var body: some View { diff --git a/PadelClub/Views/Tournament/Screen/AddTeamView.swift b/PadelClub/Views/Tournament/Screen/AddTeamView.swift index e7d65b1..518c8a7 100644 --- a/PadelClub/Views/Tournament/Screen/AddTeamView.swift +++ b/PadelClub/Views/Tournament/Screen/AddTeamView.swift @@ -7,16 +7,15 @@ import SwiftUI import LeStorage +import CoreData struct AddTeamView: View { @EnvironmentObject var dataStore: DataStore @Environment(\.dismiss) var dismiss - @FetchRequest( - sortDescriptors: [], - animation: .default) - private var fetchPlayers: FetchedResults + private var fetchRequest: FetchRequest + private var fetchPlayers: FetchedResults { fetchRequest.wrappedValue } var tournament: Tournament var cancelShouldDismiss: Bool = false @@ -69,14 +68,19 @@ struct AddTeamView: View { _createdPlayerIds = .init(wrappedValue: createdPlayerIds) } + let request: NSFetchRequest = ImportedPlayer.fetchRequest() + request.sortDescriptors = [NSSortDescriptor(keyPath: \ImportedPlayer.rank, ascending: true)] + request.fetchLimit = 1000 if let pasteString { _pasteString = .init(wrappedValue: pasteString) - _fetchPlayers = FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \ImportedPlayer.rank, ascending: true)], predicate: SearchViewModel.pastePredicate(pasteField: pasteString, mostRecentDate: tournament.rankSourceDate, filterOption: tournament.tournamentCategory.playerFilterOption)) + request.predicate = SearchViewModel.pastePredicate(pasteField: pasteString, mostRecentDate: tournament.rankSourceDate, filterOption: tournament.tournamentCategory.playerFilterOption) _autoSelect = .init(wrappedValue: true) _editableTextField = .init(wrappedValue: pasteString) _textHeight = .init(wrappedValue: Self._calculateHeight(text: pasteString)) cancelShouldDismiss = true } + + fetchRequest = FetchRequest(fetchRequest: request, animation: .default) } var body: some View { @@ -138,12 +142,9 @@ struct AddTeamView: View { } message: { Text("Cette équipe existe déjà dans votre liste d'inscription.") } - .sheet(isPresented: $presentPlayerSearch, onDismiss: { - selectionSearchField = nil - }) { + .sheet(isPresented: $presentPlayerSearch) { NavigationStack { SelectablePlayerListView(allowSelection: -1, searchField: searchField, filterOption: _filterOption(), showFemaleInMaleAssimilation: tournament.tournamentCategory.showFemaleInMaleAssimilation) { players in - selectionSearchField = nil players.forEach { player in let newPlayer = PlayerRegistration(importedPlayer: player) newPlayer.setComputedRank(in: tournament) @@ -151,15 +152,24 @@ struct AddTeamView: View { createdPlayerIds.insert(newPlayer.id) } } contentUnavailableAction: { searchViewModel in - selectionSearchField = searchViewModel.searchText presentPlayerSearch = false - presentPlayerCreation = true + selectionSearchField = searchViewModel.searchText } } .tint(.master) } .sheet(isPresented: $presentPlayerCreation) { - PlayerPopoverView(source: _searchSource(), sex: _addPlayerSex()) { p in + PlayerPopoverView(sex: _addPlayerSex()) { p in + p.setComputedRank(in: tournament) + createdPlayers.insert(p) + createdPlayerIds.insert(p.id) + } + .tint(.master) + } + .sheet(item: $selectionSearchField, onDismiss: { + selectionSearchField = nil + }) { selectionSearchField in + PlayerPopoverView(source: selectionSearchField, sex: _addPlayerSex()) { p in p.setComputedRank(in: tournament) createdPlayers.insert(p) createdPlayerIds.insert(p.id) @@ -235,7 +245,11 @@ struct AddTeamView: View { Section { RowButtonView("Créer un non classé / non licencié") { - presentPlayerCreation = true + if let pasteString, pasteString.isEmpty == false { + selectionSearchField = pasteString + } else { + presentPlayerCreation = true + } } } footer: { Text("Si le joueur n'a pas encore de licence ou n'a pas encore participé à une compétition, vous pouvez le créer vous-même.") @@ -257,11 +271,7 @@ struct AddTeamView: View { private func _filterOption() -> PlayerFilterOption { return tournament.tournamentCategory.playerFilterOption } - - private func _searchSource() -> String? { - selectionSearchField ?? pasteString - } - + private func _currentSelection() -> Set { var currentSelection = Set() createdPlayerIds.compactMap { id in @@ -437,9 +447,11 @@ struct AddTeamView: View { VStack(alignment: .leading, spacing: 0) { if let player = unsortedPlayers.first(where: { ($0.licenceId == p.licenceId && $0.licenceId != nil) }), editedTeam?.includes(player: player) == false { Text("Déjà inscrit !").foregroundStyle(.logoRed).bold() - } else if tournament.isPlayerAgeInadequate(player: p) { + } + if tournament.isPlayerAgeInadequate(player: p) { Text("Âge invalide !").foregroundStyle(.logoRed).bold() - } else if tournament.isPlayerRankInadequate(player: p) { + } + if tournament.isPlayerRankInadequate(player: p) { Text("Trop bien classé !").foregroundStyle(.logoRed).bold() } PlayerView(player: p).tag(p.id) @@ -450,9 +462,11 @@ struct AddTeamView: View { VStack(alignment: .leading, spacing: 0) { if let pasteString, pasteString.isEmpty == false, unsortedPlayers.first(where: { $0.licenceId == p.license }) != nil { Text("Déjà inscrit !").foregroundStyle(.logoRed).bold() - } else if tournament.isPlayerAgeInadequate(player: p) { + } + if tournament.isPlayerAgeInadequate(player: p) { Text("Âge invalide !").foregroundStyle(.logoRed).bold() - } else if tournament.isPlayerRankInadequate(player: p) { + } + if tournament.isPlayerRankInadequate(player: p) { Text("Trop bien classé !").foregroundStyle(.logoRed).bold() } ImportedPlayerView(player: p).tag(p.license!) @@ -515,7 +529,7 @@ struct AddTeamView: View { Text("Aucun joueur classé n'a été trouvé dans ce message. Attention, si un joueur n'a pas joué de tournoi dans les 12 derniers, Padel Club ne pourra pas le trouver.") } actions: { RowButtonView("Créer un joueur non classé") { - presentPlayerCreation = true + selectionSearchField = pasteString } RowButtonView("Chercher dans la base") { @@ -584,16 +598,17 @@ struct AddTeamView: View { @MainActor private func handlePasteString(_ first: String) { if first.isEmpty == false { - fetchPlayers.nsPredicate = SearchViewModel.pastePredicate(pasteField: first, mostRecentDate: SourceFileManager.shared.mostRecentDateAvailable, filterOption: _filterOption()) - fetchPlayers.nsSortDescriptors = [NSSortDescriptor(keyPath: \ImportedPlayer.rank, ascending: true)] - autoSelect = true + DispatchQueue.main.async { + fetchPlayers.nsPredicate = SearchViewModel.pastePredicate(pasteField: first, mostRecentDate: SourceFileManager.shared.mostRecentDateAvailable, filterOption: _filterOption()) + fetchPlayers.nsSortDescriptors = [NSSortDescriptor(keyPath: \ImportedPlayer.rank, ascending: true)] + autoSelect = true + } } pasteString = first editableTextField = first textHeight = Self._calculateHeight(text: first) } - @ViewBuilder private func _listOfPlayers(searchFilteredPlayers: [ImportedPlayer], pasteString: String) -> some View { let sortedPlayers = _sortedPlayers(searchFilteredPlayers: searchFilteredPlayers, pasteString: pasteString)