From 51395b60a4fed6a32cdcf46b9e43da9095a0dba1 Mon Sep 17 00:00:00 2001 From: Raz Date: Wed, 19 Mar 2025 10:41:41 +0100 Subject: [PATCH 1/5] fix wc stuff display --- PadelClub.xcodeproj/project.pbxproj | 4 +- PadelClub/Data/TeamRegistration.swift | 56 ++++++++++++++----- .../Views/GroupStage/GroupStageView.swift | 14 ++++- .../Match/Components/PlayerBlockView.swift | 51 ++++++++++------- PadelClub/Views/Team/TeamPickerView.swift | 12 +--- PadelClub/Views/Team/TeamRowView.swift | 27 ++++----- .../Screen/TableStructureView.swift | 1 + 7 files changed, 99 insertions(+), 66 deletions(-) diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index 2e1b674..d2c05a1 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -3344,7 +3344,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.23; + MARKETING_VERSION = 1.1.24; PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -3389,7 +3389,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.23; + MARKETING_VERSION = 1.1.24; PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/PadelClub/Data/TeamRegistration.swift b/PadelClub/Data/TeamRegistration.swift index 72de9bc..7019524 100644 --- a/PadelClub/Data/TeamRegistration.swift +++ b/PadelClub/Data/TeamRegistration.swift @@ -600,7 +600,7 @@ final class TeamRegistration: ModelObject, Storable { func wildcardLabel() -> String? { if isWildCard() { - let wildcardLabel: String = ["wildcard", (wildCardBracket ? "tableau" : "poule")].joined(separator: " ") + let wildcardLabel: String = ["Wildcard", (wildCardBracket ? "Tableau" : "Poule")].joined(separator: " ") return wildcardLabel } else { return nil @@ -647,22 +647,48 @@ final class TeamRegistration: ModelObject, Storable { unsortedPlayers().count > 0 } - func bracketMatchTitleAndQualifiedStatus() -> String? { - let v = groupStageObject()?.groupStageTitle() - var base = "Qualifié" - if qualified { - if let groupStageTitle = groupStageObject()?.groupStageTitle() { - base = base + " (\(groupStageTitle))" - } + func teamInitialPositionBracket() -> String? { + let round = initialMatch()?.roundAndMatchTitle() + if let round { + return round } - - let suffix = qualified ? nil : groupStageObject()?.groupStageTitle() - let initalMatchTitle = initialMatch()?.roundAndMatchTitle() ?? suffix - let values = [qualified ? base : nil, initalMatchTitle].compactMap({ $0 }) - if values.isEmpty { - return nil + return nil + } + + func teamInitialPositionGroupStage() -> String? { + let groupStage = self.groupStageObject() + let group = groupStage?.groupStageTitle(.title) + var groupPositionLabel: String? = nil + if let finalPosition = groupStage?.finalPosition(ofTeam: self) { + groupPositionLabel = (finalPosition + 1).ordinalFormatted() + } else if let groupStagePosition { + groupPositionLabel = "\(groupStagePosition + 1)" + } + + if let group { + if let groupPositionLabel { + return [group, "#\(groupPositionLabel)"].joined(separator: " ") + } else { + return group + } + } + return nil + } + + func qualifiedStatus(hideBracketStatus: Bool = false) -> String? { + let teamInitialPositionBracket = teamInitialPositionBracket() + let groupStageTitle = teamInitialPositionGroupStage() + + let base: String? = qualified ? "Qualifié" : nil + if let groupStageTitle, let teamInitialPositionBracket, hideBracketStatus == false { + return [base, groupStageTitle, ">", teamInitialPositionBracket].compactMap({ $0 }).joined(separator: " ") + } else if let groupStageTitle { + return [base, groupStageTitle].compactMap({ $0 }).joined(separator: " ") + } else if hideBracketStatus == false { + return teamInitialPositionBracket } - return values.joined(separator: " -> ") + + return nil } enum CodingKeys: String, CodingKey { diff --git a/PadelClub/Views/GroupStage/GroupStageView.swift b/PadelClub/Views/GroupStage/GroupStageView.swift index 9fc489f..adbb27f 100644 --- a/PadelClub/Views/GroupStage/GroupStageView.swift +++ b/PadelClub/Views/GroupStage/GroupStageView.swift @@ -140,12 +140,16 @@ struct GroupStageView: View { GroupStageTeamView(groupStage: groupStage, team: team) .environment(self.tournament) } label: { + let players = team.players() VStack(alignment: .leading, spacing: 4.0) { HStack(spacing: 6.0) { Text("#\(groupStagePosition + 1)") - if groupStage.tournamentObject()?.hideWeight() == false { + if players.isEmpty == false, groupStage.tournamentObject()?.hideWeight() == false { Text("Poids \(team.weight)") } + if players.isEmpty == false, team.isWildCard() { + Text("wildcard").foregroundStyle(.logoRed).font(.caption).italic() + } Spacer() if team.qualified { Text("qualifié") @@ -156,8 +160,14 @@ struct GroupStageView: View { VStack(alignment: .leading) { if let teamName = team.name, teamName.isEmpty == false { Text(teamName).foregroundStyle(.secondary).font(.footnote) + } else if players.isEmpty { + if team.isWildCard() { + Text("Place réservée wildcard") + } else { + Text("Place réservée") + } } - ForEach(team.players()) { player in + ForEach(players) { player in Text(player.playerLabel()).lineLimit(1) .overlay { if player.hasArrived && team.isHere() == false { diff --git a/PadelClub/Views/Match/Components/PlayerBlockView.swift b/PadelClub/Views/Match/Components/PlayerBlockView.swift index e2a7e15..5e9d2b3 100644 --- a/PadelClub/Views/Match/Components/PlayerBlockView.swift +++ b/PadelClub/Views/Match/Components/PlayerBlockView.swift @@ -74,39 +74,48 @@ struct PlayerBlockView: View { var body: some View { HStack { VStack(alignment: .leading) { - if let team { - if let teamScore, teamScore.luckyLoser != nil, match.isLoserBracket == false { - Text("Repêchée").italic().font(.caption) + ZStack(alignment: .leading) { + VStack { + if let teamName = team?.name { + Text(teamName).foregroundStyle(.secondary).font(.footnote) + } + Text("longLabelPlayerOne").lineLimit(1) + Text("longLabelPlayerTwo").lineLimit(1) } + .opacity(0) - if let teamName = team.name { - Text(teamName).foregroundStyle(.secondary).font(.footnote) - } - ForEach(team.players()) { player in - Text(player.playerLabel()).lineLimit(1) - .italic(player.isHere() == false) - .foregroundStyle(player.isHere() == false ? .secondary : .primary) - } - } else { - ZStack(alignment: .leading) { - VStack { - if let teamName = team?.name { - Text(teamName).foregroundStyle(.secondary).font(.footnote) + if let team { + if let teamScore, teamScore.luckyLoser != nil, match.isLoserBracket == false { + Text("Repêchée").italic().font(.caption) + } + + if let teamName = team.name { + Text(teamName).foregroundStyle(.secondary).font(.footnote) + } else if team.players().isEmpty { + if team.isWildCard() { + Text("Place réservée wildcard") + } else { + Text("Place réservée") } - Text("longLabelPlayerOne").lineLimit(1) - Text("longLabelPlayerTwo").lineLimit(1) } - .opacity(0) + VStack(alignment: .leading) { + ForEach(team.players()) { player in + Text(player.playerLabel()).lineLimit(1) + .italic(player.isHere() == false) + .foregroundStyle(player.isHere() == false ? .secondary : .primary) + } + } + } else { VStack(alignment: .leading) { ForEach(_defaultLabel(), id: \.self) { name in Text(name) - .foregroundStyle(.secondary) + .foregroundStyle(.secondary) .lineLimit(1) } } } } - + if displayRestingTime, let team { TeamRowView.TeamRestingView(team: team) } diff --git a/PadelClub/Views/Team/TeamPickerView.swift b/PadelClub/Views/Team/TeamPickerView.swift index 73b8d59..e8d3ad8 100644 --- a/PadelClub/Views/Team/TeamPickerView.swift +++ b/PadelClub/Views/Team/TeamPickerView.swift @@ -134,15 +134,9 @@ struct TeamPickerView: View { // presentTeamPickerView = false // } } label: { - VStack(alignment: .leading) { - if let roundAndMatchTitle = team.bracketMatchTitleAndQualifiedStatus() { - Text(roundAndMatchTitle) - .font(.headline) - .frame(maxWidth: .infinity, alignment: .leading) - } - TeamRowView(team: team) - } - .contentShape(Rectangle()) + TeamRowView(team: team) + .environment(\.isEditingTournamentSeed, .constant(false)) + .contentShape(Rectangle()) } .frame(maxWidth: .infinity) .buttonStyle(.plain) diff --git a/PadelClub/Views/Team/TeamRowView.swift b/PadelClub/Views/Team/TeamRowView.swift index bb32774..13b5ee0 100644 --- a/PadelClub/Views/Team/TeamRowView.swift +++ b/PadelClub/Views/Team/TeamRowView.swift @@ -9,7 +9,6 @@ import SwiftUI struct TeamRowView: View { @EnvironmentObject var dataStore: DataStore - @Environment(\.isEditingTournamentSeed) private var isEditingTournamentSeed var team: TeamRegistration var teamPosition: TeamPosition? = nil @@ -22,9 +21,7 @@ struct TeamRowView: View { TeamWeightView(team: team, teamPosition: teamPosition, teamIndex: teamIndex) } label: { VStack(alignment: .leading) { - if isEditingTournamentSeed.wrappedValue == false { - TeamHeadlineView(team: team) - } + TeamHeadlineView(team: team) TeamView(team: team) } if displayCallDate { @@ -78,23 +75,19 @@ struct TeamRowView: View { } struct TeamHeadlineView: View { + @Environment(\.isEditingTournamentSeed) private var isEditingTournamentSeed let team: TeamRegistration var body: some View { - HStack { - if let groupStage = team.groupStageObject() { - HStack { - Text(groupStage.groupStageTitle(.title)) - if let finalPosition = groupStage.finalPosition(ofTeam: team) { - Text((finalPosition + 1).ordinalFormatted()) - } - } - } else if let round = team.initialRound() { - Text(round.roundTitle(.wide)) - } - + VStack(alignment: .leading) { if let wildcardLabel = team.wildcardLabel() { - Text(wildcardLabel).italic().foregroundStyle(.red).font(.caption) + Text(wildcardLabel).italic().foregroundStyle(.logoRed).font(.caption) + } + + if let qualifiedStatus = team.qualifiedStatus(hideBracketStatus: isEditingTournamentSeed.wrappedValue == true) { + Text(qualifiedStatus) + .font(.caption) + .foregroundStyle(.secondary) } } } diff --git a/PadelClub/Views/Tournament/Screen/TableStructureView.swift b/PadelClub/Views/Tournament/Screen/TableStructureView.swift index 444ce72..9d8f20b 100644 --- a/PadelClub/Views/Tournament/Screen/TableStructureView.swift +++ b/PadelClub/Views/Tournament/Screen/TableStructureView.swift @@ -295,6 +295,7 @@ struct TableStructureView: View { RowButtonView("Remise-à-zéro", role: .destructive) { tournament.deleteGroupStages() tournament.deleteStructure() + structurePreset = PadelTournamentStructurePreset.manual } } } From 0a6d7fe79768458148378fd65225ff89c2e2476c Mon Sep 17 00:00:00 2001 From: Raz Date: Wed, 19 Mar 2025 12:12:22 +0100 Subject: [PATCH 2/5] fix table reset --- PadelClub/Data/Tournament.swift | 11 +++++- .../Screen/TableStructureView.swift | 39 +++++++++++++++---- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index f104e3a..492386c 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -2063,10 +2063,19 @@ defer { } } + func removeWildCards() { + let wcs = unsortedTeams().filter({ $0.isWildCard() && $0.unsortedPlayers().isEmpty }) + do { + try tournamentStore.teamRegistrations.delete(contentOfs: wcs) + } catch { + Logger.error(error) + } + } + func setGroupStageTeams(randomize: Bool) { let groupStages = groupStages() let max = groupStages.map { $0.size }.reduce(0,+) - var chunks = selectedSortedTeams().suffix(max).chunked(into: groupStageCount) + var chunks = selectedSortedTeams().filter({ $0.wildCardBracket == false }).suffix(max).chunked(into: groupStageCount) for (index, _) in chunks.enumerated() { if randomize { chunks[index].shuffle() diff --git a/PadelClub/Views/Tournament/Screen/TableStructureView.swift b/PadelClub/Views/Tournament/Screen/TableStructureView.swift index 9d8f20b..58f7145 100644 --- a/PadelClub/Views/Tournament/Screen/TableStructureView.swift +++ b/PadelClub/Views/Tournament/Screen/TableStructureView.swift @@ -81,12 +81,7 @@ struct TableStructureView: View { Text(structurePreset.localizedDescriptionStructurePresetTitle()) } .onChange(of: structurePreset) { - teamCount = structurePreset.tableDimension() + structurePreset.teamsInQualifiers() - structurePreset.qualifiedPerGroupStage() * structurePreset.groupStageCount() - groupStageCount = structurePreset.groupStageCount() - teamsPerGroupStage = structurePreset.teamsPerGroupStage() - qualifiedPerGroupStage = structurePreset.qualifiedPerGroupStage() - groupStageAdditionalQualified = 0 - buildWildcards = tournament.level.wildcardArePossible() + _updatePreset() } } @@ -293,9 +288,27 @@ struct TableStructureView: View { Section { RowButtonView("Remise-à-zéro", role: .destructive) { + tournament.removeWildCards() tournament.deleteGroupStages() tournament.deleteStructure() - structurePreset = PadelTournamentStructurePreset.manual + + if structurePreset != .manual { + structurePreset = PadelTournamentStructurePreset.manual + } else { + _updatePreset() + } + + tournament.teamCount = teamCount + tournament.groupStageCount = groupStageCount + tournament.teamsPerGroupStage = teamsPerGroupStage + tournament.qualifiedPerGroupStage = qualifiedPerGroupStage + tournament.groupStageAdditionalQualified = groupStageAdditionalQualified + + do { + try dataStore.tournaments.addOrUpdate(instance: tournament) + } catch { + Logger.error(error) + } } } } @@ -444,11 +457,12 @@ struct TableStructureView: View { tournament.groupStageAdditionalQualified = groupStageAdditionalQualified if rebuildEverything { - tournament.deleteAndBuildEverything(preset: structurePreset) + tournament.removeWildCards() if structurePreset.hasWildcards(), buildWildcards { tournament.addWildCardIfNeeded(structurePreset.wildcardBrackets(), .bracket) tournament.addWildCardIfNeeded(structurePreset.wildcardQualifiers(), .groupStage) } + tournament.deleteAndBuildEverything(preset: structurePreset) } else if (rebuildEverything == false && requirements.contains(.groupStage)) { tournament.deleteGroupStages() tournament.buildGroupStages() @@ -467,6 +481,15 @@ struct TableStructureView: View { } } + private func _updatePreset() { + teamCount = structurePreset.tableDimension() + structurePreset.teamsInQualifiers() - structurePreset.qualifiedPerGroupStage() * structurePreset.groupStageCount() + groupStageCount = structurePreset.groupStageCount() + teamsPerGroupStage = structurePreset.teamsPerGroupStage() + qualifiedPerGroupStage = structurePreset.qualifiedPerGroupStage() + groupStageAdditionalQualified = 0 + buildWildcards = tournament.level.wildcardArePossible() + } + private func _verifyValueIntegrity() { if teamCount > 128 { teamCount = 128 From faa9cd8182cfe97ca49d07a5e8ff253f4d31202a Mon Sep 17 00:00:00 2001 From: Raz Date: Wed, 19 Mar 2025 12:47:45 +0100 Subject: [PATCH 3/5] lock team --- .../Views/Tournament/Screen/AddTeamView.swift | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/PadelClub/Views/Tournament/Screen/AddTeamView.swift b/PadelClub/Views/Tournament/Screen/AddTeamView.swift index c18ada5..4e9fc2e 100644 --- a/PadelClub/Views/Tournament/Screen/AddTeamView.swift +++ b/PadelClub/Views/Tournament/Screen/AddTeamView.swift @@ -216,6 +216,7 @@ struct AddTeamView: View { let first = strings.first ?? "" handlePasteString(first) } + .disabled(_limitPlayerCount()) .foregroundStyle(.master) .labelStyle(.titleAndIcon) .buttonBorderShape(.capsule) @@ -236,6 +237,7 @@ struct AddTeamView: View { } label: { Label("Coller", systemImage: "doc.on.clipboard").labelStyle(.iconOnly) } + .disabled(_limitPlayerCount()) .foregroundStyle(.master) .labelStyle(.iconOnly) .buttonBorderShape(.capsule) @@ -258,12 +260,20 @@ struct AddTeamView: View { tournament.unsortedPlayers() } + private func _limitPlayerCount() -> Bool { + if tournament.isAnimation() { + return false + } + return _currentSelection().count >= tournament.significantPlayerCount() + } + @ViewBuilder private func _managementView() -> some View { Section { RowButtonView("Ajouter via la base fédérale") { presentPlayerSearch = true } + .disabled(_limitPlayerCount()) } footer: { if let rankSourceDate = tournament.rankSourceDate { Text("Cherchez dans la base fédérale de \(rankSourceDate.monthYearFormatted), vous y trouverez tous les joueurs ayant participé à au moins un tournoi dans les 12 derniers mois.") @@ -288,6 +298,7 @@ struct AddTeamView: View { presentPlayerCreation = true } } + .disabled(_limitPlayerCount()) } footer: { Text("Si le joueur n'a pas encore de licence ou n'a pas encore participé à une compétition, vous pouvez le créer vous-même.") } @@ -557,6 +568,10 @@ struct AddTeamView: View { // } else { // Text("Préparation de l'équipe") } + } footer: { + if _limitPlayerCount() { + Text("Taille maximum de l'équipe atteinte, supprimer un joueur pour pouvoir en rajouter un autre").foregroundStyle(.logoRed) + } } From 7721302377214cb18875c74a75b3fede724d1f9c Mon Sep 17 00:00:00 2001 From: Raz Date: Thu, 20 Mar 2025 17:27:21 +0100 Subject: [PATCH 4/5] v1.1.25 --- PadelClub.xcodeproj/project.pbxproj | 4 ++-- PadelClub/Data/Round.swift | 6 +++--- PadelClub/Data/Tournament.swift | 4 ++-- PadelClub/Views/Team/Components/TeamWeightView.swift | 7 ++++++- PadelClub/Views/Team/TeamPickerView.swift | 7 +++++-- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index d2c05a1..1dd8dcb 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -3344,7 +3344,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.24; + MARKETING_VERSION = 1.1.25; PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -3389,7 +3389,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.24; + MARKETING_VERSION = 1.1.25; PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/PadelClub/Data/Round.swift b/PadelClub/Data/Round.swift index 38355c2..de2cb34 100644 --- a/PadelClub/Data/Round.swift +++ b/PadelClub/Data/Round.swift @@ -650,9 +650,9 @@ defer { let roundCount = RoundRule.numberOfRounds(forTeams: currentRoundMatchCount) var loserBracketMatchFormat = tournamentObject()?.loserBracketMatchFormat - if let parentRound { - loserBracketMatchFormat = tournamentObject()?.loserBracketSmartMatchFormat(parentRound.index) - } +// if let parentRound { +// loserBracketMatchFormat = tournamentObject()?.loserBracketSmartMatchFormat(parentRound.index) +// } let rounds = (0.. some View { + let selectedSortedTeams = tournament.selectedSortedTeams() ForEach(teams) { team in if searchField.isEmpty || team.contains(searchField) { Button { @@ -134,7 +136,8 @@ struct TeamPickerView: View { // presentTeamPickerView = false // } } label: { - TeamRowView(team: team) + let teamIndex = team.index(in: selectedSortedTeams) + TeamRowView(team: team, teamIndex: teamIndex) .environment(\.isEditingTournamentSeed, .constant(false)) .contentShape(Rectangle()) } From 563404d92bd473eea337fe5c0c37fd53c10e3ac7 Mon Sep 17 00:00:00 2001 From: Raz Date: Thu, 20 Mar 2025 18:03:53 +0100 Subject: [PATCH 5/5] fix tournament deletion for the online reg tournament unpaid --- .../Screen/Components/TournamentStatusView.swift | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/PadelClub/Views/Tournament/Screen/Components/TournamentStatusView.swift b/PadelClub/Views/Tournament/Screen/Components/TournamentStatusView.swift index 23bdad9..2d3ce23 100644 --- a/PadelClub/Views/Tournament/Screen/Components/TournamentStatusView.swift +++ b/PadelClub/Views/Tournament/Screen/Components/TournamentStatusView.swift @@ -49,14 +49,15 @@ struct TournamentStatusView: View { let event = tournament.eventObject() let isLastTournament = event?.tournaments.count == 1 - tournament.isDeleted = true - - try dataStore.tournaments.addOrUpdate(instance: tournament) - - if let event, isLastTournament { - try dataStore.events.delete(instance: event) + if tournament.onlineTeams().isEmpty == false { + tournament.isDeleted = true + try dataStore.tournaments.addOrUpdate(instance: tournament) } else { - try dataStore.tournaments.delete(instance: tournament) + if let event, isLastTournament { + try dataStore.events.delete(instance: event) + } else { + try dataStore.tournaments.delete(instance: tournament) + } } if eventDismiss == false || isLastTournament { navigation.path = NavigationPath()