in progress loser bracket

multistore
Razmig Sarkissian 2 years ago
parent 29cc0df4a2
commit 82384e3049
  1. 26
      PadelClub/Data/Match.swift
  2. 40
      PadelClub/Data/Round.swift
  3. 1
      PadelClub/Data/TeamRegistration.swift
  4. 4
      PadelClub/Data/Tournament.swift
  5. 1
      PadelClub/Views/Match/MatchSetupView.swift
  6. 7
      PadelClub/Views/Round/LoserRoundsView.swift
  7. 92
      PadelClub/Views/Round/RoundSettingsView.swift
  8. 2
      PadelClub/Views/Round/RoundView.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
}
}

@ -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)

@ -63,6 +63,7 @@ class TeamRegistration: ModelObject, Storable {
teamPosition = upperBranch ?? (isUpper ? 1 : 0)
}
match.previousMatch(teamPosition)?.disableMatch()
match._toggleLoserMatchDisableState(false)
bracketPosition = matchIndex * 2 + teamPosition
}

@ -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()
}

@ -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")

@ -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))

@ -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..<matchCount).map { //0 is final match
return Match(round: round.id, index: $0 + matchStartIndex, matchFormat: round.matchFormat)
}
try? dataStore.rounds.addOrUpdate(instance: round)
try? dataStore.matches.addOrUpdate(contentOfs: matches)
round.buildLoserBracket()
}
}
if let availableSeedGroup = tournament.availableSeedGroup() {
Section {
@ -108,6 +65,55 @@ struct RoundSettingsView: View {
Text("Placement des têtes de série")
}
}
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 })
try? dataStore.teamRegistrations.addOrUpdate(contentOfs: tournament.unsortedTeams())
tournament.allRounds().forEach({ round in
round.enableRound()
})
}
}
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..<matchCount).map { //0 is final match
return Match(round: round.id, index: $0 + matchStartIndex, matchFormat: round.matchFormat)
}
try? dataStore.rounds.addOrUpdate(instance: round)
try? dataStore.matches.addOrUpdate(contentOfs: matches)
round.buildLoserBracket()
}
}
}
}
}

@ -13,7 +13,7 @@ struct RoundView: View {
var body: some View {
List {
let loserRounds = round.loserRounds()
if loserRounds.isEmpty == false, let first = loserRounds.first {
if loserRounds.isEmpty == false, let first = loserRounds.first(where: { $0.isDisabled() == false }) {
Section {
NavigationLink {
LoserRoundsView(upperBracketRound: round)

Loading…
Cancel
Save