diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index be6ed30..9888ad1 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -1912,7 +1912,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; @@ -1953,7 +1953,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_TEAM = BQ3Y44M3Q6; diff --git a/PadelClub/Data/Round.swift b/PadelClub/Data/Round.swift index b6e701b..c8d95be 100644 --- a/PadelClub/Data/Round.swift +++ b/PadelClub/Data/Round.swift @@ -363,7 +363,7 @@ class Round: ModelObject, Storable { } func hasNextRound() -> Bool { - return nextRound()?.isDisabled() == false + return nextRound()?.isRankDisabled() == false } func seedInterval() -> SeedInterval? { @@ -395,6 +395,20 @@ class Round: ModelObject, Storable { } return RoundRule.roundName(fromRoundIndex: index, displayStyle: displayStyle) } + + func roundTitleAndPointsRange(_ displayStyle: DisplayStyle = .wide, expanded: Bool = false, inTournament: Tournament) -> (String?, String?) { + let seedInterval = seedInterval()?.withLast(enabledMatches().count * 2 - 1) + var roundTitle : String? = nil + if parent != nil { + roundTitle = seedInterval?.localizedLabel(displayStyle) ?? "Round pas trouvé" + } else { + roundTitle = RoundRule.roundName(fromRoundIndex: index, displayStyle: displayStyle) + } + + let tournamentTeamCount = inTournament.teamCount + let pointsEarned: String? = seedInterval?.pointsRange(tournamentLevel: inTournament.tournamentLevel, teamsCount: tournamentTeamCount) + return (roundTitle, pointsEarned) + } func updateTournamentState() { if let tournamentObject = tournamentObject(), index == 0, isUpperBracket(), hasEnded() { diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index d2fac20..3841997 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -1094,22 +1094,45 @@ class Tournament : ModelObject, Storable { } let others: [Round] = rounds.flatMap { round in - round.loserRoundsAndChildren().filter { $0.isRankDisabled() == false && $0.hasNextRound() == false } + print("round", round.roundTitle()) + let rounds = round.loserRoundsAndChildren().filter { $0.isRankDisabled() == false && $0.hasNextRound() == false } + print(rounds.count, rounds.map { $0.roundTitle() }) + return rounds }.compactMap({ $0 }) others.forEach { round in + print("round", round.roundTitle()) if let interval = round.seedInterval() { + print("interval", interval.localizedLabel()) let playedMatches = round.playedMatches().filter { $0.disabled == false || $0.isReady() } + print("playedMatches", playedMatches.count) let winners = playedMatches.compactMap({ $0.winningTeamId }).filter({ ids.contains($0) == false }) + print("winners", winners.count) let losers = playedMatches.compactMap({ $0.losingTeamId }).filter({ ids.contains($0) == false }) + print("losers", losers.count) if winners.isEmpty { let disabledIds = playedMatches.flatMap({ $0.teamScores.compactMap({ $0.teamRegistration }) }).filter({ ids.contains($0) == false }) - teams[interval.last] = disabledIds + teams[interval.computedLast] = disabledIds + let teamNames : [String] = disabledIds.compactMap { + let t : TeamRegistration? = Store.main.findById($0) + return t + }.map { $0.canonicalName } + print("winners.isEmpty", "\(interval.computedLast) : ", teamNames) disabledIds.forEach { ids.insert($0) } } else { - teams[interval.first + winners.count - 1] = winners + teams[interval.computedFirst + winners.count - 1] = winners + let teamNames : [String] = winners.compactMap { + let t: TeamRegistration? = Store.main.findById($0) + return t + }.map { $0.canonicalName } + print("winners", "\(interval.computedFirst + winners.count - 1) : ", teamNames) winners.forEach { ids.insert($0) } - teams[interval.last] = losers + teams[interval.computedLast] = losers + let loserTeamNames : [String] = losers.compactMap { + let t: TeamRegistration? = Store.main.findById($0) + return t + }.map { $0.canonicalName } + print("losers", "\(interval.computedLast) : ", loserTeamNames) losers.forEach { ids.insert($0) } } } diff --git a/PadelClub/ViewModel/SeedInterval.swift b/PadelClub/ViewModel/SeedInterval.swift index 93e778e..e44455e 100644 --- a/PadelClub/ViewModel/SeedInterval.swift +++ b/PadelClub/ViewModel/SeedInterval.swift @@ -26,6 +26,14 @@ struct SeedInterval: Hashable, Comparable { first == 1 && last == 2 } + func reducedBy(_ count: Int, firstAlso: Bool = false) -> SeedInterval { + return SeedInterval(first: first - (firstAlso ? count : 0), last: last - count, reduce: reduce) + } + + func withLast(_ lastValue: Int) -> SeedInterval { + return SeedInterval(first: first, last: first + lastValue, reduce: reduce) + } + var count: Int { dimension } @@ -44,7 +52,26 @@ struct SeedInterval: Hashable, Comparable { return nil } } + + func chunksOrSelf() -> [SeedInterval] { + if dimension > 3 { + let split = dimension / 2 + let firstHalf = SeedInterval(first: first, last: first + split - 1, reduce: reduce) + let secondHalf = SeedInterval(first: first + split, last: last, reduce: reduce) + return [firstHalf, secondHalf] + } else { + return [self] + } + } + var computedLast: Int { + last - reduce + } + + var computedFirst: Int { + first - reduce + } + func localizedLabel(_ displayStyle: DisplayStyle = .wide) -> String { if dimension < 2 { return "#\(first - reduce) / #\(last - reduce)" diff --git a/PadelClub/Views/Calling/CallView.swift b/PadelClub/Views/Calling/CallView.swift index 8df33dc..6aae0fd 100644 --- a/PadelClub/Views/Calling/CallView.swift +++ b/PadelClub/Views/Calling/CallView.swift @@ -229,11 +229,12 @@ struct CallView: View { } fileprivate func _verifyUser(_ handler: () -> ()) { - if Store.main.userId != nil { - handler() - } else { - self.showUserCreationView = true - } + handler() +// if Store.main.userId != nil { +// handler() +// } else { +// self.showUserCreationView = true +// } } fileprivate func _payTournamentAndExecute(_ handler: () -> ()) { diff --git a/PadelClub/Views/Calling/Components/MenuWarningView.swift b/PadelClub/Views/Calling/Components/MenuWarningView.swift index fb16e2a..0f7376a 100644 --- a/PadelClub/Views/Calling/Components/MenuWarningView.swift +++ b/PadelClub/Views/Calling/Components/MenuWarningView.swift @@ -142,11 +142,12 @@ struct MenuWarningView: View { } fileprivate func _verifyUser(_ handler: () -> ()) { - if Store.main.userId != nil { - handler() - } else { - self.showUserCreationView = true - } + handler() +// if Store.main.userId != nil { +// handler() +// } else { +// self.showUserCreationView = true +// } } fileprivate func _payTournamentAndExecute(_ handler: () -> ()) { diff --git a/PadelClub/Views/Calling/SendToAllView.swift b/PadelClub/Views/Calling/SendToAllView.swift index f35a6bb..2ee2938 100644 --- a/PadelClub/Views/Calling/SendToAllView.swift +++ b/PadelClub/Views/Calling/SendToAllView.swift @@ -229,11 +229,12 @@ struct SendToAllView: View { } fileprivate func _verifyUser(_ handler: () -> ()) { - if Store.main.userId != nil { - handler() - } else { - self.showUserCreationView = true - } + handler() +// if Store.main.userId != nil { +// handler() +// } else { +// self.showUserCreationView = true +// } } fileprivate func _payTournamentAndExecute(_ handler: () -> ()) { diff --git a/PadelClub/Views/Match/Components/MatchDateView.swift b/PadelClub/Views/Match/Components/MatchDateView.swift index 653c5b6..9324f15 100644 --- a/PadelClub/Views/Match/Components/MatchDateView.swift +++ b/PadelClub/Views/Match/Components/MatchDateView.swift @@ -26,6 +26,22 @@ struct MatchDateView: View { var body: some View { Menu { + Button("Ne pas jouer ce match") { + match._toggleMatchDisableState(true) + } + Button("Jouer ce match") { + match._toggleMatchDisableState(false) + } + + Button("Créer les scores") { + let teamsScores = match.getOrCreateTeamScores() + do { + try dataStore.teamScores.addOrUpdate(contentOfs: teamsScores) + } catch { + Logger.error(error) + } + } + let estimatedDuration = match.getDuration() if match.startDate == nil && isReady { Button("Démarrer") { diff --git a/PadelClub/Views/Match/MatchDetailView.swift b/PadelClub/Views/Match/MatchDetailView.swift index 1107f1b..91a4b7a 100644 --- a/PadelClub/Views/Match/MatchDetailView.swift +++ b/PadelClub/Views/Match/MatchDetailView.swift @@ -442,11 +442,12 @@ struct MatchDetailView: View { } fileprivate func _verifyUser(_ handler: () -> ()) { - if Store.main.userId != nil { - handler() - } else { - self.showUserCreationView = true - } + handler() +// if Store.main.userId != nil { +// handler() +// } else { +// self.showUserCreationView = true +// } } fileprivate func _payTournamentAndExecute(_ handler: () -> ()) { diff --git a/PadelClub/Views/Round/LoserRoundView.swift b/PadelClub/Views/Round/LoserRoundView.swift index ceb9efa..d58dc52 100644 --- a/PadelClub/Views/Round/LoserRoundView.swift +++ b/PadelClub/Views/Round/LoserRoundView.swift @@ -23,35 +23,53 @@ struct LoserRoundView: View { if isEditingTournamentSeed == true { _editingView() } + let shouldDisplayLoserRounds = loserRounds.filter({ + let matches = $0.playedMatches().filter { isEditingTournamentSeed == true || (isEditingTournamentSeed == false && $0.disabled == false) } + return matches.isEmpty == false + }).isEmpty == false - ForEach(loserRounds) { loserRound in - if true { - Section { - let matches = loserRound.playedMatches().sorted(by: \.index) - ForEach(matches) { match in - MatchRowView(match: match, matchViewStyle: .sectionedStandardStyle) - .overlay { - if match.disabled /*&& isEditingTournamentSeed*/ { - Image(systemName: "xmark") - .resizable() - .scaledToFit() - .opacity(0.8) + if shouldDisplayLoserRounds { + ForEach(loserRounds) { loserRound in + let matches = loserRound.playedMatches().filter { isEditingTournamentSeed == true || (isEditingTournamentSeed == false && $0.disabled == false) }.sorted(by: \.index) + if matches.isEmpty == false { + Section { + ForEach(matches) { match in + MatchRowView(match: match, matchViewStyle: .sectionedStandardStyle) + .overlay { + if match.disabled && isEditingTournamentSeed { + Image(systemName: "xmark") + .resizable() + .scaledToFit() + .opacity(0.8) + } + } + .disabled(match.disabled) + + if isEditingTournamentSeed { + RowButtonView(match.disabled ? "Jouer ce match" : "Ne pas jouer ce match", role: .destructive) { + match._toggleMatchDisableState(!match.disabled) } } - .disabled(match.disabled) - } - } header: { - HStack { - Text(loserRound.roundTitle(.wide)) - let tournamentTeamCount = tournament.teamCount - if let seedIntervalPointRange = loserRound.seedInterval()?.pointsRange(tournamentLevel: tournament.tournamentLevel, teamsCount: tournamentTeamCount) { - Spacer() - Text(seedIntervalPointRange) - .font(.caption) + } + } header: { + HStack { + let labels = loserRound.roundTitleAndPointsRange(.wide, expanded: isEditingTournamentSeed, inTournament: tournament) + if let seedIntervalLocalizedLabel = labels.0 { + Text(seedIntervalLocalizedLabel) + } + if let seedIntervalPointRange = labels.1 { + Spacer() + Text(seedIntervalPointRange) + .font(.caption) + } } } } } + } else { + Section { + ContentUnavailableView("Aucun match joué", systemImage: "tennisball", description: Text("Il n'y aucun match à jouer dans ce tour de match de classement.")) + } } } .headerProminence(.increased)