From 289056bcd0c2a2b53b3866f1043e78a91a9538f9 Mon Sep 17 00:00:00 2001 From: Raz Date: Sat, 1 Mar 2025 12:21:36 +0100 Subject: [PATCH] b2 --- PadelClub.xcodeproj/project.pbxproj | 4 +- PadelClub/Data/GroupStage.swift | 24 +++--- PadelClub/Views/Calling/CallView.swift | 12 ++- .../Views/GroupStage/GroupStagesView.swift | 81 ++++++++++++++++++- .../Screen/TableStructureView.swift | 2 +- 5 files changed, 104 insertions(+), 19 deletions(-) diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index db5ca97..a501486 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -3318,7 +3318,7 @@ CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; @@ -3364,7 +3364,7 @@ CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_TEAM = BQ3Y44M3Q6; diff --git a/PadelClub/Data/GroupStage.swift b/PadelClub/Data/GroupStage.swift index c84ab31..b60f139 100644 --- a/PadelClub/Data/GroupStage.swift +++ b/PadelClub/Data/GroupStage.swift @@ -438,7 +438,7 @@ final class GroupStage: ModelObject, Storable { unsortedTeams().flatMap({ $0.unsortedPlayers() }) } - fileprivate typealias TeamScoreAreInIncreasingOrder = (TeamGroupStageScore, TeamGroupStageScore) -> Bool + typealias TeamScoreAreInIncreasingOrder = (TeamGroupStageScore, TeamGroupStageScore) -> Bool typealias TeamGroupStageScore = (team: TeamRegistration, wins: Int, loses: Int, setDifference: Int, gameDifference: Int) @@ -492,20 +492,24 @@ final class GroupStage: ModelObject, Storable { var scoreCache: [Int: TeamGroupStageScore] = [:] + func computedScore(forTeam team: TeamRegistration, step: Int = 0) -> TeamGroupStageScore? { + if let cachedScore = scoreCache[team.groupStagePositionAtStep(step)!] { + return cachedScore + } else { + let score = _score(forGroupStagePosition: team.groupStagePositionAtStep(step)!) + if let score = score { + scoreCache[team.groupStagePositionAtStep(step)!] = score + } + return score + } + } + func teams(_ sortedByScore: Bool = false, scores: [TeamGroupStageScore]? = nil) -> [TeamRegistration] { if sortedByScore { return unsortedTeams().compactMap({ team in // Check cache or use provided scores, otherwise calculate and store in cache scores?.first(where: { $0.team.id == team.id }) ?? { - if let cachedScore = scoreCache[team.groupStagePositionAtStep(step)!] { - return cachedScore - } else { - let score = _score(forGroupStagePosition: team.groupStagePositionAtStep(step)!) - if let score = score { - scoreCache[team.groupStagePositionAtStep(step)!] = score - } - return score - } + return computedScore(forTeam: team, step: step) }() }).sorted { (lhs, rhs) in let predicates: [TeamScoreAreInIncreasingOrder] = [ diff --git a/PadelClub/Views/Calling/CallView.swift b/PadelClub/Views/Calling/CallView.swift index 1be6236..8f8f8a7 100644 --- a/PadelClub/Views/Calling/CallView.swift +++ b/PadelClub/Views/Calling/CallView.swift @@ -199,14 +199,16 @@ struct CallView: View { let uncalledTeams = teams.filter { $0.getPhoneNumbers().isEmpty } if networkMonitor.connected == false { - if uncalledTeams.isEmpty == false { + if uncalledTeams.isEmpty == false, calledTeams.isEmpty == false { self.sentError = .uncalledTeams(uncalledTeams) } else { self.sentError = .messageNotSent } } else { - if uncalledTeams.isEmpty == false { + if uncalledTeams.isEmpty == false, calledTeams.isEmpty == false { self.sentError = .uncalledTeams(uncalledTeams) + } else if uncalledTeams.isEmpty == false, calledTeams.isEmpty { + self._called(uncalledTeams, true) } self._called(calledTeams, true) } @@ -228,14 +230,16 @@ struct CallView: View { if networkMonitor.connected == false { self.contactType = nil - if uncalledTeams.isEmpty == false { + if uncalledTeams.isEmpty == false, calledTeams.isEmpty == false { self.sentError = .uncalledTeams(uncalledTeams) } else { self.sentError = .mailNotSent } } else { - if uncalledTeams.isEmpty == false { + if uncalledTeams.isEmpty == false, calledTeams.isEmpty == false { self.sentError = .uncalledTeams(uncalledTeams) + } else if uncalledTeams.isEmpty == false, calledTeams.isEmpty { + self._called(uncalledTeams, true) } self._called(calledTeams, true) } diff --git a/PadelClub/Views/GroupStage/GroupStagesView.swift b/PadelClub/Views/GroupStage/GroupStagesView.swift index 13cd9e2..a8f9f33 100644 --- a/PadelClub/Views/GroupStage/GroupStagesView.swift +++ b/PadelClub/Views/GroupStage/GroupStagesView.swift @@ -105,6 +105,80 @@ struct GroupStagesView: View { allDestinations.append(contentsOf: groupStageDestinations) return allDestinations } + + func sortedTeams(missingQualifiedFromGroupStages: [TeamRegistration]) -> [GroupStage.TeamGroupStageScore] { + let sortedTeams = missingQualifiedFromGroupStages.compactMap({ team in + team.groupStageObject()?.computedScore(forTeam: team) + }).sorted { (lhs, rhs) in + let predicates: [GroupStage.TeamScoreAreInIncreasingOrder] = [ + { $0.wins < $1.wins }, + { $0.setDifference < $1.setDifference }, + { $0.gameDifference < $1.gameDifference}, + ] + + for predicate in predicates { + if !predicate(lhs, rhs) && !predicate(rhs, lhs) { + continue + } + + return predicate(lhs, rhs) + } + + return false + } + return sortedTeams + } + + func _sortedAdditionnalTeams(missingQualifiedFromGroupStages: [TeamRegistration]) -> some View { + Section { + let teamGroupStageScores = self.sortedTeams(missingQualifiedFromGroupStages: missingQualifiedFromGroupStages).reversed() + ForEach(teamGroupStageScores, id: \.team.id) { teamGroupStageScore in + let team = teamGroupStageScore.team + let groupStage = team.groupStageObject()! + let groupStagePosition = team.groupStagePosition! + + NavigationLink { + GroupStageTeamView(groupStage: groupStage, team: team) + .environment(self.tournament) + } label: { + HStack { + VStack(alignment: .leading) { + if let teamName = team.name, teamName.isEmpty == false { + Text(teamName).foregroundStyle(.secondary).font(.footnote) + } + ForEach(team.players()) { player in + Text(player.playerLabel()).lineLimit(1) + } + } + Spacer() + if let score = groupStage.scoreLabel(forGroupStagePosition: groupStagePosition, score: teamGroupStageScore) { + VStack(alignment: .trailing) { + HStack(spacing: 0.0) { + Text(score.wins) + Text("/") + Text(score.losses) + }.font(.headline).monospacedDigit() + if let setsDifference = score.setsDifference { + HStack(spacing: 4.0) { + Text(setsDifference) + }.font(.footnote) + } + if let gamesDifference = score.gamesDifference { + HStack(spacing: 4.0) { + Text(gamesDifference) + }.font(.footnote) + } + } + } + } + } + } + } header: { + let name = "\((tournament.qualifiedPerGroupStage + 1).ordinalFormatted())" + Text("Meilleurs \(name) de poule") + } + + } var body: some View { VStack(spacing: 0) { @@ -116,9 +190,8 @@ struct GroupStagesView: View { List { if tournament.groupStageAdditionalQualified > 0 { let missingQualifiedFromGroupStages = tournament.missingQualifiedFromGroupStages() + let name = "\((tournament.qualifiedPerGroupStage + 1).ordinalFormatted())" Section { - let name = "\((tournament.qualifiedPerGroupStage + 1).ordinalFormatted())" - NavigationLink { SpinDrawView(drawees: ["Qualification d'un \(name) de poule"], segments: missingQualifiedFromGroupStages) { results in results.forEach { drawResult in @@ -134,6 +207,8 @@ struct GroupStagesView: View { Text("Qualifier un \(name) de poule par tirage au sort") } .disabled(tournament.moreQualifiedToDraw() == 0 || missingQualifiedFromGroupStages.isEmpty) + } header: { + Text("Tirage au sort d'un \(name) de poule") } footer: { if tournament.moreQualifiedToDraw() == 0 { Text("Aucune équipe supplémentaire à qualifier. Vous pouvez en rajouter en modifier le paramètre dans structure.") @@ -141,6 +216,8 @@ struct GroupStagesView: View { Text("Aucune équipe supplémentaire à tirer au sort. Attendez la fin des poules.") } } + + _sortedAdditionnalTeams(missingQualifiedFromGroupStages: missingQualifiedFromGroupStages) } let runningMatches = Tournament.runningMatches(allMatches) diff --git a/PadelClub/Views/Tournament/Screen/TableStructureView.swift b/PadelClub/Views/Tournament/Screen/TableStructureView.swift index 4f5f95d..a06979b 100644 --- a/PadelClub/Views/Tournament/Screen/TableStructureView.swift +++ b/PadelClub/Views/Tournament/Screen/TableStructureView.swift @@ -45,7 +45,7 @@ struct TableStructureView: View { var moreQualifiedLabel: String { if groupStageAdditionalQualified == 0 { return "Aucun" } - return (groupStageAdditionalQualified > 1 ? "les \(groupStageAdditionalQualified)" : "le") + " meilleur\(groupStageAdditionalQualified.pluralSuffix) " + (qualifiedPerGroupStage + 1).ordinalFormatted() + return (groupStageAdditionalQualified > 1 ? "les \(groupStageAdditionalQualified)" : "le") + " " + (qualifiedPerGroupStage + 1).ordinalFormatted() } var maxGroupStages: Int {