diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index 61b1774..89f7137 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -121,6 +121,7 @@ FF4AB6BF2B92577A0002987F /* ImportedPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4AB6BE2B92577A0002987F /* ImportedPlayerView.swift */; }; FF4C7F022BBBD7150031B6A3 /* TabItemModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4C7F012BBBD7150031B6A3 /* TabItemModifier.swift */; }; FF53FBB82BFB302B0051D4C3 /* ClubCourtSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF53FBB72BFB302B0051D4C3 /* ClubCourtSetupView.swift */; }; + FF558C632C6CDD020071F9AE /* UnderlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF558C622C6CDD020071F9AE /* UnderlineView.swift */; }; FF5647132C0B6F390081F995 /* LoserRoundSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5647122C0B6F380081F995 /* LoserRoundSettingsView.swift */; }; FF59FFB32B90EFAC0061EFF9 /* EventListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF59FFB22B90EFAC0061EFF9 /* EventListView.swift */; }; FF59FFB72B90EFBF0061EFF9 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF59FFB62B90EFBF0061EFF9 /* MainView.swift */; }; @@ -371,14 +372,14 @@ FF0E0B6C2BC254C6005F00A9 /* TournamentScheduleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentScheduleView.swift; sourceTree = ""; }; FF0EC51D2BB16F680056B6D1 /* SwiftParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftParser.swift; sourceTree = ""; }; FF0EC5212BB173E70056B6D1 /* UpdateSourceRankDateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateSourceRankDateView.swift; sourceTree = ""; }; - FF0EC5232BB195CA0056B6D1 /* CLASSEMENT PADEL DAMES-07-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT PADEL DAMES-07-2023.csv"; sourceTree = ""; }; - FF0EC5242BB195CA0056B6D1 /* CLASSEMENT PADEL DAMES-08-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT PADEL DAMES-08-2023.csv"; sourceTree = ""; }; - FF0EC5252BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_1-07-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT PADEL MESSIEURS_1-07-2023.csv"; sourceTree = ""; }; - FF0EC5262BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_1-08-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT PADEL MESSIEURS_1-08-2023.csv"; sourceTree = ""; }; - FF0EC5272BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_2-07-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT PADEL MESSIEURS_2-07-2023.csv"; sourceTree = ""; }; - FF0EC5282BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_2-08-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT PADEL MESSIEURS_2-08-2023.csv"; sourceTree = ""; }; - FF0EC5292BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_3-07-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT PADEL MESSIEURS_3-07-2023.csv"; sourceTree = ""; }; - FF0EC52A2BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_3-08-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT PADEL MESSIEURS_3-08-2023.csv"; sourceTree = ""; }; + FF0EC5232BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-07-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-DAMES-07-2023.csv"; sourceTree = ""; }; + FF0EC5242BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-08-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-DAMES-08-2023.csv"; sourceTree = ""; }; + FF0EC5252BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-07-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-07-2023.csv"; sourceTree = ""; }; + FF0EC5262BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-08-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-08-2023.csv"; sourceTree = ""; }; + FF0EC5272BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-2-07-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-2-07-2023.csv"; sourceTree = ""; }; + FF0EC5282BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-2-08-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-2-08-2023.csv"; sourceTree = ""; }; + FF0EC5292BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-3-07-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-3-07-2023.csv"; sourceTree = ""; }; + FF0EC52A2BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-3-08-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-3-08-2023.csv"; sourceTree = ""; }; FF0EC52B2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-01-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-DAMES-01-2023.csv"; sourceTree = ""; }; FF0EC52C2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-02-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-DAMES-02-2023.csv"; sourceTree = ""; }; FF0EC52D2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-03-2023.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-DAMES-03-2023.csv"; sourceTree = ""; }; @@ -462,6 +463,7 @@ FF4AB6BE2B92577A0002987F /* ImportedPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportedPlayerView.swift; sourceTree = ""; }; FF4C7F012BBBD7150031B6A3 /* TabItemModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabItemModifier.swift; sourceTree = ""; }; FF53FBB72BFB302B0051D4C3 /* ClubCourtSetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClubCourtSetupView.swift; sourceTree = ""; }; + FF558C622C6CDD020071F9AE /* UnderlineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnderlineView.swift; sourceTree = ""; }; FF5647122C0B6F380081F995 /* LoserRoundSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoserRoundSettingsView.swift; sourceTree = ""; }; FF59FFB22B90EFAC0061EFF9 /* EventListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventListView.swift; sourceTree = ""; }; FF59FFB62B90EFBF0061EFF9 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; @@ -817,6 +819,7 @@ FF6EC8F62B94773100EA7F5A /* RowButtonView.swift */, C4A47D9E2B7D0BCE00ADC637 /* StepperView.swift */, FFCB74162C480411008384D0 /* CopyPasteButtonView.swift */, + FF558C622C6CDD020071F9AE /* UnderlineView.swift */, ); path = Components; sourceTree = ""; @@ -864,14 +867,14 @@ FF0EC54D2BB195CA0056B6D1 /* CSV */ = { isa = PBXGroup; children = ( - FF0EC5232BB195CA0056B6D1 /* CLASSEMENT PADEL DAMES-07-2023.csv */, - FF0EC5242BB195CA0056B6D1 /* CLASSEMENT PADEL DAMES-08-2023.csv */, - FF0EC5252BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_1-07-2023.csv */, - FF0EC5262BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_1-08-2023.csv */, - FF0EC5272BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_2-07-2023.csv */, - FF0EC5282BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_2-08-2023.csv */, - FF0EC5292BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_3-07-2023.csv */, - FF0EC52A2BB195CA0056B6D1 /* CLASSEMENT PADEL MESSIEURS_3-08-2023.csv */, + FF0EC5232BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-07-2023.csv */, + FF0EC5242BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-08-2023.csv */, + FF0EC5252BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-07-2023.csv */, + FF0EC5262BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-08-2023.csv */, + FF0EC5272BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-2-07-2023.csv */, + FF0EC5282BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-2-08-2023.csv */, + FF0EC5292BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-3-07-2023.csv */, + FF0EC52A2BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-3-08-2023.csv */, FF0EC52B2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-01-2023.csv */, FF0EC52C2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-02-2023.csv */, FF0EC52D2BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-03-2023.csv */, @@ -1628,6 +1631,7 @@ FF59FFB32B90EFAC0061EFF9 /* EventListView.swift in Sources */, FF8F263D2BAD627A00650388 /* TournamentConfiguratorView.swift in Sources */, FFC1E10C2BAC7FB0008D6F59 /* ClubImportView.swift in Sources */, + FF558C632C6CDD020071F9AE /* UnderlineView.swift in Sources */, FF3B60A32BC49BBC008C2E66 /* MatchScheduler.swift in Sources */, FF11627A2BCF8109000C4809 /* CallMessageCustomizationView.swift in Sources */, FF6087EA2BE25EF1004E1E47 /* TournamentStatusView.swift in Sources */, @@ -1935,7 +1939,7 @@ CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 106; + CURRENT_PROJECT_VERSION = 107; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; @@ -1985,7 +1989,7 @@ CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 106; + CURRENT_PROJECT_VERSION = 107; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_TEAM = BQ3Y44M3Q6; diff --git a/PadelClub/CSV/CLASSEMENT PADEL DAMES-07-2023.csv b/PadelClub/CSV/CLASSEMENT-PADEL-DAMES-07-2023.csv similarity index 100% rename from PadelClub/CSV/CLASSEMENT PADEL DAMES-07-2023.csv rename to PadelClub/CSV/CLASSEMENT-PADEL-DAMES-07-2023.csv diff --git a/PadelClub/CSV/CLASSEMENT PADEL DAMES-08-2023.csv b/PadelClub/CSV/CLASSEMENT-PADEL-DAMES-08-2023.csv similarity index 100% rename from PadelClub/CSV/CLASSEMENT PADEL DAMES-08-2023.csv rename to PadelClub/CSV/CLASSEMENT-PADEL-DAMES-08-2023.csv diff --git a/PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_1-07-2023.csv b/PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-07-2023.csv similarity index 100% rename from PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_1-07-2023.csv rename to PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-07-2023.csv diff --git a/PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_1-08-2023.csv b/PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-08-2023.csv similarity index 100% rename from PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_1-08-2023.csv rename to PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-08-2023.csv diff --git a/PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_2-07-2023.csv b/PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-2-07-2023.csv similarity index 100% rename from PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_2-07-2023.csv rename to PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-2-07-2023.csv diff --git a/PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_2-08-2023.csv b/PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-2-08-2023.csv similarity index 100% rename from PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_2-08-2023.csv rename to PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-2-08-2023.csv diff --git a/PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_3-07-2023.csv b/PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-3-07-2023.csv similarity index 100% rename from PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_3-07-2023.csv rename to PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-3-07-2023.csv diff --git a/PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_3-08-2023.csv b/PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-3-08-2023.csv similarity index 100% rename from PadelClub/CSV/CLASSEMENT PADEL MESSIEURS_3-08-2023.csv rename to PadelClub/CSV/CLASSEMENT-PADEL-MESSIEURS-3-08-2023.csv diff --git a/PadelClub/Data/Coredata/ImportedPlayer+Extensions.swift b/PadelClub/Data/Coredata/ImportedPlayer+Extensions.swift index 7288d76..10cd021 100644 --- a/PadelClub/Data/Coredata/ImportedPlayer+Extensions.swift +++ b/PadelClub/Data/Coredata/ImportedPlayer+Extensions.swift @@ -52,6 +52,14 @@ extension ImportedPlayer: PlayerHolder { male } + func isNotFromCurrentDate() -> Bool { + if let importDate, importDate != SourceFileManager.shared.lastDataSourceDate() { + return true + } else { + return false + } + } + func hitForSearch(_ searchText: String) -> Int { var trimmedSearchText = searchText.lowercased().trimmingCharacters(in: .whitespaces).folding(options: .diacriticInsensitive, locale: .current) trimmedSearchText = trimmedSearchText.replaceCharactersFromSet(characterSet: .punctuationCharacters, replacementString: " ") diff --git a/PadelClub/Data/Federal/PlayerHolder.swift b/PadelClub/Data/Federal/PlayerHolder.swift index e2ab0eb..d0a6801 100644 --- a/PadelClub/Data/Federal/PlayerHolder.swift +++ b/PadelClub/Data/Federal/PlayerHolder.swift @@ -8,7 +8,7 @@ import Foundation protocol PlayerHolder { - + func getFirstName() -> String func getLastName() -> String func formattedRank() -> String @@ -23,9 +23,14 @@ protocol PlayerHolder { var assimilation: String? { get } var computedAge: Int? { get } func getAssimilatedAsMaleRank() -> Int? + func isNotFromCurrentDate() -> Bool } extension PlayerHolder { + func isNotFromCurrentDate() -> Bool { + false + } + var isAssimilated: Bool { assimilation == "Oui" } diff --git a/PadelClub/Data/MonthData.swift b/PadelClub/Data/MonthData.swift index 5c79558..e269890 100644 --- a/PadelClub/Data/MonthData.swift +++ b/PadelClub/Data/MonthData.swift @@ -26,34 +26,53 @@ final class MonthData : ModelObject, Storable { var maleCount: Int? = nil var femaleCount: Int? = nil var anonymousCount: Int? = nil - + var incompleteMode: Bool = false init(monthKey: String) { self.monthKey = monthKey self.creationDate = Date() } + required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + id = try container.decode(String.self, forKey: ._id) + monthKey = try container.decode(String.self, forKey: ._monthKey) + creationDate = try container.decode(Date.self, forKey: ._creationDate) + maleUnrankedValue = try container.decodeIfPresent(Int.self, forKey: ._maleUnrankedValue) + femaleUnrankedValue = try container.decodeIfPresent(Int.self, forKey: ._femaleUnrankedValue) + maleCount = try container.decodeIfPresent(Int.self, forKey: ._maleCount) + femaleCount = try container.decodeIfPresent(Int.self, forKey: ._femaleCount) + anonymousCount = try container.decodeIfPresent(Int.self, forKey: ._anonymousCount) + incompleteMode = try container.decodeIfPresent(Bool.self, forKey: ._incompleteMode) ?? false + + } + func total() -> Int { return (maleCount ?? 0) + (femaleCount ?? 0) } - static func calculateCurrentUnrankedValues(mostRecentDateAvailable: Date) async { - let lastDataSourceMaleUnranked = await FederalPlayer.lastRank(mostRecentDateAvailable: mostRecentDateAvailable, man: true) - let lastDataSourceFemaleUnranked = await FederalPlayer.lastRank(mostRecentDateAvailable: mostRecentDateAvailable, man: false) - let anonymousCount = await FederalPlayer.anonymousCount(mostRecentDateAvailable: mostRecentDateAvailable) + static func calculateCurrentUnrankedValues(fromDate: Date) async { + + let fftImportingUncomplete = SourceFileManager.shared.allFiles(true).first(where: { $0.dateFromPath == fromDate })?.fftImportingUncomplete() + + let incompleteMode = fftImportingUncomplete != nil + + let lastDataSourceMaleUnranked = await FederalPlayer.lastRank(mostRecentDateAvailable: fromDate, man: true) + let lastDataSourceFemaleUnranked = await FederalPlayer.lastRank(mostRecentDateAvailable: fromDate, man: false) + let anonymousCount = await FederalPlayer.anonymousCount(mostRecentDateAvailable: fromDate) await MainActor.run { - if let lastDataSource = DataStore.shared.appSettings.lastDataSource { - let currentMonthData : MonthData = DataStore.shared.monthData.first(where: { $0.monthKey == lastDataSource }) ?? MonthData(monthKey: lastDataSource) - currentMonthData.maleUnrankedValue = lastDataSourceMaleUnranked?.0 - currentMonthData.maleCount = lastDataSourceMaleUnranked?.1 - currentMonthData.femaleUnrankedValue = lastDataSourceFemaleUnranked?.0 - currentMonthData.femaleCount = lastDataSourceFemaleUnranked?.1 - currentMonthData.anonymousCount = anonymousCount - do { - try DataStore.shared.monthData.addOrUpdate(instance: currentMonthData) - } catch { - Logger.error(error) - } + let lastDataSource = URL.importDateFormatter.string(from: fromDate) + let currentMonthData : MonthData = DataStore.shared.monthData.first(where: { $0.monthKey == lastDataSource }) ?? MonthData(monthKey: lastDataSource) + currentMonthData.maleUnrankedValue = incompleteMode ? 60000 : lastDataSourceMaleUnranked?.0 + currentMonthData.incompleteMode = incompleteMode + currentMonthData.maleCount = incompleteMode ? fftImportingUncomplete : lastDataSourceMaleUnranked?.1 + currentMonthData.femaleUnrankedValue = lastDataSourceFemaleUnranked?.0 + currentMonthData.femaleCount = lastDataSourceFemaleUnranked?.1 + currentMonthData.anonymousCount = anonymousCount + do { + try DataStore.shared.monthData.addOrUpdate(instance: currentMonthData) + } catch { + Logger.error(error) } } } @@ -70,5 +89,6 @@ final class MonthData : ModelObject, Storable { case _maleCount = "maleCount" case _femaleCount = "femaleCount" case _anonymousCount = "anonymousCount" + case _incompleteMode = "incompleteMode" } } diff --git a/PadelClub/Extensions/URL+Extensions.swift b/PadelClub/Extensions/URL+Extensions.swift index 6afb088..4f5b92d 100644 --- a/PadelClub/Extensions/URL+Extensions.swift +++ b/PadelClub/Extensions/URL+Extensions.swift @@ -51,6 +51,24 @@ extension URL { } extension URL { + func fftImportingUncomplete() -> Int? { + // Read the contents of the file + guard let fileContents = try? String(contentsOfFile: path(), encoding: .utf8) else { + return nil + } + + // Split the contents by newline characters + let lines = fileContents.components(separatedBy: .newlines) + + if let line = lines.first(where: { + $0.hasPrefix("max-players:") + }) { + return Int(line.replacingOccurrences(of: "max-players:", with: "")) + } + + return nil + } + func getUnrankedValue() -> Int? { // Read the contents of the file guard let fileContents = try? String(contentsOfFile: path(), encoding: .utf8) else { diff --git a/PadelClub/Utils/FileImportManager.swift b/PadelClub/Utils/FileImportManager.swift index 534b639..d7de477 100644 --- a/PadelClub/Utils/FileImportManager.swift +++ b/PadelClub/Utils/FileImportManager.swift @@ -22,12 +22,25 @@ enum FileImportManagerError: LocalizedError { class FileImportManager { static let shared = FileImportManager() + func currentlyImportingLabel() -> String { + guard let currentImportDate else { return "import en cours" } + if URL.importDateFormatter.string(from: currentImportDate) == "07-2024" { + return "consolidation des données fédérales" + } + return "import " + currentImportDate.monthYearFormatted + } + + var currentImportDate: Date? = nil + + func isImportingFile() -> Bool { + currentImportDate != nil + } + func updatePlayers(isMale: Bool, players: inout [FederalPlayer]) { - guard let mostRecentDateAvailable = URL.importDateFormatter.date(from: "05-2024") else { return } let replacements: [(Character, Character)] = [("Á", "ç"), ("‡", "à"), ("Ù", "ô"), ("Ë", "è"), ("Ó", "î"), ("Î", "ë"), ("…", "É"), ("Ô", "ï"), ("È", "é"), ("«", "Ç"), ("»", "È")] var playersLeft = players - SourceFileManager.shared.allFilesSortedByDate(isMale).filter({ $0.dateFromPath.isEarlierThan(mostRecentDateAvailable) }).forEach({ url in + SourceFileManager.shared.allFilesSortedByDate(isMale).forEach({ url in if playersLeft.isEmpty == false { let federalPlayers = readCSV(inputFile: url) let replacementsCharacters = url.dateFromPath.monthYearFormatted != "04-2024" ? [] : replacements @@ -170,17 +183,14 @@ class FileImportManager { } } - func importDataFromFFT() async -> String? { - if let importingDate = SourceFileManager.shared.mostRecentDateAvailable { - for source in SourceFile.allCases { - for fileURL in source.currentURLs { - let p = readCSV(inputFile: fileURL) - await importingChunkOfPlayers(p, importingDate: importingDate) - } + func importDataFromFFT(importingDate: Date) async -> String? { + for source in SourceFile.allCases { + for fileURL in source.currentURLs(importingDate: importingDate) { + let p = readCSV(inputFile: fileURL) + await importingChunkOfPlayers(p, importingDate: importingDate) } - return URL.importDateFormatter.string(from: importingDate) } - return nil + return URL.importDateFormatter.string(from: importingDate) } diff --git a/PadelClub/Utils/SourceFileManager.swift b/PadelClub/Utils/SourceFileManager.swift index 57fc1f3..c9ca7c7 100644 --- a/PadelClub/Utils/SourceFileManager.swift +++ b/PadelClub/Utils/SourceFileManager.swift @@ -204,18 +204,13 @@ enum SourceFile: String, CaseIterable { return allFiles.filter{$0.pathExtension == "csv" && $0.path().contains(rawValue)} } - var currentURLs: [URL] { + func currentURLs(importingDate: Date) -> [URL] { var files = Bundle.main.urls(forResourcesWithExtension: "csv", subdirectory: nil)?.filter({ url in url.path().contains(rawValue) }) ?? [] files.append(contentsOf: filesFromServer) - - if let mostRecent = files.sorted(by: \.dateFromPath).reversed().first { - return files.filter({ $0.dateFromPath == mostRecent.dateFromPath }) - } else { - return [] - } + return files.filter({ $0.dateFromPath == importingDate }) } var isMan: Bool { diff --git a/PadelClub/ViewModel/SearchViewModel.swift b/PadelClub/ViewModel/SearchViewModel.swift index c588edd..a3ec84f 100644 --- a/PadelClub/ViewModel/SearchViewModel.swift +++ b/PadelClub/ViewModel/SearchViewModel.swift @@ -215,7 +215,7 @@ class SearchViewModel: ObservableObject, Identifiable { ] if let mostRecentDate { - predicates.append(NSPredicate(format: "importDate == %@", mostRecentDate as CVarArg)) + //predicates.append(NSPredicate(format: "importDate == %@", mostRecentDate as CVarArg)) } if hideAssimilation { diff --git a/PadelClub/Views/Components/UnderlineView.swift b/PadelClub/Views/Components/UnderlineView.swift new file mode 100644 index 0000000..410cc12 --- /dev/null +++ b/PadelClub/Views/Components/UnderlineView.swift @@ -0,0 +1,18 @@ +// +// UnderlineView.swift +// PadelClub +// +// Created by Razmig Sarkissian on 14/08/2024. +// + +import SwiftUI + +struct UnderlineView: View { + var body: some View { + Rectangle() + .stroke(style: StrokeStyle(lineWidth: 2, dash: [2, 2])) + .frame(height: 2) // Height of the dashed line + .foregroundColor(.blue) + .offset(y: 10) // Offset to position the dashed line below the text + } +} diff --git a/PadelClub/Views/Navigation/MainView.swift b/PadelClub/Views/Navigation/MainView.swift index ba7e719..226951f 100644 --- a/PadelClub/Views/Navigation/MainView.swift +++ b/PadelClub/Views/Navigation/MainView.swift @@ -13,7 +13,6 @@ struct MainView: View { @EnvironmentObject var dataStore: DataStore @Environment(\.requestReview) var requestReview - @AppStorage("importingFiles") var importingFiles: Bool = false @Environment(NavigationViewModel.self) private var navigation: NavigationViewModel @State private var checkingFilesAttempt: Int = 0 @@ -61,14 +60,21 @@ struct MainView: View { ActivityView() .tabItem(for: .activity) .onAppear { - if lastDataSource == nil, checkingFiles == false, importingFiles == false { + if lastDataSource == nil, checkingFiles == false, FileImportManager.shared.isImportingFile() == false { Task { await self._checkSourceFileAvailability() } - } else if let lastDataSource, lastDataSource != URL.importDateFormatter.string(from: Date()), checkingFiles == false, importingFiles == false { + } else if let lastDataSource, lastDataSource != URL.importDateFormatter.string(from: Date()), checkingFiles == false, FileImportManager.shared.isImportingFile() == false { Task { await self._checkSourceFileAvailability() } + } else if let lastDataSource, lastDataSource == "08-2024" { + let monthData = dataStore.monthData.sorted(by: \.creationDate) + if let current = monthData.last, current.monthKey == "08-2024", current.incompleteMode == false { + Task { + await _calculateMonthData(dataSource: current.monthKey) + } + } } #if DEBUG @@ -133,7 +139,7 @@ struct MainView: View { // } // } .overlay(alignment: .bottom) { - if importingFiles { + if FileImportManager.shared.isImportingFile() { _activityStatusBoxView() } else { _activityStatusBoxView() @@ -158,15 +164,11 @@ struct MainView: View { @ViewBuilder func _activityStatus() -> some View { - if importingFiles { + if FileImportManager.shared.isImportingFile() { HStack(spacing: 20) { ProgressView() .progressViewStyle(CircularProgressViewStyle(tint: Color.black)) - if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable { - if mostRecentDateAvailable > SourceFileManager.shared.lastDataSourceDate() ?? .distantPast { - Text("import " + mostRecentDateAvailable.monthYearFormatted) - } - } + Text(FileImportManager.shared.currentlyImportingLabel()) } } else if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable, let lastDataSourceDate = SourceFileManager.shared.lastDataSourceDate() { if mostRecentDateAvailable > lastDataSourceDate { @@ -189,30 +191,49 @@ struct MainView: View { checkingFilesAttempt += 1 checkingFiles = false + if lastDataSource == nil || (dataStore.monthData.first(where: { $0.monthKey == "07-2024" }) == nil) { + await _downloadPreviousDate() + await _importMandatoryData() + } + if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable, mostRecentDateAvailable > SourceFileManager.shared.lastDataSourceDate() ?? .distantPast { - _startImporting() + + print("importing \(mostRecentDateAvailable)") + await _startImporting(importingDate: mostRecentDateAvailable) } } + + private func _startImporting(importingDate: Date) async { + await MainActor.run { + FileImportManager.shared.currentImportDate = importingDate + } + let lastDataSource = await FileImportManager.shared.importDataFromFFT(importingDate: importingDate) + dataStore.appSettings.lastDataSource = lastDataSource + dataStore.appSettingsStorage.write() + await _calculateMonthData(dataSource: lastDataSource) + await MainActor.run { + FileImportManager.shared.currentImportDate = nil + } + await _downloadPreviousDate() + } - private func _startImporting() { - importingFiles = true - Task { - let lastDataSource = await FileImportManager.shared.importDataFromFFT() - await MainActor.run { - importingFiles = false - } - dataStore.appSettings.lastDataSource = lastDataSource - dataStore.appSettingsStorage.write() - if let lastDataSource, let mostRecentDate = URL.importDateFormatter.date(from: lastDataSource) { - await MonthData.calculateCurrentUnrankedValues(mostRecentDateAvailable: mostRecentDate) - } - await _downloadPreviousDate() + private func _calculateMonthData(dataSource: String?) async { + if let dataSource, let mostRecentDate = URL.importDateFormatter.date(from: dataSource) { + await MonthData.calculateCurrentUnrankedValues(fromDate: mostRecentDate) } } private func _downloadPreviousDate() async { await SourceFileManager.shared.getAllFiles(initialDate: "05-2024") } + + private func _importMandatoryData() async { + let mandatoryKey = "07-2024" + if dataStore.monthData.first(where: { $0.monthKey == mandatoryKey }) == nil, let importingDate = URL.importDateFormatter.date(from: mandatoryKey) { + print("importing mandatory july data") + await _startImporting(importingDate: importingDate) + } + } } //#Preview { diff --git a/PadelClub/Views/Navigation/Umpire/PadelClubView.swift b/PadelClub/Views/Navigation/Umpire/PadelClubView.swift index a7a6c78..2b4b0d8 100644 --- a/PadelClub/Views/Navigation/Umpire/PadelClubView.swift +++ b/PadelClub/Views/Navigation/Umpire/PadelClubView.swift @@ -12,7 +12,6 @@ struct PadelClubView: View { @State private var uuid: UUID = UUID() @State private var checkingFilesAttempt: Int = 0 @State private var checkingFiles: Bool = false - @AppStorage("importingFiles") var importingFiles: Bool = false @EnvironmentObject var dataStore: DataStore @@ -38,7 +37,22 @@ struct PadelClubView: View { var body: some View { List { - #if targetEnvironment(simulator) + let monthData = dataStore.monthData.sorted(by: \.creationDate).reversed() + + if let currentMonth = monthData.first, currentMonth.incompleteMode { + Section { + Text("Attention, depuis Août 2024, les données fédérales publiques des joueurs (messieurs) récupérables sont incomplètes car limité au 40.000 premiers joueurs. Le rang d'un joueur non-classé n'est donc pas calculable pour le moment, Padel Club utilisera une valeur par défaut de de 60.000.") + + Text("Un classement souligné comme ci-dessous indiquera que l'information provient d'un mois précédent.") + + Text("10342ème") + .background { + UnderlineView() + } + } + } + + #if DEBUG /* ["36435", "BOUNOUA", "walid", "France", "3311600", "15,00", "Non", "2", "AUVERGNE RHONE-ALPES", "50 73 0046", "CHAMBERY TC"] ["36435", "BRUL…", "Romain", "France", "2993139", "15,00", "Non", "2", "NOUVELLE AQUITAINE", "59 33 0447", "SAINT LOUBES TC"] @@ -83,7 +97,7 @@ struct PadelClubView: View { } } - if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable, _lastDataSourceDate.isEarlierThan(mostRecentDateAvailable), importingFiles == false { + if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable, _lastDataSourceDate.isEarlierThan(mostRecentDateAvailable), FileImportManager.shared.isImportingFile() == false { Section { RowButtonView("Importer \(mostRecentDateAvailable.monthYearFormatted)") { _startImporting() @@ -100,7 +114,7 @@ struct PadelClubView: View { Text("Padel Club va récupérer les données des mois précédents") } - if importingFiles { + if FileImportManager.shared.isImportingFile() { ContentUnavailableView("Importation en cours", systemImage: "server.rack", description: Text("Une importation des données fédérales publiques est en cours, veuillez patienter.")) } else if (players.isEmpty || lastDataSource == nil) { ContentUnavailableView { @@ -116,7 +130,6 @@ struct PadelClubView: View { } } - let monthData = dataStore.monthData.sorted(by: \.creationDate).reversed() ForEach(monthData) { monthData in Section { LabeledContent { @@ -134,13 +147,15 @@ struct PadelClubView: View { Text("Dames") } -// LabeledContent { -// if let anonymousCount = monthData.anonymousCount { -// Text(anonymousCount.formatted()) -// } -// } label: { -// Text("Joueurs anonymes") -// } + if monthData.incompleteMode { + LabeledContent { + if let anonymousCount = monthData.anonymousCount { + Text(anonymousCount.formatted()) + } + } label: { + Text("Joueurs anonymes") + } + } LabeledContent { if let maleUnrankedValue = monthData.maleUnrankedValue { @@ -148,7 +163,11 @@ struct PadelClubView: View { } } label: { Text("Rang d'un non classé") - Text("Messieurs") + if monthData.incompleteMode { + Text("Messieurs (estimation car incomplet)") + } else { + Text("Messieurs") + } } LabeledContent { if let femaleUnrankedValue = monthData.femaleUnrankedValue { @@ -170,7 +189,7 @@ struct PadelClubView: View { FooterButtonView("recalculer") { Task { if let monthKeyDate = URL.importDateFormatter.date(from: monthData.monthKey) { - await MonthData.calculateCurrentUnrankedValues(mostRecentDateAvailable: monthKeyDate) + await MonthData.calculateCurrentUnrankedValues(fromDate: monthKeyDate) } } } @@ -193,14 +212,10 @@ struct PadelClubView: View { @ViewBuilder func _activityStatus() -> some View { - if checkingFiles || importingFiles { + if checkingFiles || FileImportManager.shared.isImportingFile() { HStack(spacing: 20) { ProgressView() - if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable { - if mostRecentDateAvailable > SourceFileManager.shared.lastDataSourceDate() ?? .distantPast { - Text("import " + mostRecentDateAvailable.monthYearFormatted) - } - } + Text(FileImportManager.shared.currentlyImportingLabel()) } } else if let _mostRecentDateAvailable { if _mostRecentDateAvailable > _lastDataSourceDate ?? .distantPast { @@ -226,18 +241,21 @@ struct PadelClubView: View { } private func _startImporting() { - importingFiles = true + let importingDate = SourceFileManager.shared.mostRecentDateAvailable + FileImportManager.shared.currentImportDate = importingDate Task { - let lastDataSource = await FileImportManager.shared.importDataFromFFT() - await MainActor.run { - importingFiles = false + if let importingDate { + let lastDataSource = await FileImportManager.shared.importDataFromFFT(importingDate: importingDate) + dataStore.appSettings.lastDataSource = lastDataSource + dataStore.appSettingsStorage.write() + if let lastDataSource, let mostRecentDate = URL.importDateFormatter.date(from: lastDataSource) { + await MonthData.calculateCurrentUnrankedValues(fromDate: mostRecentDate) + } + viewContext.refreshAllObjects() } - dataStore.appSettings.lastDataSource = lastDataSource - dataStore.appSettingsStorage.write() - if let lastDataSource, let mostRecentDate = URL.importDateFormatter.date(from: lastDataSource) { - await MonthData.calculateCurrentUnrankedValues(mostRecentDateAvailable: mostRecentDate) + await MainActor.run { + FileImportManager.shared.currentImportDate = nil } - viewContext.refreshAllObjects() } } diff --git a/PadelClub/Views/Shared/ImportedPlayerView.swift b/PadelClub/Views/Shared/ImportedPlayerView.swift index d16fdef..0f65159 100644 --- a/PadelClub/Views/Shared/ImportedPlayerView.swift +++ b/PadelClub/Views/Shared/ImportedPlayerView.swift @@ -41,7 +41,12 @@ struct ImportedPlayerView: View { HStack { HStack(alignment: .top, spacing: 0) { Text(player.formattedRank()).italic(player.isAssimilated) - .font(.title3) + .font(.title3) + .background { + if player.isNotFromCurrentDate() { + UnderlineView() + } + } if let rank = player.getRank() { Text(rank.ordinalFormattedSuffix()).italic(player.isAssimilated) .font(.caption) diff --git a/PadelClub/Views/Tournament/FileImportView.swift b/PadelClub/Views/Tournament/FileImportView.swift index e6ffcdb..f7e9c42 100644 --- a/PadelClub/Views/Tournament/FileImportView.swift +++ b/PadelClub/Views/Tournament/FileImportView.swift @@ -484,7 +484,7 @@ struct FileImportView: View { teams.removeAll() } if let rankSourceDate = tournament.rankSourceDate, tournament.unrankValue(for: false) == nil || tournament.unrankValue(for: true) == nil { - await MonthData.calculateCurrentUnrankedValues(mostRecentDateAvailable: rankSourceDate) + await MonthData.calculateCurrentUnrankedValues(fromDate: rankSourceDate) } let event: Event? = tournament.eventObject() diff --git a/PadelClub/Views/Tournament/Screen/AddTeamView.swift b/PadelClub/Views/Tournament/Screen/AddTeamView.swift index afd2fd3..59d03d9 100644 --- a/PadelClub/Views/Tournament/Screen/AddTeamView.swift +++ b/PadelClub/Views/Tournament/Screen/AddTeamView.swift @@ -205,7 +205,7 @@ struct AddTeamView: View { } if let mostRecentDate { - andPredicates.append(NSPredicate(format: "importDate == %@", mostRecentDate as CVarArg)) + //andPredicates.append(NSPredicate(format: "importDate == %@", mostRecentDate as CVarArg)) } if nameComponents.count > 1 {