diff --git a/PadelClub/Data/GroupStage.swift b/PadelClub/Data/GroupStage.swift index 8f81297..4f07484 100644 --- a/PadelClub/Data/GroupStage.swift +++ b/PadelClub/Data/GroupStage.swift @@ -115,17 +115,24 @@ final class GroupStage: ModelObject, Storable { return match } - func buildMatches() { - _removeMatches() - - var matches = [Match]() + func buildMatches(keepExistingMatches: Bool = false) { var teamScores = [TeamScore]() + var matches = [Match]() - for i in 0..<_numberOfMatchesToBuild() { - let newMatch = self._createMatch(index: i) -// let newMatch = Match(groupStage: self.id, index: i, matchFormat: self.matchFormat, name: localizedMatchUpLabel(for: i)) - teamScores.append(contentsOf: newMatch.createTeamScores()) - matches.append(newMatch) + if keepExistingMatches == false { + _removeMatches() + + for i in 0..<_numberOfMatchesToBuild() { + let newMatch = self._createMatch(index: i) + // let newMatch = Match(groupStage: self.id, index: i, matchFormat: self.matchFormat, name: localizedMatchUpLabel(for: i)) + teamScores.append(contentsOf: newMatch.createTeamScores()) + matches.append(newMatch) + } + } else { + for match in _matches() { + match.resetTeamScores(outsideOf: []) + teamScores.append(contentsOf: match.createTeamScores()) + } } do { diff --git a/PadelClub/Data/Match.swift b/PadelClub/Data/Match.swift index 95e08fb..7c4eb85 100644 --- a/PadelClub/Data/Match.swift +++ b/PadelClub/Data/Match.swift @@ -63,6 +63,20 @@ final class Match: ModelObject, Storable, Equatable { // self.order = order } + func setMatchName(_ serverName: String?) { + self.name = serverName + } + + func isFromLastRound() -> Bool { + guard let roundObject, roundObject.parent == nil else { return false } + guard let currentTournament = currentTournament() else { return false } + if currentTournament.rounds().count - 1 == roundObject.index { + return true + } else { + return false + } + } + var tournamentStore: TournamentStore { if let store = self.store as? TournamentStore { return store @@ -380,16 +394,17 @@ defer { func _toggleMatchDisableState(_ state: Bool, forward: Bool = false, single: Bool = false) { //if disabled == state { return } + let currentState = disabled disabled = state - if disabled { + if disabled != currentState { do { try self.tournamentStore.teamScores.delete(contentOfs: teamScores) } catch { Logger.error(error) } } - if state == true { + if state == true, state != currentState { let teams = teams() for team in teams { if isSeededBy(team: team) { @@ -403,6 +418,8 @@ defer { } } //byeState = false + roundObject?._cachedSeedInterval = nil + name = nil do { try self.tournamentStore.matches.addOrUpdate(instance: self) } catch { diff --git a/PadelClub/Data/Round.swift b/PadelClub/Data/Round.swift index d7cf727..0604917 100644 --- a/PadelClub/Data/Round.swift +++ b/PadelClub/Data/Round.swift @@ -24,7 +24,8 @@ final class Round: ModelObject, Storable { var startDate: Date? var groupStageLoserBracket: Bool = false var loserBracketMode: LoserBracketMode = .automatic - + var _cachedSeedInterval: SeedInterval? + internal init(tournament: String, index: Int, parent: String? = nil, matchFormat: MatchFormat? = nil, startDate: Date? = nil, groupStageLoserBracket: Bool = false, loserBracketMode: LoserBracketMode = .automatic) { self.tournament = tournament self.index = index @@ -451,6 +452,8 @@ defer { func correspondingLoserRoundTitle(_ displayStyle: DisplayStyle = .wide) -> String { + if let _cachedSeedInterval { return _cachedSeedInterval.localizedLabel(displayStyle) } + #if _DEBUG_TIME //DEBUGING TIME let start = Date() defer { @@ -469,8 +472,16 @@ defer { // && $0.bracketPosition != nil // && ($0.bracketPosition! / 2) < initialMatchIndexFromRoundIndex // }) + + var seedsCount = seedsAfterThisRound.count + if seedsAfterThisRound.isEmpty { + let nextRoundsDisableMatches = nextRoundsDisableMatches() + seedsCount = disabledMatches().count - nextRoundsDisableMatches + } let playedMatches = playedMatches() - let seedInterval = SeedInterval(first: playedMatches.count + seedsAfterThisRound.count + 1, last: playedMatches.count * 2 + seedsAfterThisRound.count) + let seedInterval = SeedInterval(first: playedMatches.count + seedsCount + 1, last: playedMatches.count * 2 + seedsCount) + + _cachedSeedInterval = seedInterval return seedInterval.localizedLabel(displayStyle) } @@ -492,6 +503,8 @@ defer { } func seedInterval(initialMode: Bool = false) -> SeedInterval? { + if initialMode == false, let _cachedSeedInterval { return _cachedSeedInterval } + #if _DEBUG_TIME //DEBUGING TIME let start = Date() defer { @@ -515,11 +528,17 @@ defer { && ($0.bracketPosition! / 2) < initialMatchIndexFromRoundIndex } - let playedMatches = playedMatches().count - let minimumMatches = playedMatches * 2 + var seedsCount = seedsAfterThisRound.count + if seedsAfterThisRound.isEmpty { + let nextRoundsDisableMatches = nextRoundsDisableMatches() + seedsCount = disabledMatches().count - nextRoundsDisableMatches + } + + let playedMatches = playedMatches() //print("playedMatches \(playedMatches)", initialMode, parent, parentRound?.roundTitle(), seedsAfterThisRound.count) - let seedInterval = SeedInterval(first: playedMatches + seedsAfterThisRound.count + 1, last: minimumMatches + seedsAfterThisRound.count) + let seedInterval = SeedInterval(first: playedMatches.count + seedsCount + 1, last: playedMatches.count * 2 + seedsCount) //print(seedInterval.localizedLabel()) + _cachedSeedInterval = seedInterval return seedInterval } @@ -659,6 +678,14 @@ defer { guard let parent = parent else { return nil } return self.tournamentStore.rounds.findById(parent) } + + func nextRoundsDisableMatches() -> Int { + if parent == nil, index > 0 { + return tournamentObject()?.rounds().suffix(index).flatMap { $0.disabledMatches() }.count ?? 0 + } else { + return 0 + } + } func updateMatchFormat(_ updatedMatchFormat: MatchFormat, checkIfPossible: Bool, andLoserBracket: Bool) { if updatedMatchFormat.weight < self.matchFormat.weight { diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index 8b78f8a..285a7b9 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -1112,9 +1112,10 @@ defer { return callDateIssue.count + duplicates.count + problematicPlayers.count + inadequatePlayers.count + playersWithoutValidLicense.count + playersMissing.count + waitingListInBracket.count + waitingListInGroupStage.count + ageInadequatePlayers.count + homonyms.count } - func isStartDateIsDifferentThanCallDate(_ team: TeamRegistration) -> Bool { + func isStartDateIsDifferentThanCallDate(_ team: TeamRegistration, expectedSummonDate: Date? = nil) -> Bool { guard let summonDate = team.callDate else { return true } - guard let expectedSummonDate = team.expectedSummonDate() else { return true } + let expectedSummonDate : Date? = team.expectedSummonDate() ?? expectedSummonDate + guard let expectedSummonDate else { return true } return Calendar.current.compare(summonDate, to: expectedSummonDate, toGranularity: .minute) != ComparisonResult.orderedSame } @@ -1609,7 +1610,9 @@ defer { func callStatus() async -> TournamentStatus { let selectedSortedTeams = selectedSortedTeams() let called = selectedSortedTeams.filter { isStartDateIsDifferentThanCallDate($0) == false } - let label = "\(called.count.formatted()) / \(selectedSortedTeams.count.formatted()) convoquées au bon horaire" + let justCalled = selectedSortedTeams.filter { $0.called() } + + let label = "\(justCalled.count.formatted()) / \(selectedSortedTeams.count.formatted()) (\(called.count.formatted()) au bon horaire)" let completion = (Double(called.count) / Double(selectedSortedTeams.count)) let completionLabel = completion.isNaN ? "" : completion.formatted(.percent.precision(.fractionLength(0))) return TournamentStatus(label: label, completion: completionLabel) @@ -1852,7 +1855,7 @@ defer { } } - func refreshGroupStages() { + func refreshGroupStages(keepExistingMatches: Bool = false) { unsortedTeams().forEach { team in team.groupStage = nil team.groupStagePosition = nil @@ -1861,16 +1864,16 @@ defer { if groupStageCount > 0 { switch groupStageOrderingMode { case .random: - setGroupStage(randomize: true) + setGroupStage(randomize: true, keepExistingMatches: keepExistingMatches) case .snake: - setGroupStage(randomize: false) + setGroupStage(randomize: false, keepExistingMatches: keepExistingMatches) case .swiss: - setGroupStage(randomize: true) + setGroupStage(randomize: true, keepExistingMatches: keepExistingMatches) } } } - func setGroupStage(randomize: Bool) { + func setGroupStage(randomize: Bool, keepExistingMatches: Bool = false) { let groupStages = groupStages() let numberOfBracketsAsInt = groupStages.count // let teamsPerBracket = teamsPerBracket @@ -1879,7 +1882,7 @@ defer { buildGroupStages() } else { setGroupStageTeams(randomize: randomize) - groupStages.forEach { $0.buildMatches() } + groupStages.forEach { $0.buildMatches(keepExistingMatches: keepExistingMatches) } } } @@ -2195,7 +2198,7 @@ defer { groupStages().chunked(into: 2).forEach { gss in let placeCount = i * 2 + 1 let match = Match(round: groupStageLoserBracket.id, index: placeCount, matchFormat: groupStageLoserBracket.matchFormat) - match.name = "\(placeCount)\(placeCount.ordinalFormattedSuffix(feminine: true)) place" + match.setMatchName("\(placeCount)\(placeCount.ordinalFormattedSuffix(feminine: true)) place") do { try tournamentStore.matches.addOrUpdate(instance: match) } catch { diff --git a/PadelClub/Utils/ContactManager.swift b/PadelClub/Utils/ContactManager.swift index 5c9d793..8c620a7 100644 --- a/PadelClub/Utils/ContactManager.swift +++ b/PadelClub/Utils/ContactManager.swift @@ -117,8 +117,16 @@ Il est conseillé de vous présenter 10 minutes avant de jouer.\n\nMerci de me c (DataStore.shared.user.summonsDisplayEntryFee) ? tournament?.entryFeeMessage : nil } + var linkMessage: String? { + if let tournament, tournament.isPrivate == false, let shareLink = tournament.shareURL(.matches)?.absoluteString { + return "Vous pourrez suivre tous les résultats de ce tournoi sur le site :\n\n".appending(shareLink) + } else { + return nil + } + } + var computedMessage: String { - [entryFeeMessage, message].compacted().map { $0.trimmedMultiline }.joined(separator: "\n\n") + [entryFeeMessage, message, linkMessage].compacted().map { $0.trimmedMultiline }.joined(separator: "\n\n") } let intro = reSummon ? "Suite à des forfaits, vous êtes finalement" : "Vous êtes" diff --git a/PadelClub/Views/Calling/BracketCallingView.swift b/PadelClub/Views/Calling/BracketCallingView.swift index bede32f..0ba3512 100644 --- a/PadelClub/Views/Calling/BracketCallingView.swift +++ b/PadelClub/Views/Calling/BracketCallingView.swift @@ -86,19 +86,21 @@ struct BracketCallingView: View { } label: { Text("Têtes de série") } + } footer: { + Text("Permet de convoquer par tour du tableau sans avoir tirer au sort les tétes de série. Vous pourrez ensuite confirmer leur horaire plus précis si le tour se joue sur plusieurs rotations. Les équipes ne peuvent pas être considéré comme convoqué au bon horaire en dehors de cet écran tant qu'elles n'ont pas été placé dans le tableau.") } ForEach(filteredRounds()) { round in let seeds = seeds(forRoundIndex: round.index) let startDate = round.startDate ?? round.playedMatches().first?.startDate - let callSeeds = seeds.filter({ $0.callDate == startDate }) + let callSeeds = seeds.filter({ tournament.isStartDateIsDifferentThanCallDate($0, expectedSummonDate: startDate) == false }) if seeds.isEmpty == false { Section { NavigationLink { _roundView(round: round, seeds: seeds) .environment(tournament) } label: { - CallView.CallStatusView(count: callSeeds.count, total: seeds.count, startDate: startDate) + CallView.CallStatusView(count: callSeeds.count, total: seeds.count, startDate: startDate, title: "convoquées") } } header: { Text(round.roundTitle()) @@ -111,7 +113,7 @@ struct BracketCallingView: View { } } .headerProminence(.increased) - .navigationTitle("Prévision") + .navigationTitle("Pré-convocation") } @ViewBuilder @@ -120,12 +122,38 @@ struct BracketCallingView: View { NavigationLink("Équipes non contactées") { TeamsCallingView(teams: seeds.filter({ $0.callDate == nil })) } + + let startDate = round.startDate ?? round.playedMatches().first?.startDate + let badCalled = seeds.filter({ tournament.isStartDateIsDifferentThanCallDate($0, expectedSummonDate: startDate) }) + + if badCalled.isEmpty == false { + Section { + ForEach(badCalled) { team in + CallView.TeamView(team: team) + } + } header: { + HStack { + Text("Mauvais horaire") + Spacer() + Text(badCalled.count.formatted() + " équipe\(badCalled.count.pluralSuffix)") + } + } footer: { + if let startDate { + CallView(teams: badCalled, callDate: startDate, matchFormat: round.matchFormat, roundLabel: round.roundTitle()) + } + } + } + Section { ForEach(seeds) { team in CallView.TeamView(team: team) } } header: { - Text(round.roundTitle()) + HStack { + Text(round.roundTitle()) + Spacer() + Text(seeds.count.formatted() + " équipe\(seeds.count.pluralSuffix)") + } } } .overlay { diff --git a/PadelClub/Views/Calling/CallMessageCustomizationView.swift b/PadelClub/Views/Calling/CallMessageCustomizationView.swift index 569f420..0ed9a54 100644 --- a/PadelClub/Views/Calling/CallMessageCustomizationView.swift +++ b/PadelClub/Views/Calling/CallMessageCustomizationView.swift @@ -43,7 +43,15 @@ struct CallMessageCustomizationView: View { } var computedMessage: String { - [entryFeeMessage, customCallMessageBody].compacted().map { $0.trimmedMultiline }.joined(separator: "\n") + var linkMessage: String? { + if tournament.isPrivate == false, let shareLink = tournament.shareURL(.matches)?.absoluteString { + return "Vous pourrez suivre tous les résultats de ce tournoi sur le site :\n\n".appending(shareLink) + } else { + return nil + } + } + + return [entryFeeMessage, customCallMessageBody, linkMessage].compacted().map { $0.trimmedMultiline }.joined(separator: "\n") } var finalMessage: String? { @@ -259,7 +267,7 @@ struct CallMessageCustomizationView: View { } }.italic().foregroundStyle(.gray) } header: { - Text("Rendu généré automatiquement") + Text("Exemple généré automatiquement") } } diff --git a/PadelClub/Views/Calling/CallView.swift b/PadelClub/Views/Calling/CallView.swift index 58f953c..0367f2e 100644 --- a/PadelClub/Views/Calling/CallView.swift +++ b/PadelClub/Views/Calling/CallView.swift @@ -14,6 +14,7 @@ struct CallView: View { let count: Int let total: Int let startDate: Date? + var title: String = "convoquées au bon horaire" var body: some View { VStack(spacing: 0) { @@ -32,7 +33,7 @@ struct CallView: View { Text(startDate.formatted(.dateTime.weekday().day(.twoDigits).month().year())) } Spacer() - Text("convoquées au bon horaire") + Text(title) } .font(.caption) .foregroundColor(.secondary) diff --git a/PadelClub/Views/Calling/TeamsCallingView.swift b/PadelClub/Views/Calling/TeamsCallingView.swift index 832daae..9b7b06a 100644 --- a/PadelClub/Views/Calling/TeamsCallingView.swift +++ b/PadelClub/Views/Calling/TeamsCallingView.swift @@ -16,6 +16,13 @@ struct TeamsCallingView: View { List { PlayersWithoutContactView(players: teams.flatMap({ $0.unsortedPlayers() }).sorted(by: \.computedRank)) + let called = teams.filter { tournament.isStartDateIsDifferentThanCallDate($0) == false } + let justCalled = teams.filter { $0.called() } + + let label = "\(justCalled.count.formatted()) / \(teams.count.formatted()) convoquées (dont \(called.count.formatted()) au bon horaire)" + + Text(label) + Section { ForEach(teams) { team in Menu { @@ -34,6 +41,11 @@ struct TeamsCallingView: View { .buttonStyle(.plain) .listRowView(isActive: team.confirmed(), color: .green, hideColorVariation: true) } + } footer: { + HStack { + Text("Vous pouvez indiquer si une équipe vous a confirmé sa convocation en appuyant sur ") + Image(systemName: "ellipsis.circle").font(.footnote) + } } } .headerProminence(.increased) diff --git a/PadelClub/Views/GroupStage/GroupStagesSettingsView.swift b/PadelClub/Views/GroupStage/GroupStagesSettingsView.swift index ab40d64..8f31945 100644 --- a/PadelClub/Views/GroupStage/GroupStagesSettingsView.swift +++ b/PadelClub/Views/GroupStage/GroupStagesSettingsView.swift @@ -248,7 +248,7 @@ struct GroupStagesSettingsView: View { func menuGenerateGroupStage(_ mode: GroupStageOrderingMode) -> some View { RowButtonView("Poule \(mode.localizedLabel().lowercased())", role: .destructive, systemImage: mode.systemImage) { tournament.groupStageOrderingMode = mode - tournament.refreshGroupStages() + tournament.refreshGroupStages(keepExistingMatches: true) generationDone = true tournament.shouldVerifyGroupStage = false _save() diff --git a/PadelClub/Views/GroupStage/LoserBracketFromGroupStageView.swift b/PadelClub/Views/GroupStage/LoserBracketFromGroupStageView.swift index 15f41b1..aeb532a 100644 --- a/PadelClub/Views/GroupStage/LoserBracketFromGroupStageView.swift +++ b/PadelClub/Views/GroupStage/LoserBracketFromGroupStageView.swift @@ -107,7 +107,7 @@ struct LoserBracketFromGroupStageView: View { let currentGroupStageLoserBracketsInitialPlace = tournament.groupStageLoserBracketsInitialPlace() let placeCount = displayableMatches.isEmpty ? currentGroupStageLoserBracketsInitialPlace : max(currentGroupStageLoserBracketsInitialPlace, displayableMatches.map({ $0.index }).max()! + 2) let match = Match(round: loserBracket.id, index: placeCount, matchFormat: loserBracket.matchFormat) - match.name = "\(placeCount)\(placeCount.ordinalFormattedSuffix()) place" + match.setMatchName("\(placeCount)\(placeCount.ordinalFormattedSuffix()) place") do { try tournamentStore.matches.addOrUpdate(instance: match) } catch { @@ -202,7 +202,7 @@ struct GroupStageLoserBracketMatchFooterView: View { match.index = newIndexValidated - match.name = "\(newIndexValidated)\(newIndexValidated.ordinalFormattedSuffix()) place" + match.setMatchName("\(newIndexValidated)\(newIndexValidated.ordinalFormattedSuffix()) place") do { diff --git a/PadelClub/Views/Match/MatchSetupView.swift b/PadelClub/Views/Match/MatchSetupView.swift index ac777a6..b804de0 100644 --- a/PadelClub/Views/Match/MatchSetupView.swift +++ b/PadelClub/Views/Match/MatchSetupView.swift @@ -166,7 +166,7 @@ struct MatchSetupView: View { Text("Libérer") .underline() } - } else { + } else if match.isFromLastRound() == false { ConfirmButtonView(shouldConfirm: shouldConfirm, message: MatchSetupView.confirmationMessage) { _ = match.lockAndGetSeedPosition(atTeamPosition: teamPosition) do { diff --git a/PadelClub/Views/Planning/PlanningView.swift b/PadelClub/Views/Planning/PlanningView.swift index f677510..03ae980 100644 --- a/PadelClub/Views/Planning/PlanningView.swift +++ b/PadelClub/Views/Planning/PlanningView.swift @@ -210,7 +210,7 @@ struct PlanningView: View { uniqueNames.append(name) } } - Text(names.joined(separator: ", ")) + Text(names.joined(separator: ", ")).lineLimit(1).truncationMode(.tail) } else { Text(matches.count.formatted().appending(" matchs")) } diff --git a/PadelClub/Views/Round/LoserRoundSettingsView.swift b/PadelClub/Views/Round/LoserRoundSettingsView.swift index 3b4706a..eb0c827 100644 --- a/PadelClub/Views/Round/LoserRoundSettingsView.swift +++ b/PadelClub/Views/Round/LoserRoundSettingsView.swift @@ -62,7 +62,7 @@ struct LoserRoundSettingsView: View { RowButtonView("Synchroniser les noms des matchs") { let allRoundMatches = upperBracketRound.loserRounds.flatMap({ $0.allMatches }) - allRoundMatches.forEach({ $0.name = $0.roundTitle() }) + allRoundMatches.forEach({ $0.setMatchName($0.roundTitle()) }) do { try self.tournament.tournamentStore.matches.addOrUpdate(contentOfs: allRoundMatches) } catch { @@ -82,7 +82,7 @@ struct LoserRoundSettingsView: View { RowButtonView("Créer les matchs de classements", role: .destructive) { upperBracketRound.round.buildLoserBracket() upperBracketRound.round.disabledMatches().forEach { match in - match.disableMatch() + match._toggleLoserMatchDisableState(true) } do { try self.tournament.tournamentStore.matches.addOrUpdate(contentOfs: upperBracketRound.round.allLoserRoundMatches()) diff --git a/PadelClub/Views/Round/LoserRoundView.swift b/PadelClub/Views/Round/LoserRoundView.swift index 1707e75..843765d 100644 --- a/PadelClub/Views/Round/LoserRoundView.swift +++ b/PadelClub/Views/Round/LoserRoundView.swift @@ -129,8 +129,8 @@ struct LoserRoundView: View { private func _refreshNames() { DispatchQueue.global(qos: .background).async { - let allRoundMatches = loserBracket.allMatches - allRoundMatches.forEach({ $0.name = $0.roundTitle() }) + let allRoundMatches = loserBracket.allMatches.filter({ $0.name == nil }) + allRoundMatches.forEach({ $0.setMatchName($0.roundTitle()) }) do { try self.tournament.tournamentStore.matches.addOrUpdate(contentOfs: allRoundMatches) } catch { diff --git a/PadelClub/Views/Round/RoundSettingsView.swift b/PadelClub/Views/Round/RoundSettingsView.swift index 6efa24b..53a16ab 100644 --- a/PadelClub/Views/Round/RoundSettingsView.swift +++ b/PadelClub/Views/Round/RoundSettingsView.swift @@ -111,11 +111,11 @@ struct RoundSettingsView: View { //index du match courant pair = position basse du prochain match match.disabled = true } else { - match.name = Match.setServerTitle(upperRound: round, matchIndex: currentIndex) + match.setMatchName(Match.setServerTitle(upperRound: round, matchIndex: currentIndex)) currentIndex += 1 } } else { - match.name = Match.setServerTitle(upperRound: round, matchIndex: currentIndex) + match.setMatchName(Match.setServerTitle(upperRound: round, matchIndex: currentIndex)) currentIndex += 1 } @@ -157,14 +157,16 @@ struct RoundSettingsView: View { Section { RowButtonView("Synchroniser les noms des matchs") { - let allRoundMatches = tournament.allRoundMatches() - allRoundMatches.forEach({ $0.name = $0.roundTitle() }) + let allRoundMatches = tournament.allLoserRoundMatches() + allRoundMatches.forEach({ $0.setMatchName($0.roundTitle()) }) do { try self.tournament.tournamentStore.matches.addOrUpdate(contentOfs: allRoundMatches) } catch { Logger.error(error) } } + } header: { + Text("Matchs de classement") } } .toolbar { diff --git a/PadelClub/Views/Round/RoundView.swift b/PadelClub/Views/Round/RoundView.swift index 3b31959..5ed57c3 100644 --- a/PadelClub/Views/Round/RoundView.swift +++ b/PadelClub/Views/Round/RoundView.swift @@ -80,7 +80,7 @@ struct RoundView: View { LabeledContent { Text(leftToPlay.formatted()) } label: { - Text("Match\(leftToPlay.pluralSuffix) à jouer \(upperRound.title)") + Text("Match\(leftToPlay.pluralSuffix) à jouer en \(upperRound.title)") } } footer: { Text("\(disabledMatchesCount) match\(disabledMatchesCount.pluralSuffix) désactivé\(disabledMatchesCount.pluralSuffix) automatiquement") @@ -332,12 +332,12 @@ struct RoundView: View { } private func _save() { - do { - try self.tournamentStore.teamRegistrations.addOrUpdate(contentOfs: tournament.unsortedTeams()) - } catch { - Logger.error(error) - } - +// do { +// try self.tournamentStore.teamRegistrations.addOrUpdate(contentOfs: tournament.unsortedTeams()) +// } catch { +// Logger.error(error) +// } +// if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty { self.isEditingTournamentSeed.wrappedValue = false } @@ -349,22 +349,22 @@ struct RoundView: View { DispatchQueue.global(qos: .background).async { //todo should be done server side let rounds = tournament.rounds() + var matchesToUpdate: [Match] = [Match]() rounds.forEach { round in - let matches = round.playedMatches() + let matches = round.playedMatches().filter({ $0.name == nil }) matches.forEach { match in - match.name = Match.setServerTitle(upperRound: round, matchIndex: match.indexInRound(in: matches)) + match.setMatchName(Match.setServerTitle(upperRound: round, matchIndex: match.indexInRound(in: matches))) } + matchesToUpdate.append(contentsOf: matches) } - let loserMatches = self.upperRound.loserMatches() + let loserMatches = self.upperRound.loserMatches().filter({ $0.name == nil }) loserMatches.forEach { match in - match.name = match.roundTitle() + match.setMatchName(match.roundTitle()) } - let allRoundMatches = tournament.allRoundMatches() - do { - try tournament.tournamentStore.matches.addOrUpdate(contentOfs: allRoundMatches) + try tournament.tournamentStore.matches.addOrUpdate(contentOfs: matchesToUpdate + loserMatches) } catch { Logger.error(error) } diff --git a/PadelClub/Views/Tournament/Screen/TableStructureView.swift b/PadelClub/Views/Tournament/Screen/TableStructureView.swift index ff126af..9571c44 100644 --- a/PadelClub/Views/Tournament/Screen/TableStructureView.swift +++ b/PadelClub/Views/Tournament/Screen/TableStructureView.swift @@ -369,6 +369,19 @@ struct TableStructureView: View { groupStage.updateGroupStageState() } } + + if groupStageCount == 0 { + let teams = tournament.unsortedTeams().filter({ $0.inGroupStage() }) + teams.forEach { team in + team.groupStagePosition = nil + team.groupStage = nil + } + do { + try tournament.tournamentStore.teamRegistrations.addOrUpdate(contentOfs: teams) + } catch { + Logger.error(error) + } + } do { try dataStore.tournaments.addOrUpdate(instance: tournament) } catch { diff --git a/PadelClub/Views/Tournament/Screen/TournamentCallView.swift b/PadelClub/Views/Tournament/Screen/TournamentCallView.swift index 57785fe..fd0db9d 100644 --- a/PadelClub/Views/Tournament/Screen/TournamentCallView.swift +++ b/PadelClub/Views/Tournament/Screen/TournamentCallView.swift @@ -53,8 +53,7 @@ enum CallDestination: Identifiable, Selectable, Equatable { let allSeedCalled = tournament.seeds().filter({ tournament.isStartDateIsDifferentThanCallDate($0) || $0.callDate == nil }) return allSeedCalled.count case .brackets(let tournament): - let availableSeeds = tournament.availableSeeds().filter({ $0.callDate == nil }) - return availableSeeds.count + return nil case .groupStages(let tournament): let allSeedCalled = tournament.groupStageTeams().filter({ tournament.isStartDateIsDifferentThanCallDate($0) || $0.callDate == nil }) return allSeedCalled.count @@ -74,8 +73,7 @@ enum CallDestination: Identifiable, Selectable, Equatable { let allSeedCalled = tournament.seeds().allSatisfy({ tournament.isStartDateIsDifferentThanCallDate($0) == false }) return allSeedCalled ? .checkmark : nil case .brackets(let tournament): - let availableSeeds = tournament.availableSeeds().allSatisfy({ $0.called() }) - return availableSeeds ? .checkmark : nil + return nil case .groupStages(let tournament): let allSeedCalled = tournament.groupStageTeams().allSatisfy({ tournament.isStartDateIsDifferentThanCallDate($0) == false }) return allSeedCalled ? .checkmark : nil