From 8a5db5921a7a20cb2a963fdea5c350d76c61adbf Mon Sep 17 00:00:00 2001 From: Raz Date: Tue, 11 Feb 2025 18:22:32 +0100 Subject: [PATCH] v1.1.9 --- PadelClub.xcodeproj/project.pbxproj | 4 +- .../Federal/FederalTournamentHolder.swift | 6 +- PadelClub/Data/TeamRegistration.swift | 5 +- PadelClub/Data/Tournament.swift | 28 ++++++--- .../HTML Templates/bracket-template.html | 5 +- .../HTML Templates/groupstage-template.html | 1 + PadelClub/HTML Templates/player-template.html | 1 + .../HTML Templates/tournament-template.html | 7 ++- PadelClub/Utils/HtmlGenerator.swift | 7 ++- PadelClub/Utils/HtmlService.swift | 62 ++++++++++++------- .../Views/Calling/CallSettingsView.swift | 2 + .../Views/Calling/GroupStageCallingView.swift | 19 +++++- .../Views/Calling/SeedsCallingView.swift | 18 ++++++ .../Views/Calling/TeamsCallingView.swift | 18 ++++++ .../Navigation/Agenda/EventListView.swift | 40 ++++++++++++ .../TournamentGeneralSettingsView.swift | 3 +- .../Tournament/Screen/PrintSettingsView.swift | 60 +++++++++++------- 17 files changed, 218 insertions(+), 68 deletions(-) diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index dd34dcc..e9ed9ba 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -3329,7 +3329,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.8; + MARKETING_VERSION = 1.1.9; PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -3376,7 +3376,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.8; + MARKETING_VERSION = 1.1.9; PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/PadelClub/Data/Federal/FederalTournamentHolder.swift b/PadelClub/Data/Federal/FederalTournamentHolder.swift index 4ee6bd6..1e5de69 100644 --- a/PadelClub/Data/Federal/FederalTournamentHolder.swift +++ b/PadelClub/Data/Federal/FederalTournamentHolder.swift @@ -19,10 +19,14 @@ protocol FederalTournamentHolder { var dayPeriod: DayPeriod { get } func tournamentTitle(_ displayStyle: DisplayStyle, forBuild build: any TournamentBuildHolder) -> String func displayAgeAndCategory(forBuild build: any TournamentBuildHolder) -> Bool + func togglePrivate(isPrivate: Bool) } extension FederalTournamentHolder { - + func togglePrivate(isPrivate: Bool) { + + } + func durationLabel() -> String { switch dayDuration { case 1: diff --git a/PadelClub/Data/TeamRegistration.swift b/PadelClub/Data/TeamRegistration.swift index 457b6e7..cc7dd6d 100644 --- a/PadelClub/Data/TeamRegistration.swift +++ b/PadelClub/Data/TeamRegistration.swift @@ -271,8 +271,9 @@ final class TeamRegistration: ModelObject, Storable { return teams.firstIndex(where: { $0.id == id }) } - func formattedSeed(in teams: [TeamRegistration]) -> String { - if let index = index(in: teams) { + func formattedSeed(in teams: [TeamRegistration]? = nil) -> String { + let selectedSortedTeams = teams ?? tournamentObject()?.selectedSortedTeams() ?? [] + if let index = index(in: selectedSortedTeams) { return "#\(index + 1)" } else { return "###" diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index 1869399..531e749 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -132,7 +132,7 @@ final class Tournament : ModelObject, Storable { } - internal init(event: String? = nil, name: String? = nil, startDate: Date = Date(), endDate: Date? = nil, creationDate: Date = Date(), isPrivate: Bool = false, groupStageFormat: MatchFormat? = nil, roundFormat: MatchFormat? = nil, loserRoundFormat: MatchFormat? = nil, groupStageSortMode: GroupStageOrderingMode, groupStageCount: Int = 4, rankSourceDate: Date? = nil, dayDuration: Int = 1, teamCount: Int = 24, teamSorting: TeamSortingType? = nil, federalCategory: TournamentCategory, federalLevelCategory: TournamentLevel, federalAgeCategory: FederalTournamentAge, closedRegistrationDate: Date? = nil, groupStageAdditionalQualified: Int = 0, courtCount: Int = 2, prioritizeClubMembers: Bool = false, qualifiedPerGroupStage: Int = 1, teamsPerGroupStage: Int = 4, entryFee: Double? = nil, additionalEstimationDuration: Int = 0, isDeleted: Bool = false, publishTeams: Bool = false, publishSummons: Bool = false, publishGroupStages: Bool = false, publishBrackets: Bool = false, shouldVerifyBracket: Bool = false, shouldVerifyGroupStage: Bool = false, hideTeamsWeight: Bool = false, publishTournament: Bool = false, hidePointsEarned: Bool = false, publishRankings: Bool = false, loserBracketMode: LoserBracketMode = .automatic, initialSeedRound: Int = 0, initialSeedCount: Int = 0, enableOnlineRegistration: Bool = false, registrationDateLimit: Date? = nil, openingRegistrationDate: Date? = nil, waitingListLimit: Int? = nil, accountIsRequired: Bool = true, licenseIsRequired: Bool = true, minimumPlayerPerTeam: Int = 2, maximumPlayerPerTeam: Int = 2, information: String? = nil) { + internal init(event: String? = nil, name: String? = nil, startDate: Date = Date(), endDate: Date? = nil, creationDate: Date = Date(), isPrivate: Bool = true, groupStageFormat: MatchFormat? = nil, roundFormat: MatchFormat? = nil, loserRoundFormat: MatchFormat? = nil, groupStageSortMode: GroupStageOrderingMode, groupStageCount: Int = 4, rankSourceDate: Date? = nil, dayDuration: Int = 1, teamCount: Int = 24, teamSorting: TeamSortingType? = nil, federalCategory: TournamentCategory, federalLevelCategory: TournamentLevel, federalAgeCategory: FederalTournamentAge, closedRegistrationDate: Date? = nil, groupStageAdditionalQualified: Int = 0, courtCount: Int = 2, prioritizeClubMembers: Bool = false, qualifiedPerGroupStage: Int = 1, teamsPerGroupStage: Int = 4, entryFee: Double? = nil, additionalEstimationDuration: Int = 0, isDeleted: Bool = false, publishTeams: Bool = false, publishSummons: Bool = false, publishGroupStages: Bool = false, publishBrackets: Bool = false, shouldVerifyBracket: Bool = false, shouldVerifyGroupStage: Bool = false, hideTeamsWeight: Bool = false, publishTournament: Bool = false, hidePointsEarned: Bool = false, publishRankings: Bool = false, loserBracketMode: LoserBracketMode = .automatic, initialSeedRound: Int = 0, initialSeedCount: Int = 0, enableOnlineRegistration: Bool = false, registrationDateLimit: Date? = nil, openingRegistrationDate: Date? = nil, waitingListLimit: Int? = nil, accountIsRequired: Bool = true, licenseIsRequired: Bool = true, minimumPlayerPerTeam: Int = 2, maximumPlayerPerTeam: Int = 2, information: String? = nil) { self.event = event self.name = name self.startDate = startDate @@ -141,11 +141,7 @@ final class Tournament : ModelObject, Storable { #if DEBUG self.isPrivate = false #else - if Guard.main.currentPlan == .monthlyUnlimited { - self.isPrivate = true - } else { - self.isPrivate = Guard.main.purchasedTransactions.isEmpty - } + self.isPrivate = isPrivate #endif self.groupStageFormat = groupStageFormat self.roundFormat = roundFormat @@ -1218,7 +1214,7 @@ defer { // return Store.main.filter(isIncluded: { $0.groupStage != nil && groupStageIds.contains($0.groupStage!) }) } - static let defaultSorting : [MySortDescriptor] = [.keyPath(\Match.computedStartDateForSorting), .keyPath(\Match.index)] + static let defaultSorting : [MySortDescriptor] = [.keyPath(\Match.computedStartDateForSorting), .keyPath(\Match.computedOrder)] static func availableToStart(_ allMatches: [Match], in runningMatches: [Match], checkCanPlay: Bool = true) -> [Match] { #if _DEBUG_TIME //DEBUGING TIME @@ -2684,7 +2680,10 @@ extension Tournament: Hashable { } extension Tournament: FederalTournamentHolder { - + func togglePrivate(isPrivate: Bool) { + self.isPrivate = isPrivate + } + func tournamentTitle(_ displayStyle: DisplayStyle, forBuild build: any TournamentBuildHolder) -> String { if isAnimation() { if let name { @@ -2779,12 +2778,21 @@ extension Tournament { } let rankSourceDate = _mostRecentDateAvailable - let tournaments : [Tournament] = DataStore.shared.tournaments.filter { $0.endDate != nil && $0.isDeleted == false } + let tournaments : [Tournament] = DataStore.shared.tournaments.filter { $0.endDate != nil && $0.isDeleted == false }.sorted(by: \.endDate!, order: .descending) + + var shouldBePrivate = tournaments.first?.isPrivate ?? true + + if Guard.main.currentPlan == .monthlyUnlimited { + shouldBePrivate = false + } else if Guard.main.purchasedTransactions.isEmpty == false { + shouldBePrivate = false + } + let tournamentLevel = TournamentLevel.mostUsed(inTournaments: tournaments) let tournamentCategory = TournamentCategory.mostUsed(inTournaments: tournaments) let federalTournamentAge = FederalTournamentAge.mostUsed(inTournaments: tournaments) //creator: DataStore.shared.user?.id - return Tournament(groupStageSortMode: .snake, rankSourceDate: rankSourceDate, teamSorting: tournamentLevel.defaultTeamSortingType, federalCategory: tournamentCategory, federalLevelCategory: tournamentLevel, federalAgeCategory: federalTournamentAge, loserBracketMode: DataStore.shared.user.loserBracketMode) + return Tournament(isPrivate: shouldBePrivate, groupStageSortMode: .snake, rankSourceDate: rankSourceDate, teamSorting: tournamentLevel.defaultTeamSortingType, federalCategory: tournamentCategory, federalLevelCategory: tournamentLevel, federalAgeCategory: federalTournamentAge, loserBracketMode: DataStore.shared.user.loserBracketMode) } static func fake() -> Tournament { diff --git a/PadelClub/HTML Templates/bracket-template.html b/PadelClub/HTML Templates/bracket-template.html index c344123..8c3ec91 100644 --- a/PadelClub/HTML Templates/bracket-template.html +++ b/PadelClub/HTML Templates/bracket-template.html @@ -1,4 +1,7 @@
    -
  •  {{roundLabel}}
  • +
  • +  {{roundLabel}} +
    {{formatLabel}}
    +
  • {{match-template}}
diff --git a/PadelClub/HTML Templates/groupstage-template.html b/PadelClub/HTML Templates/groupstage-template.html index 6e203b9..32de623 100644 --- a/PadelClub/HTML Templates/groupstage-template.html +++ b/PadelClub/HTML Templates/groupstage-template.html @@ -82,6 +82,7 @@ body{

{{bracketTitle}}

{{bracketStartDate}}

+

{{formatLabel}}

diff --git a/PadelClub/HTML Templates/player-template.html b/PadelClub/HTML Templates/player-template.html index 38579d9..56c92dc 100644 --- a/PadelClub/HTML Templates/player-template.html +++ b/PadelClub/HTML Templates/player-template.html @@ -1,3 +1,4 @@ +
{{teamIndex}}
{{playerOne}}{{weightOne}}
{{playerTwo}}{{weightTwo}}
diff --git a/PadelClub/HTML Templates/tournament-template.html b/PadelClub/HTML Templates/tournament-template.html index 1d6f1b9..e98ebf0 100644 --- a/PadelClub/HTML Templates/tournament-template.html +++ b/PadelClub/HTML Templates/tournament-template.html @@ -9,6 +9,7 @@ flex-direction:row; padding: 1%; } + .round{ display:flex; flex-direction:column; @@ -27,7 +28,7 @@ .round .spacer{ flex-grow:1; font-size:24px; text-align: center; - color: #bbb; + color: #000000; font-style:italic; } .round .spacer:first-child, @@ -65,7 +66,7 @@ li.game-spacer{ border-right:2px solid #4f7a38; - min-height:156px; + min-height:{{minHeight}}px; text-align: right; display : flex; justify-content: center; @@ -95,7 +96,7 @@ -

{{tournamentTitle}}

+

{{tournamentTitle}} - {{tournamentStartDate}}

{{brackets}}
diff --git a/PadelClub/Utils/HtmlGenerator.swift b/PadelClub/Utils/HtmlGenerator.swift index 4139f67..09d5ab1 100644 --- a/PadelClub/Utils/HtmlGenerator.swift +++ b/PadelClub/Utils/HtmlGenerator.swift @@ -24,6 +24,9 @@ class HtmlGenerator: ObservableObject { @Published var displayHeads: Bool = false @Published var groupStageIsReady: Bool = false @Published var displayRank: Bool = false + @Published var displayTeamIndex: Bool = false + @Published var displayScore: Bool = false + private var pdfDocument: PDFDocument = PDFDocument() private var rects: [CGRect] = [] private var completionHandler: ((Result) -> ())? @@ -167,12 +170,12 @@ class HtmlGenerator: ObservableObject { func generateHtml() -> String { //HtmlService.groupstage(bracket: tournament.orderedBrackets.first!).html() - HtmlService.template(tournament: tournament).html(headName: displayHeads, withRank: displayRank, withScore: false) + HtmlService.template(tournament: tournament).html(headName: displayHeads, withRank: displayRank, withTeamIndex: displayTeamIndex, withScore: displayScore) } func generateLoserBracketHtml(upperRound: Round) -> String { //HtmlService.groupstage(bracket: tournament.orderedBrackets.first!).html() - HtmlService.loserBracket(upperRound: upperRound).html(headName: displayHeads, withRank: displayRank, withScore: false) + HtmlService.loserBracket(upperRound: upperRound).html(headName: displayHeads, withRank: displayRank, withTeamIndex: displayTeamIndex, withScore: displayScore) } var pdfURL: URL? { diff --git a/PadelClub/Utils/HtmlService.swift b/PadelClub/Utils/HtmlService.swift index 33145b5..3ebd892 100644 --- a/PadelClub/Utils/HtmlService.swift +++ b/PadelClub/Utils/HtmlService.swift @@ -50,7 +50,7 @@ enum HtmlService { } } - func html(headName: Bool, withRank: Bool, withScore: Bool) -> String { + func html(headName: Bool, withRank: Bool, withTeamIndex: Bool, withScore: Bool) -> String { guard let file = Bundle.main.path(forResource: self.fileName, ofType: "html") else { fatalError() } @@ -69,12 +69,12 @@ enum HtmlService { } template = template.replacingOccurrences(of: "{{tournamentTitle}}", with: bracket.tournamentObject()!.tournamentTitle(.short)) template = template.replacingOccurrences(of: "{{bracketTitle}}", with: bracket.groupStageTitle()) - + template = template.replacingOccurrences(of: "{{formatLabel}}", with: bracket.matchFormat.formatTitle()) var col = "" var row = "" bracket.teams().forEach { entrant in - col = col.appending(HtmlService.groupstageColumn(entrant: entrant, position: "col").html(headName: headName, withRank: withRank, withScore: withScore)) - row = row.appending(HtmlService.groupstageRow(entrant: entrant, teamsPerBracket: bracket.size).html(headName: headName, withRank: withRank, withScore: withScore)) + col = col.appending(HtmlService.groupstageColumn(entrant: entrant, position: "col").html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore)) + row = row.appending(HtmlService.groupstageRow(entrant: entrant, teamsPerBracket: bracket.size).html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore)) } template = template.replacingOccurrences(of: "{{teamsCol}}", with: col) template = template.replacingOccurrences(of: "{{teamsRow}}", with: row) @@ -82,6 +82,12 @@ enum HtmlService { return template case .groupstageEntrant(let entrant): var template = html + if withTeamIndex == false { + template = template.replacingOccurrences(of: #"
{{teamIndex}}
"#, with: "") + } else { + template = template.replacingOccurrences(of: "{{teamIndex}}", with: entrant.seedIndex() ?? "") + } + if let playerOne = entrant.players()[safe: 0] { template = template.replacingOccurrences(of: "{{playerOne}}", with: playerOne.playerLabel()) if withRank { @@ -108,7 +114,7 @@ enum HtmlService { return template case .groupstageRow(let entrant, let teamsPerBracket): var template = html - template = template.replacingOccurrences(of: "{{team}}", with: HtmlService.groupstageColumn(entrant: entrant, position: "row").html(headName: headName, withRank: withRank, withScore: withScore)) + template = template.replacingOccurrences(of: "{{team}}", with: HtmlService.groupstageColumn(entrant: entrant, position: "row").html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore)) var scores = "" (0..{{teamIndex}}"#, with: "") + } else { + template = template.replacingOccurrences(of: "{{teamIndex}}", with: entrant.formattedSeed()) + } + + if let playerOne = entrant.players()[safe: 0] { template = template.replacingOccurrences(of: "{{playerOne}}", with: playerOne.playerLabel()) if withRank { @@ -164,18 +177,22 @@ enum HtmlService { } return template case .hiddenPlayer: - return html + html + var template = html + html + if withTeamIndex { + template += html + } + return template case .match(let match): var template = html if let entrantOne = match.team(.one) { - template = template.replacingOccurrences(of: "{{entrantOne}}", with: HtmlService.player(entrant: entrantOne).html(headName: headName, withRank: withRank, withScore: withScore)) + template = template.replacingOccurrences(of: "{{entrantOne}}", with: HtmlService.player(entrant: entrantOne).html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore)) } else { - template = template.replacingOccurrences(of: "{{entrantOne}}", with: HtmlService.hiddenPlayer.html(headName: headName, withRank: withRank, withScore: withScore)) + template = template.replacingOccurrences(of: "{{entrantOne}}", with: HtmlService.hiddenPlayer.html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore)) } if let entrantTwo = match.team(.two) { - template = template.replacingOccurrences(of: "{{entrantTwo}}", with: HtmlService.player(entrant: entrantTwo).html(headName: headName, withRank: withRank, withScore: withScore)) + template = template.replacingOccurrences(of: "{{entrantTwo}}", with: HtmlService.player(entrant: entrantTwo).html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore)) } else { - template = template.replacingOccurrences(of: "{{entrantTwo}}", with: HtmlService.hiddenPlayer.html(headName: headName, withRank: withRank, withScore: withScore)) + template = template.replacingOccurrences(of: "{{entrantTwo}}", with: HtmlService.hiddenPlayer.html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore)) } if match.disabled { template = template.replacingOccurrences(of: "{{hidden}}", with: "hidden") @@ -196,19 +213,20 @@ enum HtmlService { var template = "" var bracket = "" for (_, match) in round._matches().enumerated() { - template = template.appending(HtmlService.match(match: match).html(headName: headName, withRank: withRank, withScore: withScore)) + template = template.appending(HtmlService.match(match: match).html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore)) } bracket = html.replacingOccurrences(of: "{{match-template}}", with: template) bracket = bracket.replacingOccurrences(of: "{{roundLabel}}", with: round.roundTitle()) + bracket = bracket.replacingOccurrences(of: "{{formatLabel}}", with: round.matchFormat.formatTitle()) return bracket case .loserBracket(let upperRound): var template = html template = template.replacingOccurrences(of: "{{tournamentTitle}}", with: upperRound.correspondingLoserRoundTitle()) var brackets = "" for round in upperRound.loserRounds() { - brackets = brackets.appending(HtmlService.bracket(round: round).html(headName: headName, withRank: withRank, withScore: withScore)) + brackets = brackets.appending(HtmlService.bracket(round: round).html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore)) } - var winnerName = "" + let winnerName = "" let winner = """
  •  
  • @@ -224,15 +242,17 @@ enum HtmlService { return template case .template(let tournament): var template = html - template = template.replacingOccurrences(of: "{{tournamentTitle}}", with: tournament.tournamentTitle(.short)) + template = template.replacingOccurrences(of: "{{minHeight}}", with: withTeamIndex ? "226" : "156") + template = template.replacingOccurrences(of: "{{tournamentTitle}}", with: tournament.tournamentTitle(.title)) + template = template.replacingOccurrences(of: "{{tournamentStartDate}}", with: tournament.formattedDate()) var brackets = "" for round in tournament.rounds() { - brackets = brackets.appending(HtmlService.bracket(round: round).html(headName: headName, withRank: withRank, withScore: withScore)) + brackets = brackets.appending(HtmlService.bracket(round: round).html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore)) } var winnerName = "" if let tournamentWinner = tournament.tournamentWinner() { - winnerName = HtmlService.player(entrant: tournamentWinner).html(headName: headName, withRank: withRank, withScore: withScore) + winnerName = HtmlService.player(entrant: tournamentWinner).html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore) } let winner = """
      diff --git a/PadelClub/Views/Calling/CallSettingsView.swift b/PadelClub/Views/Calling/CallSettingsView.swift index 7834e0e..54fbcb6 100644 --- a/PadelClub/Views/Calling/CallSettingsView.swift +++ b/PadelClub/Views/Calling/CallSettingsView.swift @@ -22,6 +22,8 @@ struct CallSettingsView: View { var body: some View { List { + + Section { NavigationLink { CallMessageCustomizationView(tournament: tournament) diff --git a/PadelClub/Views/Calling/GroupStageCallingView.swift b/PadelClub/Views/Calling/GroupStageCallingView.swift index cb12cd4..020d603 100644 --- a/PadelClub/Views/Calling/GroupStageCallingView.swift +++ b/PadelClub/Views/Calling/GroupStageCallingView.swift @@ -6,15 +6,32 @@ // import SwiftUI +import LeStorage struct GroupStageCallingView: View { @Environment(Tournament.self) var tournament: Tournament + @EnvironmentObject var dataStore: DataStore @State private var displayByTeam: Bool = false var body: some View { let groupStages = tournament.groupStages() List { - + if tournament.isPrivate { + Section { + RowButtonView("Rendre visible sur Padel Club") { + tournament.isPrivate = false + do { + try dataStore.tournaments.addOrUpdate(instance: tournament) + } catch { + Logger.error(error) + } + } + } footer: { + Text("Si vous convoquez un tournoi privée, les joueurs n'auront pas le lien pour suivre le tournoi.") + .foregroundStyle(.logoRed) + } + } + let uncalled = groupStages.flatMap({ $0.unsortedTeams() }).filter({ $0.callDate == nil }) if uncalled.isEmpty == false { NavigationLink { diff --git a/PadelClub/Views/Calling/SeedsCallingView.swift b/PadelClub/Views/Calling/SeedsCallingView.swift index c1b899e..d13f4b3 100644 --- a/PadelClub/Views/Calling/SeedsCallingView.swift +++ b/PadelClub/Views/Calling/SeedsCallingView.swift @@ -6,13 +6,31 @@ // import SwiftUI +import LeStorage struct SeedsCallingView: View { + @EnvironmentObject var dataStore: DataStore @Environment(Tournament.self) var tournament: Tournament @State private var displayByMatch: Bool = true var body: some View { List { + if tournament.isPrivate { + Section { + RowButtonView("Rendre visible sur Padel Club") { + tournament.isPrivate = false + do { + try dataStore.tournaments.addOrUpdate(instance: tournament) + } catch { + Logger.error(error) + } + } + } footer: { + Text("Si vous convoquez un tournoi privée, les joueurs n'auront pas le lien pour suivre le tournoi.") + .foregroundStyle(.logoRed) + } + } + let tournamentRounds = tournament.rounds() let uncalledSeeds = tournament.seededTeams().filter({ $0.callDate == nil }) diff --git a/PadelClub/Views/Calling/TeamsCallingView.swift b/PadelClub/Views/Calling/TeamsCallingView.swift index 8a5d1e9..b2473a9 100644 --- a/PadelClub/Views/Calling/TeamsCallingView.swift +++ b/PadelClub/Views/Calling/TeamsCallingView.swift @@ -10,6 +10,7 @@ import LeStorage struct TeamsCallingView: View { @Environment(Tournament.self) var tournament: Tournament + @EnvironmentObject var dataStore: DataStore let teams : [TeamRegistration] @State private var hideConfirmed: Bool = false @@ -31,6 +32,23 @@ struct TeamsCallingView: View { var body: some View { List { + if tournament.isPrivate { + Section { + RowButtonView("Rendre visible sur Padel Club") { + tournament.isPrivate = false + do { + try dataStore.tournaments.addOrUpdate(instance: tournament) + } catch { + Logger.error(error) + } + } + } footer: { + Text("Si vous convoquez un tournoi privée, les joueurs n'auront pas le lien pour suivre le tournoi.") + .foregroundStyle(.logoRed) + } + } + + PlayersWithoutContactView(players: teams.flatMap({ $0.unsortedPlayers() }).sorted(by: \.computedRank)) let called = teams.filter { tournament.isStartDateIsDifferentThanCallDate($0) == false } diff --git a/PadelClub/Views/Navigation/Agenda/EventListView.swift b/PadelClub/Views/Navigation/Agenda/EventListView.swift index cd20e93..f9a7e2d 100644 --- a/PadelClub/Views/Navigation/Agenda/EventListView.swift +++ b/PadelClub/Views/Navigation/Agenda/EventListView.swift @@ -36,6 +36,10 @@ struct EventListView: View { let count = federalDataViewModel.countForTournamentBuilds(from: _tournaments) Text("\(count.formatted()) tournoi" + count.pluralSuffix) } + } footer: { + if _tournaments.isEmpty == false, let pcTournaments = _tournaments as? [Tournament] { + _menuOptions(pcTournaments) + } } .headerProminence(.increased) } @@ -54,6 +58,10 @@ struct EventListView: View { let count = federalDataViewModel.countForTournamentBuilds(from: _tournaments) Text("\(count.formatted()) tournoi" + count.pluralSuffix) } + } footer: { + if _tournaments.isEmpty == false, let pcTournaments = _tournaments as? [Tournament] { + _menuOptions(pcTournaments) + } } .id(sectionIndex) .headerProminence(.increased) @@ -82,6 +90,38 @@ struct EventListView: View { } } + private func _menuOptions(_ pcTournaments: [Tournament]) -> some View { + Menu { + Button { + pcTournaments.forEach { tournament in + tournament.togglePrivate(isPrivate: false) + } + do { + try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments) + } catch { + Logger.error(error) + } + } label: { + Text("Les afficher tous sur Padel Club") + } + Button { + pcTournaments.forEach { tournament in + tournament.togglePrivate(isPrivate: true) + } + do { + try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments) + } catch { + Logger.error(error) + } + } label: { + Text("Les masquer tous sur Padel Club") + } + + } label: { + Text("Options") + } + } + private func _nextMonths() -> [Date] { let currentDate = Date().startOfMonth let uniqueDates = tournaments.map { $0.startDate.startOfMonth }.uniqued().sorted() diff --git a/PadelClub/Views/Tournament/Screen/Components/TournamentGeneralSettingsView.swift b/PadelClub/Views/Tournament/Screen/Components/TournamentGeneralSettingsView.swift index 803dbc5..f2c65e8 100644 --- a/PadelClub/Views/Tournament/Screen/Components/TournamentGeneralSettingsView.swift +++ b/PadelClub/Views/Tournament/Screen/Components/TournamentGeneralSettingsView.swift @@ -93,8 +93,9 @@ struct TournamentGeneralSettingsView: View { } .frame(maxHeight: 200) .overlay { - if tournamentInformation.isEmpty { + if tournamentInformation.isEmpty, focusedField != ._information { Text("Texte visible dans l'onglet informations sur Padel Club.").italic() + .foregroundStyle(.secondary) } } } header: { diff --git a/PadelClub/Views/Tournament/Screen/PrintSettingsView.swift b/PadelClub/Views/Tournament/Screen/PrintSettingsView.swift index a8cc7d3..f9206bf 100644 --- a/PadelClub/Views/Tournament/Screen/PrintSettingsView.swift +++ b/PadelClub/Views/Tournament/Screen/PrintSettingsView.swift @@ -28,10 +28,20 @@ struct PrintSettingsView: View { // Toggle(isOn: $generator.displayHeads, label: { // Text("Afficher les têtes de séries") // }) + + Toggle(isOn: $generator.displayTeamIndex, label: { + Text("Afficher le poids et le rang de l'équipe") + }) + Toggle(isOn: $generator.displayRank, label: { Text("Afficher le classement du joueur") }) - + + Toggle(isOn: $generator.displayScore, label: { + Text("Afficher le score") + Text("Affiche le score des matchs terminés") + }) + Toggle(isOn: $generator.includeBracket, label: { Text("Tableau") }) @@ -152,32 +162,34 @@ struct PrintSettingsView: View { .navigationTitle("Imprimer") .toolbarBackground(.visible, for: .navigationBar) .navigationBarTitleDisplayMode(.inline) -// .toolbar { -// ToolbarItem(placement: .topBarTrailing) { -// Menu { -// Section { -// ShareLink(item: generator.generateHtml()) { -// Text("Tableau") -// } -// -// if let groupStage = tournament.groupStages().first { -// ShareLink(item: HtmlService.groupstage(groupStage: groupStage).html(headName: generator.displayHeads, withRank: generator.displayRank, withScore: false)) { -// Text("Poule") -// } -// } -// } header: { -// Text("Partager le code source HTML") -// } -// } label: { -// Label("Options", systemImage: "ellipsis.circle") -// } -// } -// } .sheet(isPresented: $presentShareView) { if let pdfURL = generator.pdfURL { ShareSheet(urls: [pdfURL]) } } + #if DEBUG + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + Menu { + Section { + ShareLink(item: generator.generateHtml()) { + Text("Tableau") + } + + if let groupStage = tournament.groupStages().first { + ShareLink(item: HtmlService.groupstage(groupStage: groupStage).html(headName: generator.displayHeads, withRank: generator.displayRank, withTeamIndex: generator.displayTeamIndex, withScore: generator.displayScore)) { + Text("Poule") + } + } + } header: { + Text("Partager le code source HTML") + } + } label: { + Label("Options", systemImage: "ellipsis.circle") + } + } + } + #endif } @ViewBuilder @@ -199,7 +211,7 @@ struct PrintSettingsView: View { Group { if prepareGroupStage { ForEach(tournament.groupStages()) { groupStage in - WebView(htmlRawData: HtmlService.groupstage(groupStage: groupStage).html(headName: generator.displayHeads, withRank: generator.displayRank, withScore: false), loadStatusChanged: { loaded, error, webView in + WebView(htmlRawData: HtmlService.groupstage(groupStage: groupStage).html(headName: generator.displayHeads, withRank: generator.displayRank, withTeamIndex: generator.displayTeamIndex, withScore: generator.displayScore), loadStatusChanged: { loaded, error, webView in if let error { print("preparePDF", error) } else if loaded == false { @@ -301,7 +313,7 @@ struct WebViewPreview: View { ProgressView() .onAppear { if let groupStage { - html = HtmlService.groupstage(groupStage: groupStage).html(headName: generator.displayHeads, withRank: generator.displayRank, withScore: false) + html = HtmlService.groupstage(groupStage: groupStage).html(headName: generator.displayHeads, withRank: generator.displayRank, withTeamIndex: generator.displayTeamIndex, withScore: generator.displayScore) } else if let round { html = generator.generateLoserBracketHtml(upperRound: round) } else {