From cd730f3f03edb0ead16b7dfe0f166a8e26419a3c Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Sun, 16 Jun 2024 08:26:19 +0200 Subject: [PATCH] fix stuff --- PadelClub/Data/Tournament.swift | 2 +- PadelClub/Views/Calling/CallView.swift | 66 ++++++--- .../Screen/TableStructureView.swift | 46 +++++- .../Screen/TournamentRankView.swift | 51 ++++++- .../Tournament/TournamentBuildView.swift | 136 +++++++++--------- .../Views/Tournament/TournamentView.swift | 2 +- 6 files changed, 195 insertions(+), 108 deletions(-) diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index 409f071..301a840 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -1066,7 +1066,7 @@ class Tournament : ModelObject, Storable { return Array(allMatches.filter({ $0.hasEnded() }).sorted(by: \.computedEndDateForSorting).reversed().prefix(_limit)) } - func finalRanking() -> [Int: [String]] { + func finalRanking() async -> [Int: [String]] { var teams: [Int: [String]] = [:] var ids: Set = Set() let rounds = rounds() diff --git a/PadelClub/Views/Calling/CallView.swift b/PadelClub/Views/Calling/CallView.swift index fa5f74c..606e61c 100644 --- a/PadelClub/Views/Calling/CallView.swift +++ b/PadelClub/Views/Calling/CallView.swift @@ -85,16 +85,16 @@ struct CallView: View { } } - var finalMessage: String { + func finalMessage(reSummon: Bool) -> String { ContactType.callingMessage(tournament: tournament, startDate: callDate, roundLabel: roundLabel, matchFormat: matchFormat, reSummon: reSummon) } var reSummon: Bool { teams.allSatisfy({ $0.called() }) } - + var body: some View { - let callWord = reSummon ? "Reconvoquer" : "Convoquer" + let callWord : String = (reSummon ? "Reconvoquer" : "Convoquer") HStack { if teams.count == 1 { if let previousCallDate = teams.first?.callDate, Calendar.current.compare(previousCallDate, to: callDate, toGranularity: .minute) != .orderedSame { @@ -105,23 +105,10 @@ struct CallView: View { } else { Text(callWord + " ces \(teams.count) paires par") } - Button { - self._payTournamentAndExecute { - self._contactByMessage() - } - } label: { - Text("sms") - .underline() - } + + _summonMenu(byMessage: true) Text("ou") - Button { - self._payTournamentAndExecute { - self._contactByMail() - } - } label: { - Text("mail") - .underline() - } + _summonMenu(byMessage: false) } .font(.subheadline) .buttonStyle(.borderless) @@ -182,6 +169,39 @@ struct CallView: View { }) } + @ViewBuilder + private func _summonMenu(byMessage: Bool) -> some View { + if reSummon { + Menu { + Button("Convoquer") { + _summon(byMessage: byMessage, reSummon: false) + } + + Button("Re-convoquer") { + _summon(byMessage: byMessage, reSummon: true) + } + + } label: { + Text(byMessage ? "sms" : "mail") + .underline() + } + } else { + Button(byMessage ? "sms" : "mail") { + _summon(byMessage: byMessage, reSummon: false) + } + } + } + + private func _summon(byMessage: Bool, reSummon: Bool) { + self._payTournamentAndExecute { + if byMessage { + self._contactByMessage(reSummon: reSummon) + } else { + self._contactByMail(reSummon: reSummon) + } + } + } + fileprivate func _payTournamentAndExecute(_ handler: () -> ()) { do { try tournament.payIfNecessary() @@ -191,12 +211,12 @@ struct CallView: View { } } - fileprivate func _contactByMessage() { - contactType = .message(date: callDate, recipients: teams.flatMap { $0.getPhoneNumbers() }, body: finalMessage, tournamentBuild: nil) + fileprivate func _contactByMessage(reSummon: Bool) { + contactType = .message(date: callDate, recipients: teams.flatMap { $0.getPhoneNumbers() }, body: finalMessage(reSummon: reSummon), tournamentBuild: nil) } - fileprivate func _contactByMail() { - contactType = .mail(date: callDate, recipients: tournament.umpireMail(), bccRecipients: teams.flatMap { $0.getMail() }, body: finalMessage, subject: tournament.tournamentTitle(), tournamentBuild: nil) + fileprivate func _contactByMail(reSummon: Bool) { + contactType = .mail(date: callDate, recipients: tournament.umpireMail(), bccRecipients: teams.flatMap { $0.getMail() }, body: finalMessage(reSummon: reSummon), subject: tournament.tournamentTitle(), tournamentBuild: nil) } } diff --git a/PadelClub/Views/Tournament/Screen/TableStructureView.swift b/PadelClub/Views/Tournament/Screen/TableStructureView.swift index 4fd4a9c..4ca44a6 100644 --- a/PadelClub/Views/Tournament/Screen/TableStructureView.swift +++ b/PadelClub/Views/Tournament/Screen/TableStructureView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import LeStorage struct TableStructureView: View { @Environment(Tournament.self) private var tournament: Tournament @@ -133,6 +134,24 @@ struct TableStructureView: View { Text("Équipes en tableau final") } } + + Section { + RowButtonView("Sauver sans reconstuire l'existant") { + _saveWithoutRebuild() + } + } + + Section { + RowButtonView("Recontruire les poules", role:.destructive) { + _save(rebuildEverything: false) + } + } + + Section { + RowButtonView("Tout refaire", role: .destructive) { + _save(rebuildEverything: true) + } + } } .focused($stepperFieldIsFocused) .onChange(of: stepperFieldIsFocused) { @@ -204,17 +223,17 @@ struct TableStructureView: View { } } .confirmationDialog("Refaire la structure", isPresented: $presentRefreshStructureWarning, actions: { + Button("Sauver sans reconstuire l'existant") { + _saveWithoutRebuild() + } - if requirements.allSatisfy({ $0 == .groupStage }) { - Button("Refaire les poules") { - _save(rebuildEverything: false) - } + Button("Recontruire les poules") { + _save(rebuildEverything: false) } - + Button("Tout refaire", role: .destructive) { _save(rebuildEverything: true) } - }, message: { ForEach(Array(requirements)) { requirement in Text(requirement.rebuildingRequirementMessage) @@ -226,7 +245,22 @@ struct TableStructureView: View { .navigationTitle("Structure") .navigationBarTitleDisplayMode(.inline) } + + private func _saveWithoutRebuild() { + tournament.teamCount = teamCount + tournament.groupStageCount = groupStageCount + tournament.teamsPerGroupStage = teamsPerGroupStage + tournament.qualifiedPerGroupStage = qualifiedPerGroupStage + tournament.groupStageAdditionalQualified = groupStageAdditionalQualified + do { + try dataStore.tournaments.addOrUpdate(instance: tournament) + } catch { + Logger.error(error) + } + dismiss() + } + private func _save(rebuildEverything: Bool = false) { _verifyValueIntegrity() diff --git a/PadelClub/Views/Tournament/Screen/TournamentRankView.swift b/PadelClub/Views/Tournament/Screen/TournamentRankView.swift index 70ed34e..4c36727 100644 --- a/PadelClub/Views/Tournament/Screen/TournamentRankView.swift +++ b/PadelClub/Views/Tournament/Screen/TournamentRankView.swift @@ -13,6 +13,7 @@ struct TournamentRankView: View { @EnvironmentObject var dataStore: DataStore @State private var rankings: [Int: [TeamRegistration]] = [:] + @State private var calculating = false var body: some View { List { @@ -144,18 +145,58 @@ struct TournamentRankView: View { } } } + .overlay(content: { + if calculating { + ProgressView() + } + }) .onAppear { - let finalRanks = tournament.finalRanking() - finalRanks.keys.sorted().forEach { rank in - if let rankedTeamIds = finalRanks[rank] { - rankings[rank] = rankedTeamIds.compactMap { Store.main.findById($0) } - } + calculating = true + Task { + await calculateRankings() + calculating = false } } .navigationTitle("Classement") .navigationBarTitleDisplayMode(.inline) .toolbarBackground(.visible, for: .navigationBar) + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + if let url = tournament.shareURL(.rankings) { + actionForURL(url) + } + } + } + } + + func calculateRankings() async { + let finalRanks = await tournament.finalRanking() + finalRanks.keys.sorted().forEach { rank in + if let rankedTeamIds = finalRanks[rank] { + rankings[rank] = rankedTeamIds.compactMap { Store.main.findById($0) } + } + } + } + + @ViewBuilder + func actionForURL(_ url: URL, removeSource: Bool = false) -> some View { + Menu { + Button { + UIApplication.shared.open(url) + } label: { + Label("Voir", systemImage: "safari") + } + + ShareLink(item: url) { + Label("Partager le lien", systemImage: "link") + } + } label: { + Image(systemName: "square.and.arrow.up") + } + .frame(maxWidth: .infinity) + .buttonStyle(.borderless) } + private func _save() { do { diff --git a/PadelClub/Views/Tournament/TournamentBuildView.swift b/PadelClub/Views/Tournament/TournamentBuildView.swift index 77ad3d7..976c655 100644 --- a/PadelClub/Views/Tournament/TournamentBuildView.swift +++ b/PadelClub/Views/Tournament/TournamentBuildView.swift @@ -18,85 +18,38 @@ struct TournamentBuildView: View { @ViewBuilder var body: some View { let state = tournament.state() - - if tournament.hasEnded() { - Section { + + Section { + if tournament.hasEnded() { NavigationLink(value: Screen.rankings) { Text("Classement final des équipes") } } - } - - Section { - if tournament.groupStageCount > 0 { - NavigationLink(value: Screen.groupStage) { - LabeledContent { - if let groupStageStatus { - Text(groupStageStatus).lineLimit(1) - .multilineTextAlignment(.trailing) - } else { - ProgressView() - } - } label: { - Text("Poules") - if tournament.shouldVerifyGroupStage { - Text("Vérifier les poules").foregroundStyle(.logoRed) - } - } - } - .task { - groupStageStatus = await tournament.groupStageStatus() - } - } - - if tournament.rounds().isEmpty == false { - NavigationLink(value: Screen.round) { - LabeledContent { - if let bracketStatus { - Text(bracketStatus).lineLimit(1) - .multilineTextAlignment(.trailing) - } else { - ProgressView() - } - } label: { - Text("Tableau") - if tournament.shouldVerifyBracket { - Text("Vérifier la tableau").foregroundStyle(.logoRed) - } - } - } - .task { - bracketStatus = await tournament.bracketStatus() - } - } - } - - Section { + if state == .running || state == .finished { + TournamentInscriptionView(tournament: tournament) TournamentBroadcastRowView(tournament: tournament) } - if state == .running || state == .finished { - NavigationLink(value: Screen.cashier) { - let tournamentStatus = cashierStatus - LabeledContent { - if let tournamentStatus { - Text(tournamentStatus.completion) - } else { - ProgressView() - } - } label: { - Text("Encaissement") - if let tournamentStatus { - Text(tournamentStatus.label).lineLimit(1) - } else { - Text(" ") - } + NavigationLink(value: Screen.cashier) { + let tournamentStatus = cashierStatus + LabeledContent { + if let tournamentStatus { + Text(tournamentStatus.completion) + } else { + ProgressView() + } + } label: { + Text("Encaissement") + if let tournamentStatus { + Text(tournamentStatus.label).lineLimit(1) + } else { + Text(" ") } } - .task { - cashierStatus = await tournament.cashierStatus() - } + } + .task { + cashierStatus = await tournament.cashierStatus() } if state != .finished { @@ -142,11 +95,50 @@ struct TournamentBuildView: View { callStatus = await tournament.callStatus() } } + } + + Section { + if tournament.groupStageCount > 0 { + NavigationLink(value: Screen.groupStage) { + LabeledContent { + if let groupStageStatus { + Text(groupStageStatus).lineLimit(1) + .multilineTextAlignment(.trailing) + } else { + ProgressView() + } + } label: { + Text("Poules") + if tournament.shouldVerifyGroupStage { + Text("Vérifier les poules").foregroundStyle(.logoRed) + } + } + } + .task { + groupStageStatus = await tournament.groupStageStatus() + } + } - if state == .running || state == .finished { - TournamentInscriptionView(tournament: tournament) + if tournament.rounds().isEmpty == false { + NavigationLink(value: Screen.round) { + LabeledContent { + if let bracketStatus { + Text(bracketStatus).lineLimit(1) + .multilineTextAlignment(.trailing) + } else { + ProgressView() + } + } label: { + Text("Tableau") + if tournament.shouldVerifyBracket { + Text("Vérifier la tableau").foregroundStyle(.logoRed) + } + } + } + .task { + bracketStatus = await tournament.bracketStatus() + } } - } } } diff --git a/PadelClub/Views/Tournament/TournamentView.swift b/PadelClub/Views/Tournament/TournamentView.swift index 297cd7b..a104c3a 100644 --- a/PadelClub/Views/Tournament/TournamentView.swift +++ b/PadelClub/Views/Tournament/TournamentView.swift @@ -67,8 +67,8 @@ struct TournamentView: View { TournamentInitView(tournament: tournament) TournamentBuildView(tournament: tournament) case .running: - TournamentRunningView(tournament: tournament) TournamentBuildView(tournament: tournament) + TournamentRunningView(tournament: tournament) case .finished: TournamentBuildView(tournament: tournament) TournamentRunningView(tournament: tournament)