You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
PadelClub/PadelClub/ViewModel/SearchViewModel.swift

905 lines
34 KiB

//
// SearchViewModel.swift
// Padel Tournament
//
// Created by Razmig Sarkissian on 07/02/2024.
//
import SwiftUI
import PadelClubData
class DebouncableViewModel: ObservableObject {
@Published var debouncableText: String = ""
var debounceTrigger: Double = 0.15
}
class SearchViewModel: ObservableObject, Identifiable {
let id: UUID = UUID()
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?
@Published var computedSearchText: String = ""
@Published var tokens = [SearchToken]()
@Published var suggestedTokens = [SearchToken]()
@Published var dataSet: DataSet = .national
@Published var filterOption = PlayerFilterOption.all
@Published var hideAssimilation: Bool = false
@Published var ascending: Bool = true
@Published var sortOption: SortOption = .rank
@Published var selectedPlayers: Set<ImportedPlayer> = Set()
@Published var filterSelectionEnabled: Bool = false
@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."
)
}
return message.joined(separator: "\n")
}
func sortTitle() -> String {
var base = [sortOption.localizedLabel()]
base.append((ascending ? "croissant" : "décroissant"))
if selectedAgeCategory != .unlisted {
base.append(selectedAgeCategory.localizedFederalAgeLabel())
}
return base.joined(separator: " ")
}
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
}
return nil
}
func getLigueName() -> String? {
if let ligueName { return ligueName }
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)
}
func showIndex() -> Bool {
if dataSet == .national {
if searchText.isEmpty == false
&& (tokens.isEmpty == true && hideAssimilation == false
&& selectedAgeCategory == .unlisted)
{
return false
} else {
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
}
func prompt(forDataSet: DataSet) -> String {
switch forDataSet {
case .national:
if let mostRecentDate {
return "base fédérale \(mostRecentDate.monthYearFormatted)"
} else {
return "rechercher"
}
case .ligue:
return "dans cette ligue"
case .club:
return "dans ce club"
case .favoriteClubs, .favoritePlayers:
return "dans mes favoris"
}
}
func label(forDataSet: DataSet) -> String {
switch forDataSet {
case .national:
return "National"
case .ligue:
return (ligueName)?.capitalized ?? "Ma ligue"
case .club:
return (clubName)?.capitalized ?? "Mon club"
case .favoriteClubs:
return "Clubs favoris"
case .favoritePlayers:
return "Joueurs favoris"
}
}
func words() -> [String] {
let cleanedText = searchText.cleanSearchText().canonicalVersionWithPunctuation.trimmed
return cleanedText.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:
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:
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).union(
CharacterSet(charactersIn: "-"))
let canonicalVersionWithoutPunctuation = searchText.canonicalVersion
.components(separatedBy: allowedCharacterSet.inverted)
.joined()
.trimmed
// Check for license numbers
let matches = canonicalVersionWithoutPunctuation.licencesFound()
let licensesPredicates = matches.map { NSPredicate(format: "license contains[cd] %@", $0) }
predicates.append(NSCompoundPredicate(orPredicateWithSubpredicates: licensesPredicates))
if canonicalVersionWithoutPunctuation.isEmpty == false {
let wordsPredicates = wordsPredicates()
if let wordsPredicates {
predicates.append(wordsPredicates)
}
// 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: ".*")
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).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 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)
)
}
case .club:
if canonicalVersionWithoutPunctuation.isEmpty {
predicates.append(NSPredicate(format: "clubName == nil"))
} else {
predicates.append(
NSPredicate(
format: "clubName contains[cd] %@", canonicalVersionWithoutPunctuation))
}
case .rankMoreThan:
if canonicalVersionWithoutPunctuation.isEmpty
|| Int(canonicalVersionWithoutPunctuation) == 0
{
predicates.append(NSPredicate(format: "rank == 0"))
} else {
predicates.append(
NSPredicate(format: "rank >= %@", canonicalVersionWithoutPunctuation))
}
case .rankLessThan:
if canonicalVersionWithoutPunctuation.isEmpty
|| Int(canonicalVersionWithoutPunctuation) == 0
{
predicates.append(NSPredicate(format: "rank == 0"))
} else {
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!))
}
case .age:
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()))
}
}
}
if predicates.isEmpty {
return nil
}
let full = NSCompoundPredicate(orPredicateWithSubpredicates: predicates)
return full
}
func predicate() -> NSPredicate? {
var predicates: [NSPredicate?] = [
orPredicate(),
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()))
}
if let right = computedBirthYear.1 {
predicates.append(
NSPredicate(format: "birthYear <= %@", right.formattedAsRawString()))
}
}
switch dataSet {
case .national:
break
case .ligue:
if let ligueName = getLigueName() {
predicates.append(NSPredicate(format: "ligueName == %@", ligueName))
} else {
predicates.append(NSPredicate(format: "ligueName == nil"))
}
case .club:
if let codeClub = getCodeClub() {
predicates.append(NSPredicate(format: "clubCode == %@", codeClub))
} else {
predicates.append(NSPredicate(format: "clubCode == nil"))
}
case .favoriteClubs:
predicates.append(NSPredicate(format: "clubCode IN %@", codeClubs()))
case .favoritePlayers:
//todo
predicates.append(NSPredicate(format: "license == nil"))
}
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 cleanedInput = inputString.cleanSearchText()
let pattern = /(\b[A-Za-z]+)\s*\/\s*([A-Za-z]+\b)/
// Find matches in the input string
guard let match = cleanedInput.firstMatch(of: pattern) else {
print("No valid name pairs found")
return nil
}
let lastName1 = match.output.1.trimmingCharacters(in: .whitespacesAndNewlines)
let lastName2 = match.output.2.trimmingCharacters(in: .whitespacesAndNewlines)
// Ensure both names are not empty
guard !lastName1.isEmpty && !lastName2.isEmpty else {
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)
// Output the result
//print("Generated Predicate: \(predicate)")
return predicate
}
static func pastePredicate(
pasteField: String, mostRecentDate: Date?, filterOption: PlayerFilterOption
) -> NSPredicate? {
print("🔍 pastePredicate called with: \(pasteField)")
print("📅 mostRecentDate: \(String(describing: mostRecentDate))")
print("🔍 filterOption: \(filterOption)")
var andPredicates = [NSPredicate]()
var orPredicates = [NSPredicate]()
// Check for license numbers
let matches = pasteField.licencesFound()
print("🎫 Licenses found: \(matches)")
let licensesPredicates = matches.map { NSPredicate(format: "license contains[cd] %@", $0) }
orPredicates = licensesPredicates
if matches.count == 2 {
print("✅ Returning early with 2 license predicates")
return NSCompoundPredicate(orPredicateWithSubpredicates: orPredicates)
}
// Add gender filter if specified
if filterOption == .female {
print("👩 Adding female filter")
andPredicates.append(NSPredicate(format: "male == NO"))
} else if filterOption == .male {
print("👨 Adding male filter")
andPredicates.append(NSPredicate(format: "male == YES"))
}
// Add date filter if specified
if let mostRecentDate {
print("📆 Adding date filter for: \(mostRecentDate)")
andPredicates.append(NSPredicate(format: "importDate == %@", mostRecentDate as CVarArg))
}
// Check for slashes (representing alternatives)
if let slashPredicate = getSpecialSlashPredicate(inputString: pasteField) {
print("🔀 Found slash predicate")
orPredicates.append(slashPredicate)
}
// Prepare text for processing - preserve hyphens but remove digits
var text =
pasteField
.replacingOccurrences(of: "[\\(\\)\\[\\]\\{\\}]", with: "", options: .regularExpression)
.replacingOccurrences(of: "/", with: " ") // Replace slashes with spaces
.replacingOccurrences(of: "[\\.,;:!?]", with: " ", options: .regularExpression) // Replace common punctuation with spaces
.trimmingCharacters(in: .whitespacesAndNewlines)
print("🧹 Cleaned text: \"\(text)\"")
// Remove digits
let digitPattern = /\b\w*\d\w*\b/
text = text.replacing(digitPattern, with: "").trimmingCharacters(
in: .whitespacesAndNewlines)
print("🔢 After digit removal: \"\(text)\"")
// 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", "et", "si"].contains($0.lowercased())
}
print("📚 Text components: \(textComponents)")
if textComponents.count < 50 {
print("✓ Text components count is reasonable: \(textComponents.count)")
// Handle exact fullname match
let fullName = textComponents.joined(separator: " ")
if !fullName.isEmpty {
print("📝 Adding predicate for full name: \"\(fullName)\"")
orPredicates.append(
NSPredicate(format: "canonicalFullName CONTAINS[cd] %@", fullName))
}
// Handle hyphenated last names
let hyphenatedComponents = textComponents.filter { $0.contains("-") }
print("🔗 Hyphenated components: \(hyphenatedComponents)")
for component in hyphenatedComponents {
orPredicates.append(NSPredicate(format: "lastName CONTAINS[cd] %@", component))
print("➕ Added hyphenated last name predicate: \"\(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))
print("➕ Added hyphenated part predicate: \"\(part)\"")
}
}
}
// Try different combinations for first/last name
if textComponents.count > 1 {
print("🔄 Creating combinations with \(textComponents.count) components")
// Try each pair of components as first+last and last+first
for i in 0..<textComponents.count-1 {
let j = i + 1
print("👥 Trying adjacent pair: \"\(textComponents[i])\" and \"\(textComponents[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 {
print("👤 Single component search: \"\(textComponents[0])\"")
// 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: ".*")
// print("🔍 Adding pattern match: \"\(pattern)\"")
// orPredicates.append(NSPredicate(format: "canonicalFullName MATCHES[c] %@", pattern))
} else {
print(" Too many text components: \(textComponents.count) - skipping name combinations")
}
// Construct final predicate
var predicate = NSCompoundPredicate(andPredicateWithSubpredicates: andPredicates)
print("📊 AND predicates count: \(andPredicates.count)")
if !orPredicates.isEmpty {
print("📊 OR predicates count: \(orPredicates.count)")
let orCompoundPredicate = NSCompoundPredicate(
orPredicateWithSubpredicates: orPredicates)
predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [
predicate, orCompoundPredicate,
])
}
print("🏁 Final predicate created")
print(predicate)
return predicate
}
}
enum SearchToken: String, CaseIterable, Identifiable {
case club = "club"
case ligue = "ligue"
case rankMoreThan = "rang >"
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."
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."
case .rankMoreThan:
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."
case .rankBetween:
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:
return "Chercher un club"
case .ligue:
return "Chercher une ligue"
case .rankMoreThan, .rankLessThan:
return "Chercher un rang"
case .rankBetween:
return "Chercher une intervalle de classement"
case .age:
return "Chercher une année de naissance"
}
}
func localizedLabel(_ displayStyle: DisplayStyle = .wide) -> String {
switch self {
case .club:
return "Club"
case .ligue:
return "Ligue"
case .rankMoreThan:
return "Rang supérieur ou égale à"
case .rankLessThan:
return "Rang inférieur ou égale à"
case .rankBetween:
return "Rang entre deux valeurs"
case .age:
return "Année de naissance"
}
}
var shortLocalizedLabel: String {
switch self {
case .club:
return "Club"
case .ligue:
return "Ligue"
case .rankMoreThan:
return "Rang ≥"
case .rankLessThan:
return "Rang ≤"
case .rankBetween:
return "Rang ≥,≤"
case .age:
return "Né(e) en"
}
}
func icon() -> String {
switch self {
case .club:
return "house.and.flag.fill"
case .ligue:
return "house.and.flag.fill"
case .rankMoreThan:
return "figure.racquetball"
case .rankLessThan:
return "figure.racquetball"
case .rankBetween:
return "figure.racquetball"
case .age:
return "figure.racquetball"
}
}
var systemImage: String {
switch self {
case .club:
return "house.and.flag.fill"
case .ligue:
return "house.and.flag.fill"
case .rankMoreThan:
return "figure.racquetball"
case .rankLessThan:
return "figure.racquetball"
case .rankBetween:
return "figure.racquetball"
case .age:
return "figure.racquetball"
}
}
}
enum DataSet: Int, Identifiable {
case national
case ligue
case club
case favoriteClubs
case favoritePlayers
static let allCases: [DataSet] = [.national, .ligue, .club, .favoriteClubs]
var id: Int { rawValue }
func localizedLabel(_ displayStyle: DisplayStyle = .wide) -> String {
switch self {
case .national:
return "National"
case .ligue:
return "Ligue"
case .club:
return "Club"
case .favoritePlayers, .favoriteClubs:
return "Favori"
}
}
var tokens: [SearchToken] {
var _tokens: [SearchToken] = []
switch self {
case .national:
_tokens = [.club, .ligue, .rankMoreThan, .rankLessThan, .rankBetween]
case .ligue:
_tokens = [.club, .rankMoreThan, .rankLessThan, .rankBetween]
case .club:
_tokens = [.rankMoreThan, .rankLessThan, .rankBetween]
case .favoritePlayers, .favoriteClubs:
_tokens = [.rankMoreThan, .rankLessThan, .rankBetween]
}
_tokens.append(.age)
return _tokens
}
}
extension SortOption {
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),
]
case .rank:
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),
]
}
case .tournamentCount:
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),
]
case .progression:
return [
SortDescriptor(\ImportedPlayer.progression, order: ascending ? .forward : .reverse),
SortDescriptor(\ImportedPlayer.rank), SortDescriptor(\ImportedPlayer.assimilation),
SortDescriptor(\ImportedPlayer.lastName),
]
}
}
}
//enum SortOption: Int, CaseIterable, Identifiable {
// case name
// case rank
// case tournamentCount
// case points
// case progression
//
// var id: Int { self.rawValue }
// func localizedLabel(_ displayStyle: DisplayStyle = .wide) -> String {
// switch self {
// case .name:
// return "Nom"
// case .rank:
// return "Rang"
// case .tournamentCount:
// return "Tournoi"
// case .points:
// return "Points"
// case .progression:
// 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),
// ]
// case .rank:
// 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),
// ]
// }
// case .tournamentCount:
// 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),
// ]
// case .progression:
// return [
// SortDescriptor(\ImportedPlayer.progression, order: ascending ? .forward : .reverse),
// SortDescriptor(\ImportedPlayer.rank), SortDescriptor(\ImportedPlayer.assimilation),
// SortDescriptor(\ImportedPlayer.lastName),
// ]
// }
// }
//}