diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index 5bf1cab..758e0a9 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -34,7 +34,6 @@ C4A47DB32B86387500ADC637 /* AccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A47DB22B86387500ADC637 /* AccountView.swift */; }; FF089EB42BB0020000F0AEC7 /* PlayerSexPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF089EB32BB0020000F0AEC7 /* PlayerSexPickerView.swift */; }; FF089EB62BB00A3800F0AEC7 /* TeamRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF089EB52BB00A3800F0AEC7 /* TeamRowView.swift */; }; - FF089EB82BB00ABF00F0AEC7 /* InscriptionTipsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF089EB72BB00ABF00F0AEC7 /* InscriptionTipsView.swift */; }; FF089EBB2BB0120700F0AEC7 /* PlayerPopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF089EBA2BB0120700F0AEC7 /* PlayerPopoverView.swift */; }; FF089EBD2BB0287D00F0AEC7 /* PlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF089EBC2BB0287D00F0AEC7 /* PlayerView.swift */; }; FF089EBF2BB0B14600F0AEC7 /* FileImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF089EBE2BB0B14600F0AEC7 /* FileImportView.swift */; }; @@ -159,6 +158,7 @@ FFD783FF2B91BA42000F62A6 /* PadelClubView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFD783FE2B91BA42000F62A6 /* PadelClubView.swift */; }; FFD784022B91C1B4000F62A6 /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFD784012B91C1B4000F62A6 /* WelcomeView.swift */; }; FFD784042B91C280000F62A6 /* EmptyActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFD784032B91C280000F62A6 /* EmptyActivityView.swift */; }; + FFDB1C6D2BB2A02000F1E467 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDB1C6C2BB2A02000F1E467 /* AppSettings.swift */; }; FFDDD40C2B93B2BB00C91A49 /* DeferredViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDDD40B2B93B2BB00C91A49 /* DeferredViewModifier.swift */; }; FFF8ACCD2B92367B008466FA /* FederalPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF8ACCC2B92367B008466FA /* FederalPlayer.swift */; }; FFF8ACD42B92392C008466FA /* SourceFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF8ACD32B92392C008466FA /* SourceFileManager.swift */; }; @@ -244,7 +244,6 @@ C4A47DB22B86387500ADC637 /* AccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountView.swift; sourceTree = ""; }; FF089EB32BB0020000F0AEC7 /* PlayerSexPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerSexPickerView.swift; sourceTree = ""; }; FF089EB52BB00A3800F0AEC7 /* TeamRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeamRowView.swift; sourceTree = ""; }; - FF089EB72BB00ABF00F0AEC7 /* InscriptionTipsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InscriptionTipsView.swift; sourceTree = ""; }; FF089EBA2BB0120700F0AEC7 /* PlayerPopoverView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerPopoverView.swift; sourceTree = ""; }; FF089EBC2BB0287D00F0AEC7 /* PlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerView.swift; sourceTree = ""; }; FF089EBE2BB0B14600F0AEC7 /* FileImportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileImportView.swift; sourceTree = ""; }; @@ -369,6 +368,7 @@ FFD784002B91BF79000F62A6 /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; FFD784012B91C1B4000F62A6 /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = ""; }; FFD784032B91C280000F62A6 /* EmptyActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyActivityView.swift; sourceTree = ""; }; + FFDB1C6C2BB2A02000F1E467 /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = ""; }; FFDDD40B2B93B2BB00C91A49 /* DeferredViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeferredViewModifier.swift; sourceTree = ""; }; FFF8ACCC2B92367B008466FA /* FederalPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FederalPlayer.swift; sourceTree = ""; }; FFF8ACD32B92392C008466FA /* SourceFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceFileManager.swift; sourceTree = ""; }; @@ -499,6 +499,7 @@ C4A47D622B6D3D6500ADC637 /* Club.swift */, FF8F263E2BAD7D5C00650388 /* Event.swift */, FF1DC5522BAB354A00FD8220 /* MockData.swift */, + FFDB1C6C2BB2A02000F1E467 /* AppSettings.swift */, FF6EC9012B94799200EA7F5A /* Coredata */, FF6EC9022B9479B900EA7F5A /* Federal */, ); @@ -789,7 +790,6 @@ FF8F264A2BAE0B4100650388 /* TournamentDatePickerView.swift */, FF8F26482BAE0B4100650388 /* TournamentFormatSelectionView.swift */, FF8F26492BAE0B4100650388 /* TournamentLevelPickerView.swift */, - FF089EB72BB00ABF00F0AEC7 /* InscriptionTipsView.swift */, FF0EC5212BB173E70056B6D1 /* UpdateSourceRankDateView.swift */, ); path = Components; @@ -1090,6 +1090,7 @@ FF967CF22BAECC0B00A9A3BD /* TeamScore.swift in Sources */, FFD783FD2B91B9ED000F62A6 /* AgendaDestinationPickerView.swift in Sources */, FF6EC9002B94794700EA7F5A /* PresentationContext.swift in Sources */, + FFDB1C6D2BB2A02000F1E467 /* AppSettings.swift in Sources */, FF0EC5202BB16F680056B6D1 /* SwiftParser.swift in Sources */, C4A47DA92B85F82100ADC637 /* ChangePasswordView.swift in Sources */, FF6EC8F72B94773200EA7F5A /* RowButtonView.swift in Sources */, @@ -1156,7 +1157,6 @@ C4A47DAD2B85FCCD00ADC637 /* User.swift in Sources */, FF967D012BAEF0B400A9A3BD /* MatchSummaryView.swift in Sources */, FF8F26452BAE0A3400650388 /* TournamentDurationManagerView.swift in Sources */, - FF089EB82BB00ABF00F0AEC7 /* InscriptionTipsView.swift in Sources */, FF1DC5532BAB354A00FD8220 /* MockData.swift in Sources */, FF967D092BAF3D4000A9A3BD /* TeamDetailView.swift in Sources */, FF8F26382BAD523300650388 /* PadelRule.swift in Sources */, diff --git a/PadelClub/Data/AppSettings.swift b/PadelClub/Data/AppSettings.swift new file mode 100644 index 0000000..864ea23 --- /dev/null +++ b/PadelClub/Data/AppSettings.swift @@ -0,0 +1,20 @@ +// +// AppSettings.swift +// PadelClub +// +// Created by Razmig Sarkissian on 26/03/2024. +// + +import Foundation +import LeStorage + +class AppSettings: MicroStorable { + + static var fileName: String { "appsettings.json" } + + required init() { + + } + +// var id: String = Store.randomId() +} diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index 7d9cb50..555e993 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -88,12 +88,20 @@ class Tournament : ModelObject, Storable { case build } + func hasEnded() -> Bool { + endDate != nil + } + func state() -> Tournament.State { if groupStageCount > 0 && groupStages().isEmpty == false { return .build } return .initial } + + func inscriptionClosed() -> Bool { + closedRegistrationDate != nil + } func groupStages() -> [GroupStage] { Store.main.filter { $0.tournament == self.id }.sorted(by: \.index) @@ -189,13 +197,10 @@ class Tournament : ModelObject, Storable { guard let newDate else { return } rankSourceDate = newDate - let maleDataURLs = SourceFile.allFiles(true).filter { $0.dateFromPath == newDate } - let femaleDataURLs = SourceFile.allFiles(false).filter { $0.dateFromPath == newDate } - - let lastRankWoman = femaleDataURLs.compactMap { $0.getUnrankedValue() }.first - let lastRankMan = maleDataURLs.compactMap { $0.getUnrankedValue() }.sorted().last + let lastRankWoman = SourceFileManager.shared.getUnrankValue(forMale: false, rankSourceDate: rankSourceDate) + let lastRankMan = SourceFileManager.shared.getUnrankValue(forMale: true, rankSourceDate: rankSourceDate) - let dataURLs = maleDataURLs + femaleDataURLs + let dataURLs = SourceFileManager.shared.allFiles.filter({ $0.dateFromPath == newDate }) let sources = dataURLs.map { CSVParser(url: $0) } await unsortedPlayers().concurrentForEach { player in diff --git a/PadelClub/Manager/FileImportManager.swift b/PadelClub/Manager/FileImportManager.swift index 2ddd5fc..327ce5b 100644 --- a/PadelClub/Manager/FileImportManager.swift +++ b/PadelClub/Manager/FileImportManager.swift @@ -15,7 +15,7 @@ class FileImportManager { return false } do { - return try SourceFile.allFilesSortedByDate(false).first(where: { + return try SourceFileManager.shared.allFilesSortedByDate(false).first(where: { let fileContent = try String(contentsOf: $0) return fileContent.contains(";\(license);") }) != nil @@ -30,7 +30,7 @@ class FileImportManager { return false } do { - return try SourceFile.allFilesSortedByDate(true).first(where: { + return try SourceFileManager.shared.allFilesSortedByDate(true).first(where: { let fileContent = try String(contentsOf: $0) return fileContent.contains(";\(license);") }) != nil @@ -253,7 +253,7 @@ class FileImportManager { } func importDataFromFFT() async -> String? { - if let importingDate = SourceFile.mostRecentDateAvailable { + if let importingDate = SourceFileManager.shared.mostRecentDateAvailable { for source in SourceFile.allCases { for fileURL in source.currentURLs { let p = readCSV(inputFile: fileURL) diff --git a/PadelClub/Manager/SourceFileManager.swift b/PadelClub/Manager/SourceFileManager.swift index 07fc1f5..02ec6e8 100644 --- a/PadelClub/Manager/SourceFileManager.swift +++ b/PadelClub/Manager/SourceFileManager.swift @@ -10,8 +10,17 @@ import Foundation class SourceFileManager { static let shared = SourceFileManager() + var lastDataSource: String? { + UserDefaults.standard.string(forKey: "lastDataSource") + } + + func lastDataSourceDate() -> Date? { + guard let lastDataSource else { return nil } + return URL.importDateFormatter.date(from: lastDataSource) + } + func fetchData() async { - if let mostRecent = SourceFile.mostRecentDateAvailable, let current = Calendar.current.date(byAdding: .month, value: 1, to: mostRecent), current > mostRecent { + if let mostRecent = mostRecentDateAvailable, let current = Calendar.current.date(byAdding: .month, value: 1, to: mostRecent), current > mostRecent { await fetchData(fromDate: current) } else { await fetchData(fromDate: Date()) @@ -50,7 +59,7 @@ class SourceFileManager { } catch { print("downloadRankingData", error) - if SourceFile.mostRecentDateAvailable == nil { + if mostRecentDateAvailable == nil { if let previousDate = Calendar.current.date(byAdding: .month, value: -1, to: current) { await fetchData(fromDate: previousDate) } @@ -65,7 +74,7 @@ class SourceFileManager { URL.importDateFormatter.date(from: $0) } .filter { date in - SourceFile.allFiles.contains(where: { $0.dateFromPath == date }) == false + allFiles.contains(where: { $0.dateFromPath == date }) == false } await dates.concurrentForEach { date in @@ -96,17 +105,18 @@ class SourceFileManager { } return months } -} - -enum SourceFile: String, CaseIterable { - case dames = "DAMES" - case messieurs = "MESSIEURS" - static var mostRecentDateAvailable: Date? { + func getUnrankValue(forMale: Bool, rankSourceDate: Date?) -> Int? { + let _rankSourceDate = rankSourceDate ?? mostRecentDateAvailable + let urls = allFiles(forMale).filter { $0.dateFromPath == _rankSourceDate } + return urls.compactMap { $0.getUnrankedValue() }.sorted().last + } + + var mostRecentDateAvailable: Date? { allFiles(false).first?.dateFromPath } - static func removeAllFilesFromServer() { + func removeAllFilesFromServer() { let docDir = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) let allFiles = try! FileManager.default.contentsOfDirectory(at: docDir, includingPropertiesForKeys: nil) allFiles.filter { $0.pathExtension == "csv" }.forEach { url in @@ -114,7 +124,7 @@ enum SourceFile: String, CaseIterable { } } - static var allFiles: [URL] { + var allFiles: [URL] { let docDir = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) let allFiles = try! FileManager.default.contentsOfDirectory(at: docDir, includingPropertiesForKeys: nil).filter({ url in url.pathExtension == "csv" @@ -123,15 +133,20 @@ enum SourceFile: String, CaseIterable { return (allFiles + (Bundle.main.urls(forResourcesWithExtension: "csv", subdirectory: nil) ?? [])).sorted(by: \.dateFromPath).reversed() } - static func allFiles(_ isManPlayer: Bool) -> [URL] { + func allFiles(_ isManPlayer: Bool) -> [URL] { allFiles.filter({ url in url.path().contains(isManPlayer ? SourceFile.messieurs.rawValue : SourceFile.dames.rawValue) }) } - static func allFilesSortedByDate(_ isManPlayer: Bool) -> [URL] { + func allFilesSortedByDate(_ isManPlayer: Bool) -> [URL] { return allFiles(isManPlayer) } +} + +enum SourceFile: String, CaseIterable { + case dames = "DAMES" + case messieurs = "MESSIEURS" var filesFromServer: [URL] { let docDir = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) diff --git a/PadelClub/Manager/Tips.swift b/PadelClub/Manager/Tips.swift index 06bdc5b..ccfe85e 100644 --- a/PadelClub/Manager/Tips.swift +++ b/PadelClub/Manager/Tips.swift @@ -157,7 +157,7 @@ struct InscriptionManagerCreateInputTip: Tip { var message: Text? { - Text("Si le joueur est introuvable, cela indique qu'il n'a jamais fait de compétition, rajoutez-le rapidement manuellement. Padel Club calcul le rang du non-classé ce mois-ci automatiquement.") + Text("Si le joueur est introuvable, cela indique qu'il n'a jamais fait de compétition, rajoutez-le rapidement manuellement. Padel Club calcul le rang du non-classé de ce mois-ci automatiquement.") } var image: Image? { diff --git a/PadelClub/Views/Navigation/MainView.swift b/PadelClub/Views/Navigation/MainView.swift index b194d33..fa5e9fe 100644 --- a/PadelClub/Views/Navigation/MainView.swift +++ b/PadelClub/Views/Navigation/MainView.swift @@ -25,16 +25,6 @@ struct MainView: View { animation: .default) private var players: FetchedResults - - var _mostRecentDateAvailable: Date? { - SourceFile.mostRecentDateAvailable - } - - var _lastDataSourceDate: Date? { - guard let lastDataSource else { return nil } - return URL.importDateFormatter.date(from: lastDataSource) - } - var body: some View { TabView { if dataStore.tournaments.isEmpty { @@ -91,18 +81,18 @@ struct MainView: View { if importingFiles { HStack(spacing: 20) { ProgressView() - if let _mostRecentDateAvailable { - if _mostRecentDateAvailable > _lastDataSourceDate ?? .distantPast { - Text("import " + _mostRecentDateAvailable.monthYearFormatted) + if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable { + if mostRecentDateAvailable > SourceFileManager.shared.lastDataSourceDate() ?? .distantPast { + Text("import " + mostRecentDateAvailable.monthYearFormatted) } } } - } else if let _mostRecentDateAvailable { - if _mostRecentDateAvailable > _lastDataSourceDate ?? .distantPast { - Label(_mostRecentDateAvailable.monthYearFormatted + " disponible", systemImage: "exclamationmark.triangle") + } else if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable { + if mostRecentDateAvailable > SourceFileManager.shared.lastDataSourceDate() ?? .distantPast { + Label(mostRecentDateAvailable.monthYearFormatted + " disponible", systemImage: "exclamationmark.triangle") .labelStyle(.titleAndIcon) } else { - Label(_mostRecentDateAvailable.monthYearFormatted, systemImage: "checkmark") + Label(mostRecentDateAvailable.monthYearFormatted, systemImage: "checkmark") .labelStyle(.titleAndIcon) } } @@ -118,7 +108,7 @@ struct MainView: View { checkingFilesAttempt += 1 checkingFiles = false - if let _mostRecentDateAvailable, _mostRecentDateAvailable > _lastDataSourceDate ?? .distantPast { + if let mostRecentDateAvailable = SourceFileManager.shared.mostRecentDateAvailable, mostRecentDateAvailable > SourceFileManager.shared.lastDataSourceDate() ?? .distantPast { _startImporting() } } diff --git a/PadelClub/Views/Navigation/PadelClubView.swift b/PadelClub/Views/Navigation/PadelClubView.swift index a618a5e..8c3eea0 100644 --- a/PadelClub/Views/Navigation/PadelClubView.swift +++ b/PadelClub/Views/Navigation/PadelClubView.swift @@ -23,7 +23,7 @@ struct PadelClubView: View { var _mostRecentDateAvailable: Date? { - SourceFile.mostRecentDateAvailable + SourceFileManager.shared.mostRecentDateAvailable } var _lastDataSourceDate: Date? { @@ -93,7 +93,7 @@ struct PadelClubView: View { print("check files on internet") print("check if any files on internet are more recent than here") checkingFiles = true - await fetchData() + await SourceFileManager.shared.fetchData() checkingFilesAttempt += 1 checkingFiles = false } @@ -105,56 +105,6 @@ struct PadelClubView: View { importingFiles = false } } - - private func fetchData() async { - if let mostRecent = SourceFile.mostRecentDateAvailable, let current = Calendar.current.date(byAdding: .month, value: 1, to: mostRecent), current > mostRecent { - await fetchData(fromDate: current) - } else { - await fetchData(fromDate: Date()) - } - } - - private func _removeAllData(fromDate current: Date) { - let lastStringDate = URL.importDateFormatter.string(from: current) - let files = ["MESSIEURS", "MESSIEURS-2", "MESSIEURS-3", "MESSIEURS-4", "DAMES"] - files.forEach { fileName in - NetworkManager.shared.removeRankingData(lastDateString: lastStringDate, fileName: fileName) - } - } - - private func fetchData(fromDate current: Date) async { - let lastStringDate = URL.importDateFormatter.string(from: current) - - let files = ["MESSIEURS", "MESSIEURS-2", "MESSIEURS-3", "MESSIEURS-4", "DAMES"] - do { - try await withThrowingTaskGroup(of: Void.self) { group in // Mark 1 - - for file in files { - group.addTask { - try await NetworkManager.shared.downloadRankingData(lastDateString: lastStringDate, fileName: file) - } - } - - try await group.waitForAll() - } - - if current < Date() { - if let nextCurrent = Calendar.current.date(byAdding: .month, value: 1, to: current) { - await fetchData(fromDate: nextCurrent) - } - } - } catch { - print("downloadRankingData", error) - - if _mostRecentDateAvailable == nil { - if let previousDate = Calendar.current.date(byAdding: .month, value: -1, to: current) { - await fetchData(fromDate: previousDate) - } - } - } - - } - } #Preview { diff --git a/PadelClub/Views/Shared/SelectablePlayerListView.swift b/PadelClub/Views/Shared/SelectablePlayerListView.swift index 5d75dd6..c32a32d 100644 --- a/PadelClub/Views/Shared/SelectablePlayerListView.swift +++ b/PadelClub/Views/Shared/SelectablePlayerListView.swift @@ -106,7 +106,7 @@ struct SelectablePlayerListView: View { } .id(importingFiles) .overlay { - if let importedFile = SourceFile.mostRecentDateAvailable, importingFiles { + if let importedFile = SourceFileManager.shared.mostRecentDateAvailable, importingFiles { ContentUnavailableView("Importation en cours", systemImage: "square.and.arrow.down", description: Text("Padel Club récupère les données de \(importedFile.monthYearFormatted)")) } diff --git a/PadelClub/Views/Tournament/Screen/Components/InscriptionTipsView.swift b/PadelClub/Views/Tournament/Screen/Components/InscriptionTipsView.swift deleted file mode 100644 index 669a5b7..0000000 --- a/PadelClub/Views/Tournament/Screen/Components/InscriptionTipsView.swift +++ /dev/null @@ -1,86 +0,0 @@ -// -// InscriptionTipsView.swift -// PadelClub -// -// Created by Razmig Sarkissian on 24/03/2024. -// - -import SwiftUI -import TipKit - -struct InscriptionTipsView: View { - @Environment(Tournament.self) private var tournament: Tournament - - var body: some View { - List { - - Section { - - let fileTip = InscriptionManagerFileInputTip() - TipView(fileTip) { action in - if action.id == "website" { - } else if action.id == "add-team-file" { - } - } - .tipStyle(tint: nil) - } - - Section { - - let pasteTip = InscriptionManagerPasteInputTip() - TipView(pasteTip) { action in - if let paste = UIPasteboard.general.string { - //self.pasteField = paste - } - } - .tipStyle(tint: nil) - } - - Section { - - let searchTip = InscriptionManagerSearchInputTip() - TipView(searchTip) { action in - //presentPlayerCreation = true - } - .tipStyle(tint: nil) - } - - Section { - - let createTip = InscriptionManagerCreateInputTip() - TipView(createTip) { action in - //presentPlayerSelection = true - } - .tipStyle(tint: nil) - } - - Section { - ContentUnavailableView("Aucune équipe", systemImage: "person.2.slash", description: Text("Vous n'avez encore aucune équipe dans votre liste d'attente.")) - } - - // if let mostRecentDate, let currentRankSourceDate, currentRankSourceDate < mostRecentDate, tournament.isOver == false { - // - // if #available(iOS 17.0, *) { - // Section { - // let tip = InscriptionManagerRankUpdateTip() - // TipView(tip) { action in - // self.currentRankSourceDate = mostRecentDate - // } - // .tipStyle(tint: nil) - // } - // } - // - // rankingDateSourcePickerView(showDateInLabel: false) - // } else if tournament.currentRankSourceDate == nil { - // rankingDateSourcePickerView(showDateInLabel: false) - // } - // - - } - } -} - -#Preview { - InscriptionTipsView() - .environment(Tournament.mock()) -} diff --git a/PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift b/PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift index 7c04217..f786e2a 100644 --- a/PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift +++ b/PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift @@ -32,6 +32,12 @@ struct InscriptionManagerView: View { let slideToDeleteTip = SlideToDeleteTip() let inscriptionManagerWomanRankTip = InscriptionManagerWomanRankTip() + let fileTip = InscriptionManagerFileInputTip() + let pasteTip = InscriptionManagerPasteInputTip() + let searchTip = InscriptionManagerSearchInputTip() + let createTip = InscriptionManagerCreateInputTip() + let rankUpdateTip = InscriptionManagerRankUpdateTip() + let categoryOption: PlayerFilterOption let filterable: Bool @@ -222,7 +228,7 @@ struct InscriptionManagerView: View { private func _teamRegisteredView() -> some View { List { Section { - rankingDateSourcePickerView(showDateInLabel: true) + _rankHandlerView() let duplicates = tournament.duplicates() DisclosureGroup { @@ -271,7 +277,7 @@ struct InscriptionManagerView: View { RowButtonView(title: "Créer une équipe") { Task { await MainActor.run() { -// fetchPlayers.nsPredicate = _pastePredicate(pasteField: searchField, mostRecentDate: tournament.rankSourceDate) + fetchPlayers.nsPredicate = _pastePredicate(pasteField: searchField, mostRecentDate: tournament.rankSourceDate) pasteString = searchField } } @@ -327,7 +333,7 @@ struct InscriptionManagerView: View { if testCreatedPlayers.isEmpty == false || pasteString != nil || editedTeam != nil { _buildingTeamView() } else if tournament.unsortedTeams().isEmpty { - InscriptionTipsView() + _inscriptionTipsView() } else { _teamRegisteredView() } @@ -377,15 +383,63 @@ struct InscriptionManagerView: View { } } - ToolbarItem(placement: .topBarTrailing) { - Menu { - Button { - presentImportView = true + if editedTeam == nil { + ToolbarItem(placement: .navigationBarTrailing) { + Menu { + if tournament.inscriptionClosed() == false { + Menu { + //sortingTypePickerView + } label: { + Text("Méthode de sélection") + Text(tournament.teamSortingType.localizedLabel()) + } + Divider() + rankingDateSourcePickerView(showDateInLabel: true) + if tournament.teamSortingType == .inscriptionDate { + Divider() + //prioritizeClubMembersButton + } + Divider() + Button { + let count = tournament.unsortedTeams().count + if tournament.teamCount > count { + tournament.teamCount = count + } + tournament.closedRegistrationDate = Date() + _save() + } label: { + Label("Clôturer", systemImage: "lock") + } + Divider() +// ShareLink(item: tournament.pasteDataForImporting) { +// Text("Exporter les paires") +// } + + Button { + presentImportView = true + } label: { + Label("Importer beach-padel", systemImage: "square.and.arrow.down") + } + if let url = URL(string: "beach-padel.app.fft.fr") { + Link(destination: url) { + Label("beach-padel.app.fft.fr", systemImage: "safari") + } + } + } else { + Button { + tournament.closedRegistrationDate = nil + _save() + } label: { + Label("Ré-ouvrir", systemImage: "lock.open") + } + } } label: { - Label("Importer", systemImage: "square.and.arrow.down") + if tournament.inscriptionClosed() == false { + LabelOptions() + } else { + Label("Clôturer", systemImage: "lock") + } } - } label: { - LabelOptions() } } } @@ -415,7 +469,7 @@ struct InscriptionManagerView: View { guard let first = strings.first else { return } Task { await MainActor.run() { -// fetchPlayers.nsPredicate = _pastePredicate(pasteField: first, mostRecentDate: tournament.rankSourceDate) + fetchPlayers.nsPredicate = _pastePredicate(pasteField: first, mostRecentDate: tournament.rankSourceDate) pasteString = first } } @@ -450,13 +504,13 @@ struct InscriptionManagerView: View { Text("inconnu").tag(nil as Date?) } - let dates = Array(Set(SourceFile.allFilesSortedByDate(tournament.tournamentCategory.rankingDataSourceMale).map({ $0.dateFromPath }))).sorted().reversed() + let dates = Array(Set(SourceFileManager.shared.allFilesSortedByDate(tournament.tournamentCategory.rankingDataSourceMale).map({ $0.dateFromPath }))).sorted().reversed() ForEach(dates, id: \.self) { date in Text(date.monthYearFormatted).tag(date as Date?) } } label: { - Text("Classement mensuel utilisé") + Text("Classement utilisé") if showDateInLabel { if let currentRankSourceDate { Text(currentRankSourceDate.monthYearFormatted) @@ -492,6 +546,72 @@ struct InscriptionManagerView: View { return .all } } + + @ViewBuilder + func _inscriptionTipsView() -> some View { + List { + Section { + + TipView(fileTip) { action in + if action.id == "website" { + } else if action.id == "add-team-file" { + } + } + .tipStyle(tint: nil) + } + + Section { + + TipView(pasteTip) { action in + if let paste = UIPasteboard.general.string { + self.pasteString = paste + } + } + .tipStyle(tint: nil) + } + + Section { + + TipView(searchTip) { action in + presentPlayerCreation = true + } + .tipStyle(tint: nil) + } + + Section { + + TipView(createTip) { action in + presentPlayerSearch = true + } + .tipStyle(tint: nil) + } + + Section { + ContentUnavailableView("Aucune équipe", systemImage: "person.2.slash", description: Text("Vous n'avez encore aucune équipe dans votre liste d'attente.")) + } + + _rankHandlerView() + } + } + + @ViewBuilder + func _rankHandlerView() -> some View { + if let mostRecentDate = SourceFileManager.shared.lastDataSourceDate(), let currentRankSourceDate, currentRankSourceDate < mostRecentDate, tournament.hasEnded() == false { + Section { + TipView(rankUpdateTip) { action in + self.currentRankSourceDate = mostRecentDate + } + .tipStyle(tint: nil) + } + rankingDateSourcePickerView(showDateInLabel: false) + } else if tournament.rankSourceDate == nil { + rankingDateSourcePickerView(showDateInLabel: false) + } + } + + func _save() { + try? dataStore.tournaments.addOrUpdate(instance: tournament) + } } #Preview { diff --git a/PadelClub/Views/Tournament/TournamentView.swift b/PadelClub/Views/Tournament/TournamentView.swift index e7a9681..29f6373 100644 --- a/PadelClub/Views/Tournament/TournamentView.swift +++ b/PadelClub/Views/Tournament/TournamentView.swift @@ -23,12 +23,9 @@ struct TournamentView: View { if tournament.missingUnrankedValue() { Button("update NC") { - Task { - tournament.maleUnrankedValue = await FederalPlayer.lastRank(mostRecentDateAvailable: _lastDataSourceDate, man: true) - tournament.femaleUnrankedValue = await FederalPlayer.lastRank(mostRecentDateAvailable: _lastDataSourceDate, man: false) - - try? dataStore.tournaments.addOrUpdate(instance: tournament) - } + tournament.femaleUnrankedValue = SourceFileManager.shared.getUnrankValue(forMale: false, rankSourceDate: tournament.rankSourceDate) + tournament.maleUnrankedValue = SourceFileManager.shared.getUnrankValue(forMale: true, rankSourceDate: tournament.rankSourceDate) + try? dataStore.tournaments.addOrUpdate(instance: tournament) } }