From 82384e30495031e699f26a66f80b5184e7b700da Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Fri, 5 Apr 2024 22:13:09 +0200 Subject: [PATCH] in progress loser bracket --- PadelClub/Data/Match.swift | 26 +++++- PadelClub/Data/Round.swift | 40 +++++++- PadelClub/Data/TeamRegistration.swift | 1 + PadelClub/Data/Tournament.swift | 4 + PadelClub/Views/Match/MatchSetupView.swift | 1 + PadelClub/Views/Round/LoserRoundsView.swift | 7 +- PadelClub/Views/Round/RoundSettingsView.swift | 92 ++++++++++--------- PadelClub/Views/Round/RoundView.swift | 2 +- 8 files changed, 117 insertions(+), 56 deletions(-) diff --git a/PadelClub/Data/Match.swift b/PadelClub/Data/Match.swift index 79bdd00..f272626 100644 --- a/PadelClub/Data/Match.swift +++ b/PadelClub/Data/Match.swift @@ -26,7 +26,7 @@ class Match: ModelObject, Storable { var broadcasted: Bool var name: String? var order: Int - private(set) var disabled: Bool = false + var disabled: Bool = false internal init(round: String? = nil, groupStage: String? = nil, startDate: Date? = nil, endDate: Date? = nil, index: Int, matchFormat: MatchFormat? = nil, court: String? = nil, servingTeamId: String? = nil, winningTeamId: String? = nil, losingTeamId: String? = nil, broadcasted: Bool = false, name: String? = nil, order: Int = 0) { self.round = round @@ -74,8 +74,26 @@ class Match: ModelObject, Storable { _toggleMatchDisableState(false) } + func _toggleLoserMatchDisableState(_ state: Bool) { + if isLoserBracket == false { + let indexInRound = RoundRule.matchIndexWithinRound(fromMatchIndex: index) + if let loserMatch = roundObject?.loserRounds().first?.getMatch(atMatchIndexInRound: indexInRound / 2) { + print("disabling first loserround", state, loserMatch.matchTitle(.wide)) + loserMatch.disabled = state + try? DataStore.shared.matches.addOrUpdate(instance: loserMatch) + loserMatch._toggleLoserMatchDisableState(state) + } + } else { + roundObject?.loserRounds().forEach({ round in + print("disabling", state, round.roundTitle()) + round.disableLoserRound(state) + }) + } + } + fileprivate func _toggleMatchDisableState(_ state: Bool) { disabled = state + _toggleLoserMatchDisableState(state) topPreviousRoundMatch()?._toggleMatchDisableState(state) bottomPreviousRoundMatch()?._toggleMatchDisableState(state) try? DataStore.shared.matches.addOrUpdate(instance: self) @@ -319,7 +337,7 @@ class Match: ModelObject, Storable { func isBye() -> Bool { guard let roundObject else { return false } - return (roundObject.upperBracketMatches(ofMatch: self) + roundObject.previousRoundMatches(ofMatch: self)).anySatisfy({ $0.disabled }) + return topPreviousRoundMatch()?.disabled == true || bottomPreviousRoundMatch()?.disabled == true } func upperBracketTopMatch() -> Match? { @@ -355,7 +373,7 @@ class Match: ModelObject, Storable { } else if let match = topPreviousRoundMatch() { if let teamId = match.winningTeamId { return Store.main.findById(teamId) - } else if match.isBye() { + } else if match.disabled { return match.teams().first } } @@ -365,7 +383,7 @@ class Match: ModelObject, Storable { } else if let match = bottomPreviousRoundMatch() { if let teamId = match.winningTeamId { return Store.main.findById(teamId) - } else if match.isBye() { + } else if match.disabled { return match.teams().first } } diff --git a/PadelClub/Data/Round.swift b/PadelClub/Data/Round.swift index 0092d4f..b7d5f47 100644 --- a/PadelClub/Data/Round.swift +++ b/PadelClub/Data/Round.swift @@ -81,7 +81,7 @@ class Round: ModelObject, Storable { } else if let previousMatch = topPreviousRoundMatch(ofMatch: match) { if let teamId = previousMatch.winningTeamId { return Store.main.findById(teamId) - } else if previousMatch.isBye() { + } else if previousMatch.disabled { return previousMatch.teams().first } } @@ -91,7 +91,7 @@ class Round: ModelObject, Storable { } else if let previousMatch = bottomPreviousRoundMatch(ofMatch: match) { if let teamId = previousMatch.winningTeamId { return Store.main.findById(teamId) - } else if previousMatch.isBye() { + } else if previousMatch.disabled { return previousMatch.teams().first } } @@ -143,7 +143,11 @@ class Round: ModelObject, Storable { } func playedMatches() -> [Match] { - Store.main.filter { $0.round == self.id && $0.disabled == false } + if loser == nil { + Store.main.filter { $0.round == self.id && $0.disabled == false } + } else { + Store.main.filter { $0.round == self.id } + } } func previousRound() -> Round? { @@ -159,7 +163,7 @@ class Round: ModelObject, Storable { } func isDisabled() -> Bool { - playedMatches().allSatisfy({ $0.disabled || $0.isBye() }) + _matches().allSatisfy({ $0.disabled }) } func getActiveLoserRound() -> Round? { @@ -167,6 +171,32 @@ class Round: ModelObject, Storable { return rounds.filter({ $0.hasStarted() && $0.hasEnded() == false && $0.isDisabled() == false }).sorted(by: \.index).reversed().first ?? rounds.first(where: { $0.isDisabled() == false }) } + func enableRound() { + let _matches = _matches() + _matches.forEach { match in + match.disabled = false + match.losingTeamId = nil + match.winningTeamId = nil + match.endDate = nil + match.court = nil + match.servingTeamId = nil + try? DataStore.shared.teamScores.delete(contentOfs: match.teamScores) + } + try? DataStore.shared.matches.addOrUpdate(contentOfs: _matches) + } + + func disableLoserRound(_ disable: Bool) { + let _matches = _matches() + _matches.forEach { match in + match.disabled = match.topPreviousRoundMatch()?.disabled == disable || match.bottomPreviousRoundMatch()?.disabled == disable + } + + try? DataStore.shared.matches.addOrUpdate(contentOfs: _matches) + loserRounds().forEach { round in + round.disableLoserRound(disable) + } + } + var cumulativeMatchCount: Int { var totalMatches = playedMatches().count if let parent = parentRound { @@ -188,7 +218,7 @@ class Round: ModelObject, Storable { let parentMatchCount = parentRound.cumulativeMatchCount - initialRound.playedMatches().count print("initialRound", initialRound.roundTitle()) if let initialRoundNextRound = initialRound.nextRound()?.playedMatches() { - return SeedInterval(first: parentMatchCount + initialRoundNextRound.count * 2 + 1, last: parentMatchCount + initialRoundNextRound.count * 2 + playedMatches().count * 2).localizedLabel(displayStyle) + return SeedInterval(first: parentMatchCount + initialRoundNextRound.count * 2 + 1, last: parentMatchCount + initialRoundNextRound.count * 2 + (previousRound() ?? parentRound).playedMatches().count).localizedLabel(displayStyle) } } return RoundRule.roundName(fromRoundIndex: index) diff --git a/PadelClub/Data/TeamRegistration.swift b/PadelClub/Data/TeamRegistration.swift index 7bef636..37484e1 100644 --- a/PadelClub/Data/TeamRegistration.swift +++ b/PadelClub/Data/TeamRegistration.swift @@ -63,6 +63,7 @@ class TeamRegistration: ModelObject, Storable { teamPosition = upperBranch ?? (isUpper ? 1 : 0) } match.previousMatch(teamPosition)?.disableMatch() + match._toggleLoserMatchDisableState(false) bracketPosition = matchIndex * 2 + teamPosition } diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index 9211fdc..50200bd 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -253,6 +253,10 @@ class Tournament : ModelObject, Storable { return rounds.filter({ $0.hasStarted() && $0.hasEnded() == false }).sorted(by: \.index).reversed().first ?? rounds.first } + func allRounds() -> [Round] { + Store.main.filter { $0.tournament == self.id } + } + func rounds() -> [Round] { Store.main.filter { $0.tournament == self.id && $0.loser == nil }.sorted(by: \.index).reversed() } diff --git a/PadelClub/Views/Match/MatchSetupView.swift b/PadelClub/Views/Match/MatchSetupView.swift index 8309546..8e35ea3 100644 --- a/PadelClub/Views/Match/MatchSetupView.swift +++ b/PadelClub/Views/Match/MatchSetupView.swift @@ -25,6 +25,7 @@ struct MatchSetupView: View { .swipeActions(edge: .trailing, allowsFullSwipe: false) { Button(role: .cancel) { team.bracketPosition = nil + match._toggleLoserMatchDisableState(false) try? dataStore.teamRegistrations.addOrUpdate(instance: team) } label: { Label("retirer", systemImage: "xmark") diff --git a/PadelClub/Views/Round/LoserRoundsView.swift b/PadelClub/Views/Round/LoserRoundsView.swift index 0e9b0ca..60c647d 100644 --- a/PadelClub/Views/Round/LoserRoundsView.swift +++ b/PadelClub/Views/Round/LoserRoundsView.swift @@ -44,13 +44,14 @@ struct LoserRoundView: View { ForEach(loserRound.playedMatches()) { match in MatchRowView(match: match, matchViewStyle: .sectionedStandardStyle) .overlay { - if match.isBye() { - Image(systemName: "pencil.slash") + if match.disabled { + Image(systemName: "xmark") .resizable() .scaledToFit() - .opacity(0.3) + .opacity(0.8) } } + .disabled(match.disabled) } } header: { Text(loserRound.roundTitle(.wide)) diff --git a/PadelClub/Views/Round/RoundSettingsView.swift b/PadelClub/Views/Round/RoundSettingsView.swift index ed45818..8004418 100644 --- a/PadelClub/Views/Round/RoundSettingsView.swift +++ b/PadelClub/Views/Round/RoundSettingsView.swift @@ -21,50 +21,7 @@ struct RoundSettingsView: View { var body: some View { List { Toggle("Éditer les têtes de série", isOn: $isEditingTournamentSeed) - - Section { - RowButtonView("Effacer classement", role: .destructive) { - tournament.rounds().forEach { round in - try? dataStore.rounds.delete(contentOfs: round.loserRounds()) - } - } - } - Section { - RowButtonView("Match de classement") { - tournament.rounds().forEach { round in - round.buildLoserBracket() - } - } - } - Section { - RowButtonView("Retirer toutes les têtes de séries", role: .destructive) { - tournament.unsortedTeams().forEach({ $0.bracketPosition = nil }) - } - } - Section { - if let lastRound = tournament.rounds().first { // first is final, last round - RowButtonView("Supprimer " + lastRound.roundTitle(), role: .destructive) { - try? dataStore.rounds.delete(instance: lastRound) - } - } - } - - Section { - let roundIndex = tournament.rounds().count - RowButtonView("Ajouter " + RoundRule.roundName(fromRoundIndex: roundIndex)) { - let round = Round(tournament: tournament.id, index: roundIndex, matchFormat: tournament.matchFormat) - let matchCount = RoundRule.numberOfMatches(forRoundIndex: roundIndex) - let matchStartIndex = RoundRule.matchIndex(fromRoundIndex: roundIndex) - let matches = (0..