fix search stuff

sync2
Raz 1 year ago
parent b2f38febc8
commit 6f929c44cf
  1. 4
      PadelClub.xcodeproj/project.pbxproj
  2. 23
      PadelClub/Data/PlayerRegistration.swift
  3. 1
      PadelClub/Data/TeamRegistration.swift
  4. 2
      PadelClub/Views/Player/Components/PlayerPopoverView.swift
  5. 2
      PadelClub/Views/Shared/SelectablePlayerListView.swift
  6. 17
      PadelClub/Views/Team/Components/TeamWeightView.swift
  7. 69
      PadelClub/Views/Tournament/Screen/AddTeamView.swift

@ -3295,7 +3295,7 @@
CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 9; CURRENT_PROJECT_VERSION = 12;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
@ -3337,7 +3337,7 @@
CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 9; CURRENT_PROJECT_VERSION = 12;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6; DEVELOPMENT_TEAM = BQ3Y44M3Q6;

@ -73,6 +73,7 @@ final class PlayerRegistration: ModelObject, Storable {
self.ligueName = importedPlayer.ligueName self.ligueName = importedPlayer.ligueName
self.assimilation = importedPlayer.assimilation self.assimilation = importedPlayer.assimilation
self.source = .frenchFederation self.source = .frenchFederation
self.birthdate = importedPlayer.birthYear
} }
internal init?(federalData: [String], sex: Int, sexUnknown: Bool) { internal init?(federalData: [String], sex: Int, sexUnknown: Bool) {
@ -123,19 +124,17 @@ final class PlayerRegistration: ModelObject, Storable {
var computedAge: Int? { var computedAge: Int? {
if let birthdate { if let birthdate {
let components = birthdate.components(separatedBy: "/") let components = birthdate.components(separatedBy: "/")
if components.count == 3 { if let age = components.last, let ageInt = Int(age) {
if let age = components.last, let ageInt = Int(age) { let year = Calendar.current.getSportAge()
let year = Calendar.current.getSportAge()
if age.count == 2 { //si l'année est sur 2 chiffres dans le fichier
if age.count == 2 { //si l'année est sur 2 chiffres dans le fichier if ageInt < 23 {
if ageInt < 23 { return year - 2000 - ageInt
return year - 2000 - ageInt } else {
} else { return year - 2000 + 100 - ageInt
return year - 2000 + 100 - ageInt
}
} else { //si l'année est représenté sur 4 chiffres
return year - ageInt
} }
} else { //si l'année est représenté sur 4 chiffres
return year - ageInt
} }
} }
} }

@ -242,6 +242,7 @@ final class TeamRegistration: ModelObject, Storable {
let arrayOfIds : [String] = unsortedPlayers().compactMap({ $0.licenceId?.strippedLicense?.canonicalVersion }) let arrayOfIds : [String] = unsortedPlayers().compactMap({ $0.licenceId?.strippedLicense?.canonicalVersion })
let ids : Set<String> = Set<String>(arrayOfIds.sorted()) let ids : Set<String> = Set<String>(arrayOfIds.sorted())
let searchedIds = Set<String>(playerLicenses.compactMap({ $0?.strippedLicense?.canonicalVersion }).sorted()) let searchedIds = Set<String>(playerLicenses.compactMap({ $0?.strippedLicense?.canonicalVersion }).sorted())
if ids.isEmpty || searchedIds.isEmpty { return false }
return ids.hashValue == searchedIds.hashValue return ids.hashValue == searchedIds.hashValue
} }

@ -31,7 +31,7 @@ struct PlayerPopoverView: View {
@State private var source: String? @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 { if let source {
let words = source.components(separatedBy: .whitespaces) let words = source.components(separatedBy: .whitespaces)
if words.isEmpty == false { if words.isEmpty == false {

@ -1033,7 +1033,7 @@ struct MySearchView: View {
Text(searchViewModel.contentUnavailableMessage) Text(searchViewModel.contentUnavailableMessage)
} actions: { } actions: {
RowButtonView("Lancer une nouvelle recherche") { RowButtonView("Nouvelle recherche") {
searchViewModel.debouncableText = "" searchViewModel.debouncableText = ""
} }
.padding() .padding()

@ -8,17 +8,16 @@
import SwiftUI import SwiftUI
struct TeamWeightView: View { struct TeamWeightView: View {
var team: TeamRegistration @EnvironmentObject var dataStore: DataStore
let team: TeamRegistration
var teamPosition: TeamPosition? = nil 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) { var displayWeight: Bool {
self.team = team team.tournamentObject()?.hideWeight() == false
self.teamPosition = teamPosition
let tournament = team.tournamentObject()
self.teamIndex = tournament?.indexOf(team: team)
self.displayWeight = tournament?.hideWeight() == false
} }
var body: some View { var body: some View {

@ -7,16 +7,15 @@
import SwiftUI import SwiftUI
import LeStorage import LeStorage
import CoreData
struct AddTeamView: View { struct AddTeamView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(\.dismiss) var dismiss @Environment(\.dismiss) var dismiss
@FetchRequest( private var fetchRequest: FetchRequest<ImportedPlayer>
sortDescriptors: [], private var fetchPlayers: FetchedResults<ImportedPlayer> { fetchRequest.wrappedValue }
animation: .default)
private var fetchPlayers: FetchedResults<ImportedPlayer>
var tournament: Tournament var tournament: Tournament
var cancelShouldDismiss: Bool = false var cancelShouldDismiss: Bool = false
@ -69,14 +68,19 @@ struct AddTeamView: View {
_createdPlayerIds = .init(wrappedValue: createdPlayerIds) _createdPlayerIds = .init(wrappedValue: createdPlayerIds)
} }
let request: NSFetchRequest<ImportedPlayer> = ImportedPlayer.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(keyPath: \ImportedPlayer.rank, ascending: true)]
request.fetchLimit = 1000
if let pasteString { if let pasteString {
_pasteString = .init(wrappedValue: pasteString) _pasteString = .init(wrappedValue: pasteString)
_fetchPlayers = FetchRequest<ImportedPlayer>(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) _autoSelect = .init(wrappedValue: true)
_editableTextField = .init(wrappedValue: pasteString) _editableTextField = .init(wrappedValue: pasteString)
_textHeight = .init(wrappedValue: Self._calculateHeight(text: pasteString)) _textHeight = .init(wrappedValue: Self._calculateHeight(text: pasteString))
cancelShouldDismiss = true cancelShouldDismiss = true
} }
fetchRequest = FetchRequest(fetchRequest: request, animation: .default)
} }
var body: some View { var body: some View {
@ -138,12 +142,9 @@ struct AddTeamView: View {
} message: { } message: {
Text("Cette équipe existe déjà dans votre liste d'inscription.") Text("Cette équipe existe déjà dans votre liste d'inscription.")
} }
.sheet(isPresented: $presentPlayerSearch, onDismiss: { .sheet(isPresented: $presentPlayerSearch) {
selectionSearchField = nil
}) {
NavigationStack { NavigationStack {
SelectablePlayerListView(allowSelection: -1, searchField: searchField, filterOption: _filterOption(), showFemaleInMaleAssimilation: tournament.tournamentCategory.showFemaleInMaleAssimilation) { players in SelectablePlayerListView(allowSelection: -1, searchField: searchField, filterOption: _filterOption(), showFemaleInMaleAssimilation: tournament.tournamentCategory.showFemaleInMaleAssimilation) { players in
selectionSearchField = nil
players.forEach { player in players.forEach { player in
let newPlayer = PlayerRegistration(importedPlayer: player) let newPlayer = PlayerRegistration(importedPlayer: player)
newPlayer.setComputedRank(in: tournament) newPlayer.setComputedRank(in: tournament)
@ -151,15 +152,24 @@ struct AddTeamView: View {
createdPlayerIds.insert(newPlayer.id) createdPlayerIds.insert(newPlayer.id)
} }
} contentUnavailableAction: { searchViewModel in } contentUnavailableAction: { searchViewModel in
selectionSearchField = searchViewModel.searchText
presentPlayerSearch = false presentPlayerSearch = false
presentPlayerCreation = true selectionSearchField = searchViewModel.searchText
} }
} }
.tint(.master) .tint(.master)
} }
.sheet(isPresented: $presentPlayerCreation) { .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) p.setComputedRank(in: tournament)
createdPlayers.insert(p) createdPlayers.insert(p)
createdPlayerIds.insert(p.id) createdPlayerIds.insert(p.id)
@ -235,7 +245,11 @@ struct AddTeamView: View {
Section { Section {
RowButtonView("Créer un non classé / non licencié") { RowButtonView("Créer un non classé / non licencié") {
presentPlayerCreation = true if let pasteString, pasteString.isEmpty == false {
selectionSearchField = pasteString
} else {
presentPlayerCreation = true
}
} }
} footer: { } 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.") 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 { private func _filterOption() -> PlayerFilterOption {
return tournament.tournamentCategory.playerFilterOption return tournament.tournamentCategory.playerFilterOption
} }
private func _searchSource() -> String? {
selectionSearchField ?? pasteString
}
private func _currentSelection() -> Set<PlayerRegistration> { private func _currentSelection() -> Set<PlayerRegistration> {
var currentSelection = Set<PlayerRegistration>() var currentSelection = Set<PlayerRegistration>()
createdPlayerIds.compactMap { id in createdPlayerIds.compactMap { id in
@ -437,9 +447,11 @@ struct AddTeamView: View {
VStack(alignment: .leading, spacing: 0) { VStack(alignment: .leading, spacing: 0) {
if let player = unsortedPlayers.first(where: { ($0.licenceId == p.licenceId && $0.licenceId != nil) }), editedTeam?.includes(player: player) == false { 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() Text("Déjà inscrit !").foregroundStyle(.logoRed).bold()
} else if tournament.isPlayerAgeInadequate(player: p) { }
if tournament.isPlayerAgeInadequate(player: p) {
Text("Âge invalide !").foregroundStyle(.logoRed).bold() Text("Âge invalide !").foregroundStyle(.logoRed).bold()
} else if tournament.isPlayerRankInadequate(player: p) { }
if tournament.isPlayerRankInadequate(player: p) {
Text("Trop bien classé !").foregroundStyle(.logoRed).bold() Text("Trop bien classé !").foregroundStyle(.logoRed).bold()
} }
PlayerView(player: p).tag(p.id) PlayerView(player: p).tag(p.id)
@ -450,9 +462,11 @@ struct AddTeamView: View {
VStack(alignment: .leading, spacing: 0) { VStack(alignment: .leading, spacing: 0) {
if let pasteString, pasteString.isEmpty == false, unsortedPlayers.first(where: { $0.licenceId == p.license }) != nil { if let pasteString, pasteString.isEmpty == false, unsortedPlayers.first(where: { $0.licenceId == p.license }) != nil {
Text("Déjà inscrit !").foregroundStyle(.logoRed).bold() Text("Déjà inscrit !").foregroundStyle(.logoRed).bold()
} else if tournament.isPlayerAgeInadequate(player: p) { }
if tournament.isPlayerAgeInadequate(player: p) {
Text("Âge invalide !").foregroundStyle(.logoRed).bold() Text("Âge invalide !").foregroundStyle(.logoRed).bold()
} else if tournament.isPlayerRankInadequate(player: p) { }
if tournament.isPlayerRankInadequate(player: p) {
Text("Trop bien classé !").foregroundStyle(.logoRed).bold() Text("Trop bien classé !").foregroundStyle(.logoRed).bold()
} }
ImportedPlayerView(player: p).tag(p.license!) 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.") 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: { } actions: {
RowButtonView("Créer un joueur non classé") { RowButtonView("Créer un joueur non classé") {
presentPlayerCreation = true selectionSearchField = pasteString
} }
RowButtonView("Chercher dans la base") { RowButtonView("Chercher dans la base") {
@ -584,16 +598,17 @@ struct AddTeamView: View {
@MainActor @MainActor
private func handlePasteString(_ first: String) { private func handlePasteString(_ first: String) {
if first.isEmpty == false { if first.isEmpty == false {
fetchPlayers.nsPredicate = SearchViewModel.pastePredicate(pasteField: first, mostRecentDate: SourceFileManager.shared.mostRecentDateAvailable, filterOption: _filterOption()) DispatchQueue.main.async {
fetchPlayers.nsSortDescriptors = [NSSortDescriptor(keyPath: \ImportedPlayer.rank, ascending: true)] fetchPlayers.nsPredicate = SearchViewModel.pastePredicate(pasteField: first, mostRecentDate: SourceFileManager.shared.mostRecentDateAvailable, filterOption: _filterOption())
autoSelect = true fetchPlayers.nsSortDescriptors = [NSSortDescriptor(keyPath: \ImportedPlayer.rank, ascending: true)]
autoSelect = true
}
} }
pasteString = first pasteString = first
editableTextField = first editableTextField = first
textHeight = Self._calculateHeight(text: first) textHeight = Self._calculateHeight(text: first)
} }
@ViewBuilder @ViewBuilder
private func _listOfPlayers(searchFilteredPlayers: [ImportedPlayer], pasteString: String) -> some View { private func _listOfPlayers(searchFilteredPlayers: [ImportedPlayer], pasteString: String) -> some View {
let sortedPlayers = _sortedPlayers(searchFilteredPlayers: searchFilteredPlayers, pasteString: pasteString) let sortedPlayers = _sortedPlayers(searchFilteredPlayers: searchFilteredPlayers, pasteString: pasteString)

Loading…
Cancel
Save