fix new feature loser bracket groupstages

xcode16
Raz 1 year ago
parent 9a2d293b41
commit 40fc73e6bf
  1. 7
      PadelClub/Data/Tournament.swift
  2. 4
      PadelClub/Utils/PadelRule.swift
  3. 8
      PadelClub/Views/GroupStage/GroupStagesView.swift
  4. 68
      PadelClub/Views/GroupStage/LoserBracketFromGroupStageView.swift
  5. 12
      PadelClub/Views/Match/EditSharingView.swift
  6. 3
      PadelClub/Views/Match/MatchRowView.swift
  7. 8
      PadelClub/Views/Match/MatchSetupView.swift
  8. 3
      PadelClub/Views/Match/MatchSummaryView.swift
  9. 25
      PadelClub/Views/Team/TeamPickerView.swift

@ -1258,12 +1258,15 @@ defer {
}
}
groupStageLoserBracket()?.playedMatches().forEach({ match in
if let groupStageLoserBracketPlayedMatches = groupStageLoserBracket()?.playedMatches() {
groupStageLoserBracketPlayedMatches.forEach({ match in
if match.hasEnded() {
let sameMatchIndexCount = groupStageLoserBracketPlayedMatches.filter({ $0.index == match.index }).count
teams.setOrAppend(match.winningTeamId, at: match.index)
teams.setOrAppend(match.losingTeamId, at: match.index + 1)
teams.setOrAppend(match.losingTeamId, at: match.index + sameMatchIndexCount)
}
})
}
let groupStages = groupStages()
let baseRank = teamCount - groupStageSpots() + qualifiedPerGroupStage * groupStageCount + groupStageAdditionalQualified

@ -293,8 +293,8 @@ enum TournamentLevel: Int, Hashable, Codable, CaseIterable, Identifiable {
func pointsRange(first: Int, last: Int, teamsCount: Int) -> String {
let range = [points(for: last - 1, count: teamsCount),
points(for: first - 1, count: teamsCount)]
let range = [points(for: first - 1, count: teamsCount),
points(for: last - 1, count: teamsCount)]
return range.map { $0.formatted(.number.sign(strategy: .always())) }.joined(separator: " / ") + " pts"
}

@ -9,8 +9,9 @@ import SwiftUI
import LeStorage
struct GroupStagesView: View {
var tournament: Tournament
@State var tournament: Tournament
@State private var selectedDestination: GroupStageDestination?
@EnvironmentObject var dataStore: DataStore
enum GroupStageDestination: Selectable, Identifiable, Equatable {
static func == (lhs: GroupStagesView.GroupStageDestination, rhs: GroupStagesView.GroupStageDestination) -> Bool {
@ -67,6 +68,7 @@ struct GroupStagesView: View {
return nil
}
case .loserBracket(let loserBracket):
if loserBracket._matches().isEmpty { return nil }
return loserBracket.badgeImage()
case .groupStage(let groupStage):
return groupStage.badgeImage()
@ -78,8 +80,6 @@ struct GroupStagesView: View {
tournament.groupStagesMatches()
}
@State private var isEditingLoserBracketGroupStage: Bool
init(tournament: Tournament) {
self.tournament = tournament
if tournament.shouldVerifyGroupStage {
@ -92,7 +92,6 @@ struct GroupStagesView: View {
_selectedDestination = State(wrappedValue: .groupStage(gs))
}
}
_isEditingLoserBracketGroupStage = .init(wrappedValue: tournament.groupStageLoserBracket()?._matches().isEmpty ?? false)
}
func allDestinations() -> [GroupStageDestination] {
@ -158,7 +157,6 @@ struct GroupStagesView: View {
GroupStageView(groupStage: groupStage).id(groupStage.id)
case .loserBracket(let loserBracket):
LoserBracketFromGroupStageView(loserBracket: loserBracket).id(loserBracket.id)
.environment(\.isEditingTournamentSeed, $isEditingLoserBracketGroupStage)
case nil:
GroupStagesSettingsView()
.navigationTitle("Réglages")

@ -10,32 +10,31 @@ import LeStorage
struct LoserBracketFromGroupStageView: View {
@Environment(\.isEditingTournamentSeed) var isEditingTournamentSeed
@Environment(Tournament.self) var tournament: Tournament
@EnvironmentObject var dataStore: DataStore
@Environment(NavigationViewModel.self) private var navigation: NavigationViewModel
@State var loserBracket: Round
@State private var isEditingLoserBracketGroupStage: Bool
init(loserBracket: Round) {
self.loserBracket = loserBracket
_isEditingLoserBracketGroupStage = .init(wrappedValue: loserBracket._matches().isEmpty)
}
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var displayableMatches: [Match] {
loserBracket.playedMatches().sorted(by: \.index)
}
var body: some View {
List {
let displayableMatches = loserBracket.playedMatches().sorted(by: \.index)
if isEditingTournamentSeed.wrappedValue == true {
if isEditingLoserBracketGroupStage == true && displayableMatches.isEmpty == false {
Section {
RowButtonView("Ajouter un match", role: .destructive) {
let placeCount = tournament.groupStageLoserBracketsInitialPlace() + displayableMatches.count * 2
let match = Match(round: loserBracket.id, index: placeCount, matchFormat: loserBracket.matchFormat)
match.name = "\(placeCount)\(placeCount.ordinalFormattedSuffix()) place"
do {
try tournamentStore.matches.addOrUpdate(instance: match)
} catch {
Logger.error(error)
}
_addNewMatch()
}
}
}
@ -43,9 +42,10 @@ struct LoserBracketFromGroupStageView: View {
ForEach(displayableMatches) { match in
Section {
MatchRowView(match: match, matchViewStyle: .sectionedStandardStyle)
.environment(\.isEditingTournamentSeed, $isEditingLoserBracketGroupStage)
} header: {
let tournamentTeamCount = tournament.teamCount
let seedIntervalPointRange = tournament.tournamentLevel.pointsRange(first: match.index, last: match.index + 1, teamsCount: tournamentTeamCount)
let seedIntervalPointRange = tournament.tournamentLevel.pointsRange(first: match.index, last: match.index + displayableMatches.filter({ $0.index == match.index }).count, teamsCount: tournamentTeamCount)
HStack {
Text(match.matchTitle(.wide))
Spacer()
@ -53,7 +53,7 @@ struct LoserBracketFromGroupStageView: View {
.font(.caption)
}
} footer: {
if isEditingTournamentSeed.wrappedValue == true {
if isEditingLoserBracketGroupStage == true {
HStack {
if match.index > tournament.groupStageLoserBracketsInitialPlace() {
FooterButtonView("même place qu'au-dessus") {
@ -80,7 +80,7 @@ struct LoserBracketFromGroupStageView: View {
}
Section {
if displayableMatches.isEmpty == false && isEditingTournamentSeed.wrappedValue == true {
if displayableMatches.count > 1 && isEditingLoserBracketGroupStage == true {
Section {
RowButtonView("Effacer tous les matchs", role: .destructive) {
_deleteAllMatches()
@ -91,20 +91,48 @@ struct LoserBracketFromGroupStageView: View {
}
}
}
.overlay {
if displayableMatches.isEmpty {
ContentUnavailableView {
Label("Aucun match de classement", systemImage: "figure.tennis")
} description: {
Text("Vous n'avez créé aucun match de classement entre les perdants de poules.")
} actions: {
RowButtonView("Ajouter un match") {
isEditingLoserBracketGroupStage = true
_addNewMatch()
}
.padding(.horizontal)
}
}
}
.headerProminence(.increased)
.navigationTitle("Classement de poules")
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button(isEditingTournamentSeed.wrappedValue == true ? "Valider" : "Modifier") {
if isEditingTournamentSeed.wrappedValue == true {
isEditingTournamentSeed.wrappedValue = false
if displayableMatches.isEmpty == false {
Button(isEditingLoserBracketGroupStage == true ? "Valider" : "Modifier") {
if isEditingLoserBracketGroupStage == true {
isEditingLoserBracketGroupStage = false
} else {
isEditingTournamentSeed.wrappedValue = true
isEditingLoserBracketGroupStage = true
}
}
}
}
}
}
private func _addNewMatch() {
let placeCount = tournament.groupStageLoserBracketsInitialPlace() + displayableMatches.count * 2
let match = Match(round: loserBracket.id, index: placeCount, matchFormat: loserBracket.matchFormat)
match.name = "\(placeCount)\(placeCount.ordinalFormattedSuffix()) place"
do {
try tournamentStore.matches.addOrUpdate(instance: match)
} catch {
Logger.error(error)
}
}
private func _deleteAllMatches() {
let displayableMatches = loserBracket.playedMatches().sorted(by: \.index)

@ -24,18 +24,20 @@ struct EditSharingView: View {
func shareMessage(displayRank: Bool, displayTeamName: Bool) -> String {
var messageData: [String] = []
var locAndTime: String = ""
if match.hasEnded() == false {
var locAndTime: String?
if let courtName = match.courtName() {
locAndTime.append("\(courtName)")
locAndTime = "\(courtName)"
}
if let startDate = match.startDate {
locAndTime = locAndTime + " à " + startDate.formattedAsHourMinute()
locAndTime = [locAndTime, startDate.formattedAsHourMinute()].compactMap({ $0 }).joined(separator: " à ")
}
if locAndTime.isEmpty == false {
if let locAndTime, locAndTime.isEmpty == false {
messageData.append(locAndTime)
}
}
if let tournament = match.currentTournament() {
messageData.append(tournament.tournamentTitle())
@ -52,6 +54,8 @@ struct EditSharingView: View {
let players = "\(labelOne)\ncontre\n\(labelTwo)"
messageData.append(players)
messageData.append(match.scoreLabel())
return messageData.joined(separator: "\n")
}

@ -9,7 +9,8 @@ import SwiftUI
struct MatchRowView: View {
var match: Match
@EnvironmentObject var dataStore: DataStore
@State var match: Match
let matchViewStyle: MatchViewStyle
var title: String? = nil

@ -214,6 +214,14 @@ struct MatchSetupView: View {
} catch {
Logger.error(error)
}
} else if match.isLoserBracket {
if let score = match.teamScore(ofTeam: team) {
do {
try tournamentStore.teamScores.delete(instance: score)
} catch {
Logger.error(error)
}
}
} else {
match.teamWillBeWalkOut(team)
do {

@ -8,7 +8,8 @@
import SwiftUI
struct MatchSummaryView: View {
var match: Match
@EnvironmentObject var dataStore: DataStore
@State var match: Match
let matchViewStyle: MatchViewStyle
let matchTitle: String
let roundTitle: String?

@ -68,19 +68,34 @@ struct TeamPickerView: View {
.toolbarBackground(.visible, for: .navigationBar)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .topBarLeading) {
Button("Annuler", role: .cancel) {
presentTeamPickerView = false
}
}
ToolbarItem(placement: .topBarTrailing) {
Menu {
Section {
Picker(selection: $sortOrder) {
Label("Poids", systemImage: "arrow.up").tag(SortOrder.ascending)
Label("Trier les équipes par poids croissant", systemImage: "chevron.up").tag(SortOrder.ascending)
.labelStyle(.titleAndIcon)
Label("Poids", systemImage: "arrow.down").tag(SortOrder.descending)
Label("Trier les équipes par poids décroissant", systemImage: "chevron.down").tag(SortOrder.descending)
.labelStyle(.titleAndIcon)
} label: {
Label("Trier", systemImage: "arrow.up.arrow.down")
Text("Trier les équipes par poids")
}
.pickerStyle(.inline)
} header: {
Text("Trier les équipes par poids")
}
} label: {
HStack {
Text("Poids")
Image(systemName: sortOrder == .ascending ? "chevron.up" : "chevron.down")
}
}
.pickerStyle(.menu)
}
}
.headerProminence(.increased)
}
.tint(.master)
}

Loading…
Cancel
Save