paca_championship
Raz 1 year ago
parent 17f371e450
commit 7c3725ce5b
  1. 18
      PadelClub/Data/Match.swift
  2. 8
      PadelClub/Data/TeamRegistration.swift
  3. 2
      PadelClub/Views/Calling/Components/MenuWarningView.swift
  4. 8
      PadelClub/Views/Cashier/CashierView.swift
  5. 2
      PadelClub/Views/GroupStage/Components/GroupStageTeamView.swift
  6. 19
      PadelClub/Views/GroupStage/GroupStageView.swift
  7. 2
      PadelClub/Views/GroupStage/Shared/GroupStageTeamReplacementView.swift
  8. 20
      PadelClub/Views/Match/Components/PlayerBlockView.swift
  9. 21
      PadelClub/Views/Round/LoserRoundSettingsView.swift
  10. 112
      PadelClub/Views/Round/RoundSettingsView.swift
  11. 4
      PadelClub/Views/Team/Components/TeamHeaderView.swift
  12. 8
      PadelClub/Views/Team/TeamRowView.swift
  13. 7
      PadelClub/Views/Tournament/FileImportView.swift
  14. 4
      PadelClub/Views/Tournament/Screen/TournamentRankView.swift

@ -347,15 +347,21 @@ defer {
guard let forwardMatch = _forwardMatch(inRound: roundObject) else { return }
guard let next = _otherMatch() else { return }
if next.disabled && byeState == false && next.byeState == false {
forwardMatch.byeState = false
forwardMatch._toggleMatchDisableState(state, forward: true)
if forwardMatch.disabled != state || forwardMatch.byeState {
forwardMatch.byeState = false
forwardMatch._toggleMatchDisableState(state, forward: true)
}
} else if byeState && next.byeState {
print("don't disable forward match")
forwardMatch.byeState = false
forwardMatch._toggleMatchDisableState(false, forward: true)
if forwardMatch.byeState || forwardMatch.disabled {
forwardMatch.byeState = false
forwardMatch._toggleMatchDisableState(false, forward: true)
}
} else {
forwardMatch.byeState = true
forwardMatch._toggleMatchDisableState(state, forward: true)
if forwardMatch.byeState == false || forwardMatch.disabled != state {
forwardMatch.byeState = true
forwardMatch._toggleMatchDisableState(state, forward: true)
}
}
// if next.disabled == false {

@ -536,6 +536,14 @@ final class TeamRegistration: ModelObject, Storable {
matches().sorted(by: \.computedEndDateForSorting).last?.endDate
}
func teamNameLabel() -> String {
if let name, name.isEmpty == false {
return name
} else {
return "Toute l'équipe"
}
}
enum CodingKeys: String, CodingKey {
case _id = "id"
case _tournament = "tournament"

@ -124,7 +124,7 @@ struct MenuWarningView: View {
@ViewBuilder
func _teamActionView(_ team: TeamRegistration) -> some View {
Menu(team.name ?? "Toute l'équipe") {
Menu(team.teamNameLabel()) {
let players = team.players()
_actionView(players: players)
}

@ -377,8 +377,8 @@ struct CashierView: View {
}
} header: {
HStack {
if let name = team.name {
Text(name)
if let teamName = team.name, teamName.isEmpty == false {
Text(teamName)
}
if displayTournamentTitle, let tournamentTitle = team.tournamentObject()?.tournamentTitle() {
Spacer()
@ -418,8 +418,8 @@ struct CashierView: View {
EditablePlayerView(player: player, editingOptions: editingOptions)
}
} header: {
if let name = team.name {
Text(name)
if let teamName = team.name, teamName.isEmpty == false {
Text(teamName)
}
if displayTournamentTitle, let tournamentTitle = team.tournamentObject()?.tournamentTitle() {

@ -48,7 +48,7 @@ struct GroupStageTeamView: View {
var body: some View {
List {
Section {
if let name = team.name {
if let name = team.name, name.isEmpty == false {
Text(name).foregroundStyle(.secondary)
}
ForEach(team.players()) { player in

@ -142,17 +142,16 @@ struct GroupStageView: View {
.font(.footnote)
HStack {
VStack(alignment: .leading) {
if let teamName = team.name {
Text(teamName).font(.title3)
} else {
ForEach(team.players()) { player in
Text(player.playerLabel()).lineLimit(1)
.overlay {
if player.hasArrived && team.isHere() == false {
Color.green.opacity(0.6)
}
if let teamName = team.name, teamName.isEmpty == false {
Text(teamName).foregroundStyle(.secondary).font(.footnote)
}
ForEach(team.players()) { player in
Text(player.playerLabel()).lineLimit(1)
.overlay {
if player.hasArrived && team.isHere() == false {
Color.green.opacity(0.6)
}
}
}
}
}
Spacer()

@ -54,7 +54,7 @@ struct GroupStageTeamReplacementView: View {
Section {
Picker(selection: $selectedPlayer) {
HStack {
Text(team.name ?? "Toute l'équipe")
Text(team.teamNameLabel())
Spacer()
Text(team.weight.formatted()).bold()
}

@ -58,22 +58,20 @@ struct PlayerBlockView: View {
Text("Repêchée").italic().font(.caption)
}
if let name = team?.name {
Text(name).font(.title3)
} else {
ForEach(names, id: \.self) { name in
Text(name).lineLimit(1)
}
if let teamName = team?.name {
Text(teamName).foregroundStyle(.secondary).font(.footnote)
}
ForEach(names, id: \.self) { name in
Text(name).lineLimit(1)
}
} else {
ZStack(alignment: .leading) {
VStack {
if let name = team?.name {
Text(name).font(.title3)
} else {
Text("longLabelPlayerOne").lineLimit(1)
Text("longLabelPlayerTwo").lineLimit(1)
if let teamName = team?.name {
Text(teamName).foregroundStyle(.secondary).font(.footnote)
}
Text("longLabelPlayerOne").lineLimit(1)
Text("longLabelPlayerTwo").lineLimit(1)
}
.opacity(0)
Text(_defaultLabel()).foregroundStyle(.secondary).lineLimit(1)

@ -80,15 +80,7 @@ struct LoserRoundSettingsView: View {
Section {
RowButtonView("Créer les matchs de classements", role: .destructive) {
upperBracketRound.round.buildLoserBracket()
upperBracketRound.round.disabledMatches().forEach { match in
match._toggleLoserMatchDisableState(true)
}
do {
try self.tournament.tournamentStore.matches.addOrUpdate(contentOfs: upperBracketRound.round.allLoserRoundMatches())
} catch {
Logger.error(error)
}
await _addLoserBracketMatches()
}
}
.disabled(upperBracketRound.round.loserRounds().isEmpty == false)
@ -147,6 +139,17 @@ struct LoserRoundSettingsView: View {
Text(" Modifier quand même ?").foregroundStyle(.red)
}
private func _addLoserBracketMatches() async {
upperBracketRound.round.buildLoserBracket()
upperBracketRound.round.disabledMatches().forEach { match in
match._toggleLoserMatchDisableState(true)
}
do {
try self.tournament.tournamentStore.matches.addOrUpdate(contentOfs: upperBracketRound.round.allLoserRoundMatches())
} catch {
Logger.error(error)
}
}
}
//#Preview {

@ -93,64 +93,14 @@ struct RoundSettingsView: View {
Section {
let roundIndex = tournament.rounds().count
RowButtonView("Ajouter " + RoundRule.roundName(fromRoundIndex: roundIndex), role: .destructive) {
let round = Round(tournament: tournament.id, index: roundIndex, matchFormat: tournament.matchFormat)
let matchCount = RoundRule.numberOfMatches(forRoundIndex: roundIndex)
let matchStartIndex = RoundRule.matchIndex(fromRoundIndex: roundIndex)
let nextRound = round.nextRound()
var currentIndex = 0
let matches = (0..<matchCount).map { index in //0 is final match
let computedIndex = index + matchStartIndex
let match = Match(round: round.id, index: computedIndex, matchFormat: round.matchFormat)
if let nextRound, let followingMatch = self.tournament.tournamentStore.matches.first(where: { $0.round == nextRound.id && $0.index == (computedIndex - 1) / 2 }) {
if followingMatch.disabled {
match.disabled = true
} else if computedIndex%2 == 1 && followingMatch.team(.one) != nil {
//index du match courant impair = position haut du prochain match
match.disabled = true
} else if computedIndex%2 == 0 && followingMatch.team(.two) != nil {
//index du match courant pair = position basse du prochain match
match.disabled = true
} else {
match.setMatchName(Match.setServerTitle(upperRound: round, matchIndex: currentIndex))
currentIndex += 1
}
} else {
match.setMatchName(Match.setServerTitle(upperRound: round, matchIndex: currentIndex))
currentIndex += 1
}
return match
}
do {
try tournamentStore.rounds.addOrUpdate(instance: round)
} catch {
Logger.error(error)
}
do {
try tournamentStore.matches.addOrUpdate(contentOfs: matches)
} catch {
Logger.error(error)
}
round.buildLoserBracket()
matches.filter { $0.disabled }.forEach {
$0._toggleLoserMatchDisableState(true)
}
await _addNewRound(roundIndex)
}
}
Section {
if let lastRound = tournament.rounds().first { // first is final, last round
RowButtonView("Supprimer " + lastRound.roundTitle(), role: .destructive) {
do {
let teams = lastRound.seeds()
teams.forEach { team in
team.resetBracketPosition()
}
try tournamentStore.teamRegistrations.addOrUpdate(contentOfs: teams)
try tournamentStore.rounds.delete(instance: lastRound)
} catch {
Logger.error(error)
}
await _removeRound(lastRound)
}
}
}
@ -199,6 +149,64 @@ struct RoundSettingsView: View {
})
self.isEditingTournamentSeed.wrappedValue = true
}
private func _addNewRound(_ roundIndex: Int) async {
let round = Round(tournament: tournament.id, index: roundIndex, matchFormat: tournament.matchFormat)
let matchCount = RoundRule.numberOfMatches(forRoundIndex: roundIndex)
let matchStartIndex = RoundRule.matchIndex(fromRoundIndex: roundIndex)
let nextRound = round.nextRound()
var currentIndex = 0
let matches = (0..<matchCount).map { index in //0 is final match
let computedIndex = index + matchStartIndex
let match = Match(round: round.id, index: computedIndex, matchFormat: round.matchFormat)
if let nextRound, let followingMatch = self.tournament.tournamentStore.matches.first(where: { $0.round == nextRound.id && $0.index == (computedIndex - 1) / 2 }) {
if followingMatch.disabled {
match.disabled = true
} else if computedIndex%2 == 1 && followingMatch.team(.one) != nil {
//index du match courant impair = position haut du prochain match
match.disabled = true
} else if computedIndex%2 == 0 && followingMatch.team(.two) != nil {
//index du match courant pair = position basse du prochain match
match.disabled = true
} else {
match.setMatchName(Match.setServerTitle(upperRound: round, matchIndex: currentIndex))
currentIndex += 1
}
} else {
match.setMatchName(Match.setServerTitle(upperRound: round, matchIndex: currentIndex))
currentIndex += 1
}
return match
}
do {
try tournamentStore.rounds.addOrUpdate(instance: round)
} catch {
Logger.error(error)
}
do {
try tournamentStore.matches.addOrUpdate(contentOfs: matches)
} catch {
Logger.error(error)
}
round.buildLoserBracket()
matches.filter { $0.disabled }.forEach {
$0._toggleLoserMatchDisableState(true)
}
}
private func _removeRound(_ lastRound: Round) async {
do {
let teams = lastRound.seeds()
teams.forEach { team in
team.resetBracketPosition()
}
try tournamentStore.teamRegistrations.addOrUpdate(contentOfs: teams)
try tournamentStore.rounds.delete(instance: lastRound)
} catch {
Logger.error(error)
}
}
}
//#Preview {

@ -29,10 +29,10 @@ struct TeamHeaderView: View {
Text(team.weight.formatted())
}
}
if let name = team.name {
if let name = team.name, name.isEmpty == false {
VStack(alignment: .leading, spacing: 0) {
Text("Nom de l'équipe").font(.caption)
Text(name)
Text(name).lineLimit(1).truncationMode(.tail)
}
}
}

@ -35,10 +35,14 @@ struct TeamRowView: View {
}
}
if let name = team.name {
Text(name).font(.title3)
if let name = team.name, name.isEmpty == false {
Text(name).foregroundStyle(.secondary).font(.footnote)
if team.players().isEmpty {
Text("Aucun joueur")
} else {
ForEach(team.players()) { player in
Text(player.playerLabel()).lineLimit(1).truncationMode(.tail)
}
}
} else {
if team.players().isEmpty == false {

@ -86,6 +86,11 @@ struct FileImportView: View {
@State private var validatedTournamentIds: Set<String> = Set()
@State private var chunkByParameter: Bool = true
enum ChunkMode {
case byParameter
case byCoupleOfLines
}
init(defaultFileProvider: FileImportManager.FileProvider = .frenchFederation) {
_fileProvider = .init(wrappedValue: defaultFileProvider)
}
@ -558,7 +563,7 @@ struct FileImportView: View {
Section {
HStack {
VStack(alignment: .leading) {
if let teamName = team.name {
if let teamName = team.name, teamName.isEmpty == false {
Text(teamName).foregroundStyle(.secondary)
}
ForEach(team.players.sorted(by: \.computedRank)) {

@ -233,8 +233,8 @@ struct TournamentRankView: View {
Divider()
VStack(alignment: .leading) {
if let name = team.name {
Text(name).foregroundStyle(.secondary)
if let teamName = team.name, teamName.isEmpty == false {
Text(teamName).foregroundStyle(.secondary)
}
ForEach(team.players()) { player in

Loading…
Cancel
Save