From 3781aac0902bd19c1cce9feddef05c4a538d007b Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Fri, 4 Jul 2025 08:46:24 +0200 Subject: [PATCH] add planned date display in print options --- PadelClub.xcodeproj/project.pbxproj | 4 +- PadelClub/HTML Templates/match-template.html | 1 + .../HTML Templates/tournament-template.html | 8 ++ PadelClub/Utils/HtmlGenerator.swift | 9 +- PadelClub/Utils/HtmlService.swift | 85 +++++++++++++------ .../Tournament/Screen/PrintSettingsView.swift | 12 ++- 6 files changed, 83 insertions(+), 36 deletions(-) diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index 2e686ab..9cadd62 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -3137,7 +3137,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.42; + MARKETING_VERSION = 1.2.43; PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -3183,7 +3183,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.42; + MARKETING_VERSION = 1.2.43; PRODUCT_BUNDLE_IDENTIFIER = app.padelclub; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/PadelClub/HTML Templates/match-template.html b/PadelClub/HTML Templates/match-template.html index bf0365d..1f6b761 100644 --- a/PadelClub/HTML Templates/match-template.html +++ b/PadelClub/HTML Templates/match-template.html @@ -3,6 +3,7 @@
{{matchDescriptionTop}}
  • +
    {{centerMatchText}}
  • diff --git a/PadelClub/HTML Templates/tournament-template.html b/PadelClub/HTML Templates/tournament-template.html index 03c77d2..72d6621 100644 --- a/PadelClub/HTML Templates/tournament-template.html +++ b/PadelClub/HTML Templates/tournament-template.html @@ -113,6 +113,14 @@ font-size: 1em; /* Optional: Adjust font size */ /* Add any other desired styling for the overlay */ } + .center-match-overlay { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 0.8em; + white-space: nowrap; /* Prevents text from wrapping */ + } diff --git a/PadelClub/Utils/HtmlGenerator.swift b/PadelClub/Utils/HtmlGenerator.swift index 6ec685a..cd61cc0 100644 --- a/PadelClub/Utils/HtmlGenerator.swift +++ b/PadelClub/Utils/HtmlGenerator.swift @@ -27,6 +27,7 @@ class HtmlGenerator: ObservableObject { @Published var displayRank: Bool = false @Published var displayTeamIndex: Bool = false @Published var displayScore: Bool = false + @Published var displayPlannedDate: Bool = true private var pdfDocument: PDFDocument = PDFDocument() private var rects: [CGRect] = [] @@ -179,12 +180,16 @@ class HtmlGenerator: ObservableObject { func generateHtml() -> String { //HtmlService.groupstage(bracket: tournament.orderedBrackets.first!).html() - HtmlService.template(tournament: tournament).html(headName: displayHeads, withRank: displayRank, withTeamIndex: displayTeamIndex, withScore: displayScore) + HtmlService.template(tournament: tournament).html(options: options) } func generateLoserBracketHtml(upperRound: Round) -> String { //HtmlService.groupstage(bracket: tournament.orderedBrackets.first!).html() - HtmlService.loserBracket(upperRound: upperRound, hideTitle: false).html(headName: displayHeads, withRank: displayRank, withTeamIndex: displayTeamIndex, withScore: displayScore) + HtmlService.loserBracket(upperRound: upperRound, hideTitle: false).html(options: options) + } + + var options: HtmlOptions { + HtmlOptions(headName: displayHeads, withRank: displayRank, withTeamIndex: displayTeamIndex, withScore: displayScore, withPlannedDate: displayPlannedDate) } var pdfURL: URL? { diff --git a/PadelClub/Utils/HtmlService.swift b/PadelClub/Utils/HtmlService.swift index da7e2f0..292f11f 100644 --- a/PadelClub/Utils/HtmlService.swift +++ b/PadelClub/Utils/HtmlService.swift @@ -8,6 +8,29 @@ import Foundation import PadelClubData +struct HtmlOptions { + let headName: Bool + let withRank: Bool + let withTeamIndex: Bool + let withScore: Bool + let withPlannedDate: Bool + + // Default initializer with all options defaulting to true + init( + headName: Bool = true, + withRank: Bool = true, + withTeamIndex: Bool = true, + withScore: Bool = true, + withPlannedDate: Bool = true + ) { + self.headName = headName + self.withRank = withRank + self.withTeamIndex = withTeamIndex + self.withScore = withScore + self.withPlannedDate = withPlannedDate + } +} + enum HtmlService { case template(tournament: Tournament) @@ -51,7 +74,7 @@ enum HtmlService { } } - func html(headName: Bool, withRank: Bool, withTeamIndex: Bool, withScore: Bool) -> String { + func html(options: HtmlOptions = HtmlOptions()) -> String { guard let file = Bundle.main.path(forResource: self.fileName, ofType: "html") else { fatalError() } @@ -74,8 +97,8 @@ enum HtmlService { var col = "" var row = "" bracket.teams().forEach { entrant in - 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)) + col = col.appending(HtmlService.groupstageColumn(entrant: entrant, position: "col").html(options: options)) + row = row.appending(HtmlService.groupstageRow(entrant: entrant, teamsPerBracket: bracket.size).html(options: options)) } template = template.replacingOccurrences(of: "{{teamsCol}}", with: col) template = template.replacingOccurrences(of: "{{teamsRow}}", with: row) @@ -83,7 +106,7 @@ enum HtmlService { return template case .groupstageEntrant(let entrant): var template = html - if withTeamIndex == false { + if options.withTeamIndex == false { template = template.replacingOccurrences(of: #"
    {{teamIndex}}
    "#, with: "") } else { template = template.replacingOccurrences(of: "{{teamIndex}}", with: entrant.seedIndex() ?? "") @@ -91,7 +114,7 @@ enum HtmlService { if let playerOne = entrant.players()[safe: 0] { template = template.replacingOccurrences(of: "{{playerOne}}", with: playerOne.playerLabel()) - if withRank { + if options.withRank { template = template.replacingOccurrences(of: "{{weightOne}}", with: "(\(playerOne.formattedRank()))") } else { template = template.replacingOccurrences(of: "{{weightOne}}", with: "") @@ -103,7 +126,7 @@ enum HtmlService { if let playerTwo = entrant.players()[safe: 1] { template = template.replacingOccurrences(of: "{{playerTwo}}", with: playerTwo.playerLabel()) - if withRank { + if options.withRank { template = template.replacingOccurrences(of: "{{weightTwo}}", with: "(\(playerTwo.formattedRank()))") } else { template = template.replacingOccurrences(of: "{{weightTwo}}", with: "") @@ -115,7 +138,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, withTeamIndex: withTeamIndex, withScore: withScore)) + template = template.replacingOccurrences(of: "{{team}}", with: HtmlService.groupstageColumn(entrant: entrant, position: "row").html(options: options)) var scores = "" (0..{{teamIndex}}
    "#, with: "") } else { template = template.replacingOccurrences(of: "{{teamIndex}}", with: entrant.formattedSeed()) @@ -155,7 +178,7 @@ enum HtmlService { if let playerOne = entrant.players()[safe: 0] { template = template.replacingOccurrences(of: "{{playerOne}}", with: playerOne.playerLabel()) - if withRank { + if options.withRank { template = template.replacingOccurrences(of: "{{weightOne}}", with: "(\(playerOne.formattedRank()))") } else { template = template.replacingOccurrences(of: "{{weightOne}}", with: "") @@ -167,7 +190,7 @@ enum HtmlService { if let playerTwo = entrant.players()[safe: 1] { template = template.replacingOccurrences(of: "{{playerTwo}}", with: playerTwo.playerLabel()) - if withRank { + if options.withRank { template = template.replacingOccurrences(of: "{{weightTwo}}", with: "(\(playerTwo.formattedRank()))") } else { template = template.replacingOccurrences(of: "{{weightTwo}}", with: "") @@ -179,27 +202,32 @@ enum HtmlService { return template case .hiddenPlayer: var template = html + html - if withTeamIndex { + if options.withTeamIndex { template += html } return template case .match(let match): var template = html + if options.withPlannedDate, let plannedStartDate = match.plannedStartDate { + template = template.replacingOccurrences(of: "{{centerMatchText}}", with: plannedStartDate.localizedDate()) + } else { + + } if let entrantOne = match.team(.one) { - template = template.replacingOccurrences(of: "{{entrantOne}}", with: HtmlService.player(entrant: entrantOne).html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore)) - if withScore, let top = match.topPreviousRoundMatch(), top.hasEnded() { + template = template.replacingOccurrences(of: "{{entrantOne}}", with: HtmlService.player(entrant: entrantOne).html(options: options)) + if options.withScore, let top = match.topPreviousRoundMatch(), top.hasEnded() { template = template.replacingOccurrences(of: "{{matchDescriptionTop}}", with: [top.scoreLabel(winnerFirst:true)].compactMap({ $0 }).joined(separator: "\n")) } } else { - template = template.replacingOccurrences(of: "{{entrantOne}}", with: HtmlService.hiddenPlayer.html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore)) + template = template.replacingOccurrences(of: "{{entrantOne}}", with: HtmlService.hiddenPlayer.html(options: options)) } if let entrantTwo = match.team(.two) { - template = template.replacingOccurrences(of: "{{entrantTwo}}", with: HtmlService.player(entrant: entrantTwo).html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore)) - if withScore, let bottom = match.bottomPreviousRoundMatch(), bottom.hasEnded() { + template = template.replacingOccurrences(of: "{{entrantTwo}}", with: HtmlService.player(entrant: entrantTwo).html(options: options)) + if options.withScore, let bottom = match.bottomPreviousRoundMatch(), bottom.hasEnded() { template = template.replacingOccurrences(of: "{{matchDescriptionBottom}}", with: [bottom.scoreLabel(winnerFirst:true)].compactMap({ $0 }).joined(separator: "\n")) } } else { - template = template.replacingOccurrences(of: "{{entrantTwo}}", with: HtmlService.hiddenPlayer.html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore)) + template = template.replacingOccurrences(of: "{{entrantTwo}}", with: HtmlService.hiddenPlayer.html(options: options)) } if match.disabled { template = template.replacingOccurrences(of: "{{hidden}}", with: "hidden") @@ -216,12 +244,13 @@ enum HtmlService { } template = template.replacingOccurrences(of: "{{matchDescriptionTop}}", with: "") template = template.replacingOccurrences(of: "{{matchDescriptionBottom}}", with: "") + template = template.replacingOccurrences(of: "{{centerMatchText}}", with: "") return template case .bracket(let round): var template = "" var bracket = "" for (_, match) in round._matches().enumerated() { - template = template.appending(HtmlService.match(match: match).html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore)) + template = template.appending(HtmlService.match(match: match).html(options: options)) } bracket = html.replacingOccurrences(of: "{{match-template}}", with: template) @@ -230,7 +259,7 @@ enum HtmlService { return bracket case .loserBracket(let upperRound, let hideTitle): var template = html - template = template.replacingOccurrences(of: "{{minHeight}}", with: withTeamIndex ? "226" : "156") + template = template.replacingOccurrences(of: "{{minHeight}}", with: options.withTeamIndex ? "226" : "156") template = template.replacingOccurrences(of: "{{tournamentTitle}}", with: upperRound.correspondingLoserRoundTitle()) if let tournamentStartDate = upperRound.initialStartDate()?.localizedDate() { template = template.replacingOccurrences(of: "{{tournamentStartDate}}", with: tournamentStartDate) @@ -242,10 +271,10 @@ enum HtmlService { var brackets = "" for round in upperRound.loserRounds() { - brackets = brackets.appending(HtmlService.bracket(round: round).html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore)) + brackets = brackets.appending(HtmlService.bracket(round: round).html(options: options)) if round.index == 1 { - let sub = HtmlService.loserBracket(upperRound: round, hideTitle: true).html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore) + let sub = HtmlService.loserBracket(upperRound: round, hideTitle: true).html(options: options) template = template.appending(sub) } } @@ -265,7 +294,7 @@ enum HtmlService { for round in upperRound.loserRounds() { if round.index > 1 { - let sub = HtmlService.loserBracket(upperRound: round, hideTitle: true).html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore) + let sub = HtmlService.loserBracket(upperRound: round, hideTitle: true).html(options: options) template = template.appending(sub) } } @@ -273,17 +302,17 @@ enum HtmlService { return template case .template(let tournament): var template = html - template = template.replacingOccurrences(of: "{{minHeight}}", with: withTeamIndex ? "226" : "156") + template = template.replacingOccurrences(of: "{{minHeight}}", with: options.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, withTeamIndex: withTeamIndex, withScore: withScore)) + brackets = brackets.appending(HtmlService.bracket(round: round).html(options: options)) } var winnerName = "" if let tournamentWinner = tournament.tournamentWinner() { - winnerName = HtmlService.player(entrant: tournamentWinner).html(headName: headName, withRank: withRank, withTeamIndex: withTeamIndex, withScore: withScore) + winnerName = HtmlService.player(entrant: tournamentWinner).html(options: options) } let winner = """