fix issue with search

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

@ -14,13 +14,13 @@ class DebouncableViewModel: ObservableObject {
class SearchViewModel: ObservableObject, Identifiable {
let id: UUID = UUID()
var allowSelection : Int = 0
var allowSelection: Int = 0
var codeClub: String? = nil
var clubName: String? = nil
var ligueName: String? = nil
var showFemaleInMaleAssimilation: Bool = false
var hidePlayers: [String]?
@Published var debouncableText: String = ""
@Published var searchText: String = ""
@Published var task: DispatchWorkItem?
@ -37,91 +37,103 @@ class SearchViewModel: ObservableObject, Identifiable {
@Published var isPresented: Bool = false
@Published var selectedAgeCategory: FederalTournamentAge = .unlisted
@Published var mostRecentDate: Date? = nil
var selectionIsOver: Bool {
if allowSingleSelection && selectedPlayers.count == 1 {
return true
} else if allowMultipleSelection && selectedPlayers.count == allowSelection {
return true
}
return false
}
var allowMultipleSelection: Bool {
allowSelection > 1 || allowSelection == -1
}
var allowSingleSelection: Bool {
allowSelection == 1
}
var debounceTrigger: Double {
(dataSet == .national || dataSet == .ligue) ? 0.4 : 0.1
}
var throttleTrigger: Double {
(dataSet == .national || dataSet == .ligue) ? 0.15 : 0.1
}
var contentUnavailableMessage: String {
var message = ["Vérifiez l'ortographe ou lancez une nouvelle recherche."]
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")
}
func codeClubs() -> [String] {
let clubs: [Club] = DataStore.shared.user.clubsObjects()
return clubs.compactMap { $0.code }
}
func getCodeClub() -> String? {
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
}
func getLigueName() -> String? {
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
}
func shouldIncludeSearchTextPredicate() -> Bool {
if allowMultipleSelection {
return true
}
if allowSingleSelection {
return true
}
if tokens.isEmpty == false || hideAssimilation || selectedAgeCategory != .unlisted {
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 {
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
} else {
return isFiltering()
}
}
if (dataSet == .ligue) { return isFiltering() }
if dataSet == .ligue { return isFiltering() }
if filterOption == .all { return isFiltering() }
return true
}
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 {
switch forDataSet {
case .national:
@ -138,7 +150,7 @@ class SearchViewModel: ObservableObject, Identifiable {
return "dans mes favoris"
}
}
func label(forDataSet: DataSet) -> String {
switch forDataSet {
case .national:
@ -155,102 +167,201 @@ class SearchViewModel: ObservableObject, Identifiable {
}
func words() -> [String] {
return searchText.canonicalVersionWithPunctuation.trimmed.components(separatedBy: .whitespaces)
return searchText.canonicalVersionWithPunctuation.trimmed.components(
separatedBy: .whitespaces)
}
func wordsPredicates() -> NSPredicate? {
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 {
case 2:
let predicates = [
NSPredicate(format: "canonicalLastName beginswith[cd] %@ AND canonicalFirstName beginswith[cd] %@", words[0], words[1]),
NSPredicate(format: "canonicalLastName beginswith[cd] %@ AND canonicalFirstName beginswith[cd] %@", words[1], words[0]),
]
return NSCompoundPredicate(orPredicateWithSubpredicates: predicates)
predicates.append(contentsOf: [
NSPredicate(
format:
"canonicalLastName CONTAINS[cd] %@ AND canonicalFirstName CONTAINS[cd] %@",
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:
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? {
var predicates : [NSPredicate] = []
let allowedCharacterSet = CharacterSet.alphanumerics.union(.whitespaces)
let canonicalVersionWithoutPunctuation = searchText.canonicalVersion.components(separatedBy: allowedCharacterSet.inverted).joined().trimmed
var predicates: [NSPredicate] = []
let allowedCharacterSet = CharacterSet.alphanumerics.union(.whitespaces).union(
CharacterSet(charactersIn: "-"))
let canonicalVersionWithoutPunctuation = searchText.canonicalVersion
.components(separatedBy: allowedCharacterSet.inverted)
.joined()
.trimmed
if canonicalVersionWithoutPunctuation.isEmpty == false {
let wordsPredicates = wordsPredicates()
if let wordsPredicates {
predicates.append(wordsPredicates)
} 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 pattern = components.joined(separator: ".*")
let predicate = NSPredicate(format: "canonicalFullName MATCHES[c] %@", pattern)
predicates.append(predicate)
predicates.append(NSPredicate(format: "canonicalFullName MATCHES[c] %@", pattern))
// 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 {
return nil
}
return NSCompoundPredicate(orPredicateWithSubpredicates: predicates)
}
func orPredicate() -> NSPredicate? {
var predicates : [NSPredicate] = []
let allowedCharacterSet = CharacterSet.alphanumerics.union(.whitespaces)
let canonicalVersionWithoutPunctuation = searchText.canonicalVersion.components(separatedBy: allowedCharacterSet.inverted).joined().trimmed
var predicates: [NSPredicate] = []
let allowedCharacterSet = CharacterSet.alphanumerics.union(.whitespaces).union(
CharacterSet(charactersIn: "-"))
let canonicalVersionWithoutPunctuation = searchText.canonicalVersion
.components(separatedBy: allowedCharacterSet.inverted)
.joined()
.trimmed
let canonicalVersionWithPunctuation = searchText.canonicalVersionWithPunctuation.trimmed
if tokens.isEmpty {
if shouldIncludeSearchTextPredicate(), canonicalVersionWithoutPunctuation.isEmpty == false {
if shouldIncludeSearchTextPredicate(),
canonicalVersionWithoutPunctuation.isEmpty == false
{
if let searchTextPredicate = searchTextPredicate() {
predicates.append(searchTextPredicate)
}
}
}
// Process tokens
for token in tokens {
switch token {
case .ligue:
if canonicalVersionWithoutPunctuation.isEmpty {
predicates.append(NSPredicate(format: "ligueName == nil"))
} else {
predicates.append(NSPredicate(format: "ligueName contains[cd] %@", canonicalVersionWithoutPunctuation))
predicates.append(
NSPredicate(
format: "ligueName contains[cd] %@", canonicalVersionWithoutPunctuation)
)
}
case .club:
if canonicalVersionWithoutPunctuation.isEmpty {
predicates.append(NSPredicate(format: "clubName == nil"))
} else {
predicates.append(NSPredicate(format: "clubName contains[cd] %@", canonicalVersionWithoutPunctuation))
predicates.append(
NSPredicate(
format: "clubName contains[cd] %@", canonicalVersionWithoutPunctuation))
}
case .rankMoreThan:
if canonicalVersionWithoutPunctuation.isEmpty || Int(canonicalVersionWithoutPunctuation) == 0 {
if canonicalVersionWithoutPunctuation.isEmpty
|| Int(canonicalVersionWithoutPunctuation) == 0
{
predicates.append(NSPredicate(format: "rank == 0"))
} else {
predicates.append(NSPredicate(format: "rank >= %@", canonicalVersionWithoutPunctuation))
predicates.append(
NSPredicate(format: "rank >= %@", canonicalVersionWithoutPunctuation))
}
case .rankLessThan:
if canonicalVersionWithoutPunctuation.isEmpty || Int(canonicalVersionWithoutPunctuation) == 0 {
if canonicalVersionWithoutPunctuation.isEmpty
|| Int(canonicalVersionWithoutPunctuation) == 0
{
predicates.append(NSPredicate(format: "rank == 0"))
} else {
predicates.append(NSPredicate(format: "rank <= %@", canonicalVersionWithoutPunctuation))
predicates.append(
NSPredicate(format: "rank <= %@", canonicalVersionWithoutPunctuation))
}
case .rankBetween:
let values = canonicalVersionWithPunctuation.components(separatedBy: ",")
if canonicalVersionWithPunctuation.isEmpty || values.count != 2 {
predicates.append(NSPredicate(format: "rank == 0"))
} else {
predicates.append(NSPredicate(format: "rank BETWEEN {%@,%@}", values.first!, values.last!))
predicates.append(
NSPredicate(format: "rank BETWEEN {%@,%@}", values.first!, values.last!))
}
case .age:
if canonicalVersionWithoutPunctuation.isEmpty || Int(canonicalVersionWithoutPunctuation) == 0 {
if canonicalVersionWithoutPunctuation.isEmpty
|| Int(canonicalVersionWithoutPunctuation) == 0
{
predicates.append(NSPredicate(format: "birthYear == 0"))
} else if let birthYear = Int(canonicalVersionWithoutPunctuation) {
predicates.append(NSPredicate(format: "birthYear == %@", birthYear.formattedAsRawString()))
predicates.append(
NSPredicate(format: "birthYear == %@", birthYear.formattedAsRawString()))
}
}
}
if predicates.isEmpty {
return nil
}
@ -258,35 +369,33 @@ class SearchViewModel: ObservableObject, Identifiable {
}
func predicate() -> NSPredicate? {
var predicates : [NSPredicate?] = [
var predicates: [NSPredicate?] = [
orPredicate(),
filterOption == .male ?
NSPredicate(format: "male == YES") :
nil,
filterOption == .female ?
NSPredicate(format: "male == NO") :
nil,
filterOption == .male ? NSPredicate(format: "male == YES") : nil,
filterOption == .female ? NSPredicate(format: "male == NO") : nil,
]
if let mostRecentDate {
predicates.append(NSPredicate(format: "importDate == %@", mostRecentDate as CVarArg))
}
if hideAssimilation {
predicates.append(NSPredicate(format: "assimilation == %@", "Non"))
}
if selectedAgeCategory != .unlisted {
let computedBirthYear = selectedAgeCategory.computedBirthYear()
if let left = computedBirthYear.0 {
predicates.append(NSPredicate(format: "birthYear >= %@", left.formattedAsRawString()))
predicates.append(
NSPredicate(format: "birthYear >= %@", left.formattedAsRawString()))
}
if let right = computedBirthYear.1 {
predicates.append(NSPredicate(format: "birthYear <= %@", right.formattedAsRawString()))
predicates.append(
NSPredicate(format: "birthYear <= %@", right.formattedAsRawString()))
}
}
switch dataSet {
case .national:
break
@ -312,23 +421,22 @@ class SearchViewModel: ObservableObject, Identifiable {
if hidePlayers?.isEmpty == false {
predicates.append(NSPredicate(format: "NOT (license IN %@)", hidePlayers!))
}
return NSCompoundPredicate(andPredicateWithSubpredicates: predicates.compactMap({ $0 }))
}
func sortDescriptors() -> [SortDescriptor<ImportedPlayer>] {
sortOption.sortDescriptors(ascending, dataSet: dataSet)
}
func nsSortDescriptors() -> [NSSortDescriptor] {
sortDescriptors().map { NSSortDescriptor($0) }
}
static func getSpecialSlashPredicate(inputString: String) -> NSPredicate? {
// Define a regular expression to find slashes between alphabetic characters (not digits)
print(inputString)
let pattern = /(\b[A-Za-z]+)\s*\/\s*([A-Za-z]+\b)/
// Find matches in the input string
@ -336,7 +444,7 @@ class SearchViewModel: ObservableObject, Identifiable {
print("No valid name pairs found")
return nil
}
let lastName1 = match.output.1.trimmingCharacters(in: .whitespacesAndNewlines)
let lastName2 = match.output.2.trimmingCharacters(in: .whitespacesAndNewlines)
@ -345,20 +453,23 @@ class SearchViewModel: ObservableObject, Identifiable {
print("One or both names are empty")
return nil
}
// 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
//print("Generated Predicate: \(predicate)")
return predicate
}
static func pastePredicate(pasteField: String, mostRecentDate: Date?, filterOption: PlayerFilterOption) -> NSPredicate? {
static func pastePredicate(
pasteField: String, mostRecentDate: Date?, filterOption: PlayerFilterOption
) -> NSPredicate? {
var andPredicates = [NSPredicate]()
var orPredicates = [NSPredicate]()
// Check for license numbers
let matches = pasteField.licencesFound()
let licensesPredicates = matches.map { NSPredicate(format: "license contains[cd] %@", $0) }
orPredicates = licensesPredicates
@ -367,59 +478,110 @@ class SearchViewModel: ObservableObject, Identifiable {
return NSCompoundPredicate(orPredicateWithSubpredicates: orPredicates)
}
let allowedCharacterSet = CharacterSet.alphanumerics.union(.whitespaces)
// 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
// Add gender filter if specified
if filterOption == .female {
andPredicates.append(NSPredicate(format: "male == NO"))
} else if filterOption == .male {
andPredicates.append(NSPredicate(format: "male == YES"))
}
// Add date filter if specified
if let mostRecentDate {
andPredicates.append(NSPredicate(format: "importDate == %@", mostRecentDate as CVarArg))
}
// Check for slashes (representing alternatives)
if let slashPredicate = getSpecialSlashPredicate(inputString: pasteField) {
orPredicates.append(slashPredicate)
}
print("nameComponents", nameComponents.count)
if nameComponents.count < 50 {
if nameComponents.count > 1 {
orPredicates.append(contentsOf: nameComponents.pairs().map {
return NSPredicate(format: "(firstName BEGINSWITH[cd] %@ AND lastName BEGINSWITH[cd] %@) OR (firstName BEGINSWITH[cd] %@ AND lastName BEGINSWITH[cd] %@)", $0, $1, $1, $0) })
} else {
orPredicates.append(contentsOf: nameComponents.map { NSPredicate(format: "firstName contains[cd] %@ OR lastName contains[cd] %@", $0,$0) })
// Prepare text for processing - preserve hyphens but remove digits
var text =
pasteField
.replacingOccurrences(of: "/", with: " ") // Replace slashes with spaces
.trimmingCharacters(in: .whitespacesAndNewlines)
// Remove digits
let digitPattern = /\b\w*\d\w*\b/
text = text.replacing(digitPattern, with: "").trimmingCharacters(
in: .whitespacesAndNewlines)
// 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())
}
if textComponents.count < 50 {
// Handle exact fullname match
let fullName = textComponents.joined(separator: " ")
if !fullName.isEmpty {
orPredicates.append(
NSPredicate(format: "canonicalFullName CONTAINS[cd] %@", fullName))
}
// 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))
}
}
}
// Try different combinations for first/last name
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))
}
let components = text.split(separator: " ")
let pattern = components.joined(separator: ".*")
print(text, pattern)
let canonicalFullNamePredicate = NSPredicate(format: "canonicalFullName MATCHES[c] %@", pattern)
orPredicates.append(canonicalFullNamePredicate)
// Construct final predicate
var predicate = NSCompoundPredicate(andPredicateWithSubpredicates: andPredicates)
if orPredicates.isEmpty == false {
predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, NSCompoundPredicate(orPredicateWithSubpredicates: orPredicates)])
if !orPredicates.isEmpty {
let orCompoundPredicate = NSCompoundPredicate(
orPredicateWithSubpredicates: orPredicates)
predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [
predicate, orCompoundPredicate,
])
}
print(predicate)
return predicate
}
@ -432,28 +594,33 @@ enum SearchToken: String, CaseIterable, Identifiable {
case rankLessThan = "rang <"
case rankBetween = "rang <>"
case age = "âge sportif"
var id: String {
rawValue
}
var message: String {
switch self {
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:
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:
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:
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:
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:
return "Taper une année de naissance"
}
}
var titleLabel: String {
switch self {
case .club:
@ -468,7 +635,7 @@ enum SearchToken: String, CaseIterable, Identifiable {
return "Chercher une année de naissance"
}
}
func localizedLabel(_ displayStyle: DisplayStyle = .wide) -> String {
switch self {
case .club:
@ -485,7 +652,7 @@ enum SearchToken: String, CaseIterable, Identifiable {
return "Année de naissance"
}
}
var shortLocalizedLabel: String {
switch self {
case .club:
@ -502,7 +669,7 @@ enum SearchToken: String, CaseIterable, Identifiable {
return "Né(e) en"
}
}
func icon() -> String {
switch self {
case .club:
@ -519,7 +686,7 @@ enum SearchToken: String, CaseIterable, Identifiable {
return "figure.racquetball"
}
}
var systemImage: String {
switch self {
case .club:
@ -544,9 +711,9 @@ enum DataSet: Int, Identifiable {
case club
case favoriteClubs
case favoritePlayers
static let allCases : [DataSet] = [.national, .ligue, .club, .favoriteClubs]
static let allCases: [DataSet] = [.national, .ligue, .club, .favoriteClubs]
var id: Int { rawValue }
func localizedLabel(_ displayStyle: DisplayStyle = .wide) -> String {
switch self {
@ -560,9 +727,9 @@ enum DataSet: Int, Identifiable {
return "Favori"
}
}
var tokens: [SearchToken] {
var _tokens : [SearchToken] = []
var _tokens: [SearchToken] = []
switch self {
case .national:
_tokens = [.club, .ligue, .rankMoreThan, .rankLessThan, .rankBetween]
@ -573,7 +740,7 @@ enum DataSet: Int, Identifiable {
case .favoritePlayers, .favoriteClubs:
_tokens = [.rankMoreThan, .rankLessThan, .rankBetween]
}
_tokens.append(.age)
return _tokens
}
@ -585,7 +752,7 @@ enum SortOption: Int, CaseIterable, Identifiable {
case tournamentCount
case points
case progression
var id: Int { self.rawValue }
func localizedLabel(_ displayStyle: DisplayStyle = .wide) -> String {
switch self {
@ -601,23 +768,45 @@ enum SortOption: Int, CaseIterable, Identifiable {
return "Progression"
}
}
func sortDescriptors(_ ascending: Bool, dataSet: DataSet) -> [SortDescriptor<ImportedPlayer>] {
switch self {
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:
if (dataSet == .national || dataSet == .ligue) {
return [SortDescriptor(\ImportedPlayer.rank, order: ascending ? .forward : .reverse)]
if dataSet == .national || dataSet == .ligue {
return [
SortDescriptor(\ImportedPlayer.rank, order: ascending ? .forward : .reverse)
]
} 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:
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:
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:
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),
]
}
}
}
@ -626,20 +815,20 @@ enum PlayerFilterOption: Int, Hashable, CaseIterable, Identifiable {
case all = -1
case male = 1
case female = 0
var id: Int { rawValue }
func icon() -> String {
switch self {
case .all:
return "Tous"
case .male:
return "Homme"
case .female:
return "Femme"
case .all:
return "Tous"
case .male:
return "Homme"
case .female:
return "Femme"
}
}
var localizedPlayerLabel: String {
switch self {
case .female:

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

Loading…
Cancel
Save