fix issue with search

sync_v2
Raz 8 months ago
parent b27cdfa1e6
commit f83cb5f251
  1. 393
      PadelClub/ViewModel/SearchViewModel.swift
  2. 4
      PadelClub/Views/Tournament/Screen/AddTeamView.swift

@ -14,7 +14,7 @@ class DebouncableViewModel: ObservableObject {
class SearchViewModel: ObservableObject, Identifiable { class SearchViewModel: ObservableObject, Identifiable {
let id: UUID = UUID() let id: UUID = UUID()
var allowSelection : Int = 0 var allowSelection: Int = 0
var codeClub: String? = nil var codeClub: String? = nil
var clubName: String? = nil var clubName: String? = nil
var ligueName: String? = nil var ligueName: String? = nil
@ -67,7 +67,9 @@ class SearchViewModel: ObservableObject, Identifiable {
var contentUnavailableMessage: String { var contentUnavailableMessage: String {
var message = ["Vérifiez l'ortographe ou lancez une nouvelle recherche."] var message = ["Vérifiez l'ortographe ou lancez une nouvelle recherche."]
if tokens.isEmpty { if tokens.isEmpty {
message.append("Il est possible que cette personne n'est joué aucun tournoi depuis les 12 derniers mois, dans ce cas, Padel Club ne pourra pas le trouver.") message.append(
"Il est possible que cette personne n'est joué aucun tournoi depuis les 12 derniers mois, dans ce cas, Padel Club ne pourra pas le trouver."
)
} }
return message.joined(separator: "\n") return message.joined(separator: "\n")
} }
@ -79,13 +81,17 @@ class SearchViewModel: ObservableObject, Identifiable {
func getCodeClub() -> String? { func getCodeClub() -> String? {
if let codeClub { return codeClub } if let codeClub { return codeClub }
if let userCodeClub = DataStore.shared.user.currentPlayerData()?.clubCode { return userCodeClub } if let userCodeClub = DataStore.shared.user.currentPlayerData()?.clubCode {
return userCodeClub
}
return nil return nil
} }
func getLigueName() -> String? { func getLigueName() -> String? {
if let ligueName { return ligueName } if let ligueName { return ligueName }
if let userLigueName = DataStore.shared.user.currentPlayerData()?.ligueName { return userLigueName } if let userLigueName = DataStore.shared.user.currentPlayerData()?.ligueName {
return userLigueName
}
return nil return nil
} }
@ -102,24 +108,30 @@ class SearchViewModel: ObservableObject, Identifiable {
return true return true
} }
return dataSet == .national && searchText.isEmpty == false && (tokens.isEmpty == true && hideAssimilation == false && selectedAgeCategory == .unlisted) return dataSet == .national && searchText.isEmpty == false
&& (tokens.isEmpty == true && hideAssimilation == false
&& selectedAgeCategory == .unlisted)
} }
func showIndex() -> Bool { func showIndex() -> Bool {
if dataSet == .national { if dataSet == .national {
if searchText.isEmpty == false && (tokens.isEmpty == true && hideAssimilation == false && selectedAgeCategory == .unlisted) { if searchText.isEmpty == false
&& (tokens.isEmpty == true && hideAssimilation == false
&& selectedAgeCategory == .unlisted)
{
return false return false
} else { } else {
return isFiltering() return isFiltering()
} }
} }
if (dataSet == .ligue) { return isFiltering() } if dataSet == .ligue { return isFiltering() }
if filterOption == .all { return isFiltering() } if filterOption == .all { return isFiltering() }
return true return true
} }
func isFiltering() -> Bool { func isFiltering() -> Bool {
searchText.isEmpty == false || tokens.isEmpty == false || hideAssimilation || selectedAgeCategory != .unlisted searchText.isEmpty == false || tokens.isEmpty == false || hideAssimilation
|| selectedAgeCategory != .unlisted
} }
func prompt(forDataSet: DataSet) -> String { func prompt(forDataSet: DataSet) -> String {
@ -155,41 +167,117 @@ class SearchViewModel: ObservableObject, Identifiable {
} }
func words() -> [String] { func words() -> [String] {
return searchText.canonicalVersionWithPunctuation.trimmed.components(separatedBy: .whitespaces) return searchText.canonicalVersionWithPunctuation.trimmed.components(
separatedBy: .whitespaces)
} }
func wordsPredicates() -> NSPredicate? { func wordsPredicates() -> NSPredicate? {
let words = words().filter({ $0.isEmpty == false }) let words = words().filter({ $0.isEmpty == false })
// Handle special case of hyphenated words
let hyphenatedWords = searchText.components(separatedBy: .whitespaces)
.filter { $0.contains("-") }
var predicates: [NSPredicate] = []
// Add predicates for hyphenated words
for word in hyphenatedWords {
predicates.append(NSPredicate(format: "lastName CONTAINS[cd] %@", word))
let parts = word.components(separatedBy: "-")
for part in parts where part.count > 1 {
predicates.append(NSPredicate(format: "lastName CONTAINS[cd] %@", part))
}
}
// Regular words processing
switch words.count { switch words.count {
case 2: case 2:
let predicates = [ predicates.append(contentsOf: [
NSPredicate(format: "canonicalLastName beginswith[cd] %@ AND canonicalFirstName beginswith[cd] %@", words[0], words[1]), NSPredicate(
NSPredicate(format: "canonicalLastName beginswith[cd] %@ AND canonicalFirstName beginswith[cd] %@", words[1], words[0]), format:
] "canonicalLastName CONTAINS[cd] %@ AND canonicalFirstName CONTAINS[cd] %@",
return NSCompoundPredicate(orPredicateWithSubpredicates: predicates) words[0], words[1]),
NSPredicate(
format:
"canonicalLastName CONTAINS[cd] %@ AND canonicalFirstName CONTAINS[cd] %@",
words[1], words[0]),
// For multi-word first names, try the two words as a first name
NSPredicate(
format: "canonicalFirstName CONTAINS[cd] %@", words.joined(separator: " ")),
])
case 3:
// Handle potential cases like "Jean Christophe CROS"
predicates.append(contentsOf: [
// First two words as first name, last as last name
NSPredicate(
format:
"canonicalFirstName CONTAINS[cd] %@ AND canonicalLastName CONTAINS[cd] %@",
words[0] + " " + words[1], words[2]),
// First as first name, last two as last name
NSPredicate(
format:
"canonicalFirstName CONTAINS[cd] %@ AND canonicalLastName CONTAINS[cd] %@",
words[0], words[1] + " " + words[2]),
// Last as first name, first two as last name
NSPredicate(
format:
"canonicalFirstName CONTAINS[cd] %@ AND canonicalLastName CONTAINS[cd] %@",
words[2], words[0] + " " + words[1]),
])
default: default:
return nil if words.count > 0 {
// For single word or many words, try matching against full name
predicates.append(
NSPredicate(
format: "canonicalFullName CONTAINS[cd] %@",
words.joined(separator: " ")))
}
} }
return predicates.isEmpty
? nil : NSCompoundPredicate(orPredicateWithSubpredicates: predicates)
} }
func searchTextPredicate() -> NSPredicate? { func searchTextPredicate() -> NSPredicate? {
var predicates : [NSPredicate] = [] var predicates: [NSPredicate] = []
let allowedCharacterSet = CharacterSet.alphanumerics.union(.whitespaces) let allowedCharacterSet = CharacterSet.alphanumerics.union(.whitespaces).union(
let canonicalVersionWithoutPunctuation = searchText.canonicalVersion.components(separatedBy: allowedCharacterSet.inverted).joined().trimmed CharacterSet(charactersIn: "-"))
let canonicalVersionWithoutPunctuation = searchText.canonicalVersion
.components(separatedBy: allowedCharacterSet.inverted)
.joined()
.trimmed
if canonicalVersionWithoutPunctuation.isEmpty == false { if canonicalVersionWithoutPunctuation.isEmpty == false {
let wordsPredicates = wordsPredicates() let wordsPredicates = wordsPredicates()
if let wordsPredicates { if let wordsPredicates {
predicates.append(wordsPredicates) predicates.append(wordsPredicates)
} else { } else {
predicates.append(NSPredicate(format: "license contains[cd] %@", canonicalVersionWithoutPunctuation)) predicates.append(
NSPredicate(
format: "license contains[cd] %@", canonicalVersionWithoutPunctuation))
} }
predicates.append(NSPredicate(format: "canonicalFullName contains[cd] %@", canonicalVersionWithoutPunctuation))
// Add match for full name
predicates.append(
NSPredicate(
format: "canonicalFullName contains[cd] %@", canonicalVersionWithoutPunctuation)
)
// Add pattern match for more flexible matching
let components = canonicalVersionWithoutPunctuation.split(separator: " ") let components = canonicalVersionWithoutPunctuation.split(separator: " ")
let pattern = components.joined(separator: ".*") let pattern = components.joined(separator: ".*")
let predicate = NSPredicate(format: "canonicalFullName MATCHES[c] %@", pattern) predicates.append(NSPredicate(format: "canonicalFullName MATCHES[c] %@", pattern))
predicates.append(predicate)
// Look for exact matches on first or last name
let words = canonicalVersionWithoutPunctuation.components(separatedBy: .whitespaces)
for word in words where word.count > 2 {
predicates.append(
NSPredicate(
format: "firstName CONTAINS[cd] %@ OR lastName CONTAINS[cd] %@", word, word)
)
}
} }
if predicates.isEmpty { if predicates.isEmpty {
return nil return nil
} }
@ -197,60 +285,83 @@ class SearchViewModel: ObservableObject, Identifiable {
} }
func orPredicate() -> NSPredicate? { func orPredicate() -> NSPredicate? {
var predicates : [NSPredicate] = [] var predicates: [NSPredicate] = []
let allowedCharacterSet = CharacterSet.alphanumerics.union(.whitespaces) let allowedCharacterSet = CharacterSet.alphanumerics.union(.whitespaces).union(
let canonicalVersionWithoutPunctuation = searchText.canonicalVersion.components(separatedBy: allowedCharacterSet.inverted).joined().trimmed CharacterSet(charactersIn: "-"))
let canonicalVersionWithoutPunctuation = searchText.canonicalVersion
.components(separatedBy: allowedCharacterSet.inverted)
.joined()
.trimmed
let canonicalVersionWithPunctuation = searchText.canonicalVersionWithPunctuation.trimmed let canonicalVersionWithPunctuation = searchText.canonicalVersionWithPunctuation.trimmed
if tokens.isEmpty { if tokens.isEmpty {
if shouldIncludeSearchTextPredicate(), canonicalVersionWithoutPunctuation.isEmpty == false { if shouldIncludeSearchTextPredicate(),
canonicalVersionWithoutPunctuation.isEmpty == false
{
if let searchTextPredicate = searchTextPredicate() { if let searchTextPredicate = searchTextPredicate() {
predicates.append(searchTextPredicate) predicates.append(searchTextPredicate)
} }
} }
} }
// Process tokens
for token in tokens { for token in tokens {
switch token { switch token {
case .ligue: case .ligue:
if canonicalVersionWithoutPunctuation.isEmpty { if canonicalVersionWithoutPunctuation.isEmpty {
predicates.append(NSPredicate(format: "ligueName == nil")) predicates.append(NSPredicate(format: "ligueName == nil"))
} else { } else {
predicates.append(NSPredicate(format: "ligueName contains[cd] %@", canonicalVersionWithoutPunctuation)) predicates.append(
NSPredicate(
format: "ligueName contains[cd] %@", canonicalVersionWithoutPunctuation)
)
} }
case .club: case .club:
if canonicalVersionWithoutPunctuation.isEmpty { if canonicalVersionWithoutPunctuation.isEmpty {
predicates.append(NSPredicate(format: "clubName == nil")) predicates.append(NSPredicate(format: "clubName == nil"))
} else { } else {
predicates.append(NSPredicate(format: "clubName contains[cd] %@", canonicalVersionWithoutPunctuation)) predicates.append(
NSPredicate(
format: "clubName contains[cd] %@", canonicalVersionWithoutPunctuation))
} }
case .rankMoreThan: case .rankMoreThan:
if canonicalVersionWithoutPunctuation.isEmpty || Int(canonicalVersionWithoutPunctuation) == 0 { if canonicalVersionWithoutPunctuation.isEmpty
|| Int(canonicalVersionWithoutPunctuation) == 0
{
predicates.append(NSPredicate(format: "rank == 0")) predicates.append(NSPredicate(format: "rank == 0"))
} else { } else {
predicates.append(NSPredicate(format: "rank >= %@", canonicalVersionWithoutPunctuation)) predicates.append(
NSPredicate(format: "rank >= %@", canonicalVersionWithoutPunctuation))
} }
case .rankLessThan: case .rankLessThan:
if canonicalVersionWithoutPunctuation.isEmpty || Int(canonicalVersionWithoutPunctuation) == 0 { if canonicalVersionWithoutPunctuation.isEmpty
|| Int(canonicalVersionWithoutPunctuation) == 0
{
predicates.append(NSPredicate(format: "rank == 0")) predicates.append(NSPredicate(format: "rank == 0"))
} else { } else {
predicates.append(NSPredicate(format: "rank <= %@", canonicalVersionWithoutPunctuation)) predicates.append(
NSPredicate(format: "rank <= %@", canonicalVersionWithoutPunctuation))
} }
case .rankBetween: case .rankBetween:
let values = canonicalVersionWithPunctuation.components(separatedBy: ",") let values = canonicalVersionWithPunctuation.components(separatedBy: ",")
if canonicalVersionWithPunctuation.isEmpty || values.count != 2 { if canonicalVersionWithPunctuation.isEmpty || values.count != 2 {
predicates.append(NSPredicate(format: "rank == 0")) predicates.append(NSPredicate(format: "rank == 0"))
} else { } else {
predicates.append(NSPredicate(format: "rank BETWEEN {%@,%@}", values.first!, values.last!)) predicates.append(
NSPredicate(format: "rank BETWEEN {%@,%@}", values.first!, values.last!))
} }
case .age: case .age:
if canonicalVersionWithoutPunctuation.isEmpty || Int(canonicalVersionWithoutPunctuation) == 0 { if canonicalVersionWithoutPunctuation.isEmpty
|| Int(canonicalVersionWithoutPunctuation) == 0
{
predicates.append(NSPredicate(format: "birthYear == 0")) predicates.append(NSPredicate(format: "birthYear == 0"))
} else if let birthYear = Int(canonicalVersionWithoutPunctuation) { } else if let birthYear = Int(canonicalVersionWithoutPunctuation) {
predicates.append(NSPredicate(format: "birthYear == %@", birthYear.formattedAsRawString())) predicates.append(
NSPredicate(format: "birthYear == %@", birthYear.formattedAsRawString()))
} }
} }
} }
if predicates.isEmpty { if predicates.isEmpty {
return nil return nil
} }
@ -258,14 +369,10 @@ class SearchViewModel: ObservableObject, Identifiable {
} }
func predicate() -> NSPredicate? { func predicate() -> NSPredicate? {
var predicates : [NSPredicate?] = [ var predicates: [NSPredicate?] = [
orPredicate(), orPredicate(),
filterOption == .male ? filterOption == .male ? NSPredicate(format: "male == YES") : nil,
NSPredicate(format: "male == YES") : filterOption == .female ? NSPredicate(format: "male == NO") : nil,
nil,
filterOption == .female ?
NSPredicate(format: "male == NO") :
nil,
] ]
if let mostRecentDate { if let mostRecentDate {
@ -279,10 +386,12 @@ class SearchViewModel: ObservableObject, Identifiable {
if selectedAgeCategory != .unlisted { if selectedAgeCategory != .unlisted {
let computedBirthYear = selectedAgeCategory.computedBirthYear() let computedBirthYear = selectedAgeCategory.computedBirthYear()
if let left = computedBirthYear.0 { if let left = computedBirthYear.0 {
predicates.append(NSPredicate(format: "birthYear >= %@", left.formattedAsRawString())) predicates.append(
NSPredicate(format: "birthYear >= %@", left.formattedAsRawString()))
} }
if let right = computedBirthYear.1 { if let right = computedBirthYear.1 {
predicates.append(NSPredicate(format: "birthYear <= %@", right.formattedAsRawString())) predicates.append(
NSPredicate(format: "birthYear <= %@", right.formattedAsRawString()))
} }
} }
@ -316,7 +425,6 @@ class SearchViewModel: ObservableObject, Identifiable {
return NSCompoundPredicate(andPredicateWithSubpredicates: predicates.compactMap({ $0 })) return NSCompoundPredicate(andPredicateWithSubpredicates: predicates.compactMap({ $0 }))
} }
func sortDescriptors() -> [SortDescriptor<ImportedPlayer>] { func sortDescriptors() -> [SortDescriptor<ImportedPlayer>] {
sortOption.sortDescriptors(ascending, dataSet: dataSet) sortOption.sortDescriptors(ascending, dataSet: dataSet)
} }
@ -347,18 +455,21 @@ class SearchViewModel: ObservableObject, Identifiable {
} }
// Create the NSPredicate for searching in the `lastName` field // Create the NSPredicate for searching in the `lastName` field
let predicate = NSPredicate(format: "lastName CONTAINS[cd] %@ OR lastName CONTAINS[cd] %@", lastName1, lastName2) let predicate = NSPredicate(
format: "lastName CONTAINS[cd] %@ OR lastName CONTAINS[cd] %@", lastName1, lastName2)
// Output the result // Output the result
//print("Generated Predicate: \(predicate)") //print("Generated Predicate: \(predicate)")
return predicate return predicate
} }
static func pastePredicate(
static func pastePredicate(pasteField: String, mostRecentDate: Date?, filterOption: PlayerFilterOption) -> NSPredicate? { pasteField: String, mostRecentDate: Date?, filterOption: PlayerFilterOption
) -> NSPredicate? {
var andPredicates = [NSPredicate]() var andPredicates = [NSPredicate]()
var orPredicates = [NSPredicate]() var orPredicates = [NSPredicate]()
// Check for license numbers
let matches = pasteField.licencesFound() let matches = pasteField.licencesFound()
let licensesPredicates = matches.map { NSPredicate(format: "license contains[cd] %@", $0) } let licensesPredicates = matches.map { NSPredicate(format: "license contains[cd] %@", $0) }
orPredicates = licensesPredicates orPredicates = licensesPredicates
@ -367,59 +478,110 @@ class SearchViewModel: ObservableObject, Identifiable {
return NSCompoundPredicate(orPredicateWithSubpredicates: orPredicates) return NSCompoundPredicate(orPredicateWithSubpredicates: orPredicates)
} }
let allowedCharacterSet = CharacterSet.alphanumerics.union(.whitespaces) // Add gender filter if specified
// Remove all characters that are not in the allowedCharacterSet
var text = pasteField.canonicalVersion.components(separatedBy: allowedCharacterSet.inverted).joined().trimmedMultiline
// Define the regex pattern to match digits
let digitPattern = /\b\w*\d\w*\b/
// Replace all occurrences of the pattern (digits) with an empty string
text = text.replacing(digitPattern, with: "").trimmingCharacters(in: .whitespacesAndNewlines)
let textStrings: [String] = text.components(separatedBy: .whitespacesAndNewlines)
let nonEmptyStrings: [String] = textStrings.compactMap { $0.isEmpty ? nil : $0 }
let nameComponents = nonEmptyStrings.filter({ $0 != "de" && $0 != "la" && $0 != "le" && $0.count > 1 })
//self.wordsCount = nameComponents.count
if filterOption == .female { if filterOption == .female {
andPredicates.append(NSPredicate(format: "male == NO")) andPredicates.append(NSPredicate(format: "male == NO"))
} else if filterOption == .male {
andPredicates.append(NSPredicate(format: "male == YES"))
} }
// Add date filter if specified
if let mostRecentDate { if let mostRecentDate {
andPredicates.append(NSPredicate(format: "importDate == %@", mostRecentDate as CVarArg)) andPredicates.append(NSPredicate(format: "importDate == %@", mostRecentDate as CVarArg))
} }
// Check for slashes (representing alternatives)
if let slashPredicate = getSpecialSlashPredicate(inputString: pasteField) { if let slashPredicate = getSpecialSlashPredicate(inputString: pasteField) {
orPredicates.append(slashPredicate) orPredicates.append(slashPredicate)
} }
print("nameComponents", nameComponents.count) // Prepare text for processing - preserve hyphens but remove digits
var text =
pasteField
.replacingOccurrences(of: "/", with: " ") // Replace slashes with spaces
.trimmingCharacters(in: .whitespacesAndNewlines)
if nameComponents.count < 50 { // Remove digits
if nameComponents.count > 1 { let digitPattern = /\b\w*\d\w*\b/
orPredicates.append(contentsOf: nameComponents.pairs().map { text = text.replacing(digitPattern, with: "").trimmingCharacters(
return NSPredicate(format: "(firstName BEGINSWITH[cd] %@ AND lastName BEGINSWITH[cd] %@) OR (firstName BEGINSWITH[cd] %@ AND lastName BEGINSWITH[cd] %@)", $0, $1, $1, $0) }) in: .whitespacesAndNewlines)
} else {
orPredicates.append(contentsOf: nameComponents.map { NSPredicate(format: "firstName contains[cd] %@ OR lastName contains[cd] %@", $0,$0) }) // Split text by whitespace to get potential name components
let textComponents = text.components(separatedBy: .whitespacesAndNewlines)
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
.filter {
!$0.isEmpty && $0.count > 1 && !["de", "la", "le", "du"].contains($0.lowercased())
} }
}
let components = text.split(separator: " ") if textComponents.count < 50 {
let pattern = components.joined(separator: ".*") // Handle exact fullname match
print(text, pattern) let fullName = textComponents.joined(separator: " ")
let canonicalFullNamePredicate = NSPredicate(format: "canonicalFullName MATCHES[c] %@", pattern) if !fullName.isEmpty {
orPredicates.append(canonicalFullNamePredicate) orPredicates.append(
NSPredicate(format: "canonicalFullName CONTAINS[cd] %@", fullName))
}
var predicate = NSCompoundPredicate(andPredicateWithSubpredicates: andPredicates) // Handle hyphenated last names
let hyphenatedComponents = textComponents.filter { $0.contains("-") }
for component in hyphenatedComponents {
orPredicates.append(NSPredicate(format: "lastName CONTAINS[cd] %@", component))
// Also search for each part of the hyphenated name
let parts = component.components(separatedBy: "-")
for part in parts {
if part.count > 1 {
orPredicates.append(NSPredicate(format: "lastName CONTAINS[cd] %@", part))
}
}
}
if orPredicates.isEmpty == false { // Try different combinations for first/last name
predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, NSCompoundPredicate(orPredicateWithSubpredicates: orPredicates)]) if textComponents.count > 1 {
// Try each pair of components as first+last and last+first
for i in 0..<textComponents.count {
for j in 0..<textComponents.count where i != j {
orPredicates.append(
NSPredicate(
format:
"(firstName CONTAINS[cd] %@ AND lastName CONTAINS[cd] %@) OR (firstName CONTAINS[cd] %@ AND lastName CONTAINS[cd] %@)",
textComponents[i], textComponents[j], textComponents[j],
textComponents[i]
))
// Also try beginswith for more precise matches
orPredicates.append(
NSPredicate(
format:
"(firstName BEGINSWITH[cd] %@ AND lastName BEGINSWITH[cd] %@) OR (firstName BEGINSWITH[cd] %@ AND lastName BEGINSWITH[cd] %@)",
textComponents[i], textComponents[j], textComponents[j],
textComponents[i]
))
}
}
} else if textComponents.count == 1 {
// If only one component, search in both first and last name
orPredicates.append(
NSPredicate(
format: "firstName CONTAINS[cd] %@ OR lastName CONTAINS[cd] %@",
textComponents[0], textComponents[0]))
}
// Add pattern match for canonical full name
let pattern = textComponents.joined(separator: ".*")
orPredicates.append(NSPredicate(format: "canonicalFullName MATCHES[c] %@", pattern))
} }
// Construct final predicate
var predicate = NSCompoundPredicate(andPredicateWithSubpredicates: andPredicates)
if !orPredicates.isEmpty {
let orCompoundPredicate = NSCompoundPredicate(
orPredicateWithSubpredicates: orPredicates)
predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [
predicate, orCompoundPredicate,
])
}
print(predicate)
return predicate return predicate
} }
@ -440,15 +602,20 @@ enum SearchToken: String, CaseIterable, Identifiable {
var message: String { var message: String {
switch self { switch self {
case .club: case .club:
return "Taper le nom d'un club pour y voir tous les joueurs ayant déjà joué un tournoi dans les 12 derniers mois." return
"Taper le nom d'un club pour y voir tous les joueurs ayant déjà joué un tournoi dans les 12 derniers mois."
case .ligue: case .ligue:
return "Taper le nom d'une ligue pour y voir tous les joueurs ayant déjà joué un tournoi dans les 12 derniers mois." return
"Taper le nom d'une ligue pour y voir tous les joueurs ayant déjà joué un tournoi dans les 12 derniers mois."
case .rankMoreThan: case .rankMoreThan:
return "Taper un nombre pour chercher les joueurs ayant un classement supérieur ou égale." return
"Taper un nombre pour chercher les joueurs ayant un classement supérieur ou égale."
case .rankLessThan: case .rankLessThan:
return "Taper un nombre pour chercher les joueurs ayant un classement inférieur ou égale." return
"Taper un nombre pour chercher les joueurs ayant un classement inférieur ou égale."
case .rankBetween: case .rankBetween:
return "Taper deux nombres séparés par une virgule pour chercher les joueurs dans cette intervalle de classement" return
"Taper deux nombres séparés par une virgule pour chercher les joueurs dans cette intervalle de classement"
case .age: case .age:
return "Taper une année de naissance" return "Taper une année de naissance"
} }
@ -545,7 +712,7 @@ enum DataSet: Int, Identifiable {
case favoriteClubs case favoriteClubs
case favoritePlayers case favoritePlayers
static let allCases : [DataSet] = [.national, .ligue, .club, .favoriteClubs] static let allCases: [DataSet] = [.national, .ligue, .club, .favoriteClubs]
var id: Int { rawValue } var id: Int { rawValue }
func localizedLabel(_ displayStyle: DisplayStyle = .wide) -> String { func localizedLabel(_ displayStyle: DisplayStyle = .wide) -> String {
@ -562,7 +729,7 @@ enum DataSet: Int, Identifiable {
} }
var tokens: [SearchToken] { var tokens: [SearchToken] {
var _tokens : [SearchToken] = [] var _tokens: [SearchToken] = []
switch self { switch self {
case .national: case .national:
_tokens = [.club, .ligue, .rankMoreThan, .rankLessThan, .rankBetween] _tokens = [.club, .ligue, .rankMoreThan, .rankLessThan, .rankBetween]
@ -605,19 +772,41 @@ enum SortOption: Int, CaseIterable, Identifiable {
func sortDescriptors(_ ascending: Bool, dataSet: DataSet) -> [SortDescriptor<ImportedPlayer>] { func sortDescriptors(_ ascending: Bool, dataSet: DataSet) -> [SortDescriptor<ImportedPlayer>] {
switch self { switch self {
case .name: case .name:
return [SortDescriptor(\ImportedPlayer.lastName, order: ascending ? .forward : .reverse), SortDescriptor(\ImportedPlayer.rank), SortDescriptor(\ImportedPlayer.assimilation)] return [
SortDescriptor(\ImportedPlayer.lastName, order: ascending ? .forward : .reverse),
SortDescriptor(\ImportedPlayer.rank), SortDescriptor(\ImportedPlayer.assimilation),
]
case .rank: case .rank:
if (dataSet == .national || dataSet == .ligue) { if dataSet == .national || dataSet == .ligue {
return [SortDescriptor(\ImportedPlayer.rank, order: ascending ? .forward : .reverse)] return [
SortDescriptor(\ImportedPlayer.rank, order: ascending ? .forward : .reverse)
]
} else { } else {
return [SortDescriptor(\ImportedPlayer.rank, order: ascending ? .forward : .reverse), SortDescriptor(\ImportedPlayer.assimilation), SortDescriptor(\ImportedPlayer.lastName)] return [
SortDescriptor(\ImportedPlayer.rank, order: ascending ? .forward : .reverse),
SortDescriptor(\ImportedPlayer.assimilation),
SortDescriptor(\ImportedPlayer.lastName),
]
} }
case .tournamentCount: case .tournamentCount:
return [SortDescriptor(\ImportedPlayer.tournamentCount, order: ascending ? .forward : .reverse), SortDescriptor(\ImportedPlayer.rank), SortDescriptor(\ImportedPlayer.assimilation), SortDescriptor(\ImportedPlayer.lastName)] return [
SortDescriptor(
\ImportedPlayer.tournamentCount, order: ascending ? .forward : .reverse),
SortDescriptor(\ImportedPlayer.rank), SortDescriptor(\ImportedPlayer.assimilation),
SortDescriptor(\ImportedPlayer.lastName),
]
case .points: case .points:
return [SortDescriptor(\ImportedPlayer.points, order: ascending ? .forward : .reverse), SortDescriptor(\ImportedPlayer.rank), SortDescriptor(\ImportedPlayer.assimilation), SortDescriptor(\ImportedPlayer.lastName)] return [
SortDescriptor(\ImportedPlayer.points, order: ascending ? .forward : .reverse),
SortDescriptor(\ImportedPlayer.rank), SortDescriptor(\ImportedPlayer.assimilation),
SortDescriptor(\ImportedPlayer.lastName),
]
case .progression: case .progression:
return [SortDescriptor(\ImportedPlayer.progression, order: ascending ? .forward : .reverse), SortDescriptor(\ImportedPlayer.rank), SortDescriptor(\ImportedPlayer.assimilation), SortDescriptor(\ImportedPlayer.lastName)] return [
SortDescriptor(\ImportedPlayer.progression, order: ascending ? .forward : .reverse),
SortDescriptor(\ImportedPlayer.rank), SortDescriptor(\ImportedPlayer.assimilation),
SortDescriptor(\ImportedPlayer.lastName),
]
} }
} }
} }
@ -631,12 +820,12 @@ enum PlayerFilterOption: Int, Hashable, CaseIterable, Identifiable {
func icon() -> String { func icon() -> String {
switch self { switch self {
case .all: case .all:
return "Tous" return "Tous"
case .male: case .male:
return "Homme" return "Homme"
case .female: case .female:
return "Femme" return "Femme"
} }
} }

@ -214,7 +214,9 @@ struct AddTeamView: View {
ToolbarItem(placement: .bottomBar) { ToolbarItem(placement: .bottomBar) {
PasteButton(payloadType: String.self) { strings in PasteButton(payloadType: String.self) { strings in
let first = strings.first ?? "" let first = strings.first ?? ""
handlePasteString(first) DispatchQueue.main.async {
self.handlePasteString(first)
}
} }
.disabled(_limitPlayerCount()) .disabled(_limitPlayerCount())
.foregroundStyle(.master) .foregroundStyle(.master)

Loading…
Cancel
Save