You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
347 lines
12 KiB
347 lines
12 KiB
//
|
|
// PrintSettingsView.swift
|
|
// Padel Tournament
|
|
//
|
|
// Created by Razmig Sarkissian on 23/10/2023.
|
|
//
|
|
|
|
import SwiftUI
|
|
import WebKit
|
|
import PadelClubData
|
|
|
|
struct PrintSettingsView: View {
|
|
let tournament: Tournament
|
|
@StateObject var generator: HtmlGenerator
|
|
@State private var presentShareView: Bool = false
|
|
@State private var prepareGroupStage: Bool = false
|
|
@State private var generationId: UUID = UUID()
|
|
@State private var generationGroupStageId: UUID = UUID()
|
|
@State private var generating: Bool = false
|
|
|
|
init(tournament: Tournament) {
|
|
self.tournament = tournament
|
|
_generator = StateObject(wrappedValue: HtmlGenerator(tournament: tournament))
|
|
}
|
|
|
|
var body: some View {
|
|
List {
|
|
Section {
|
|
// Toggle(isOn: $generator.displayHeads, label: {
|
|
// Text("Afficher les têtes de séries")
|
|
// }
|
|
|
|
Toggle(isOn: $generator.displayPlannedDate, label: {
|
|
Text("Afficher la date plannifiée")
|
|
})
|
|
|
|
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")
|
|
})
|
|
.onChange(of: generator.includeBracket) { oldValue, newValue in
|
|
if newValue == false {
|
|
generator.includeLoserBracket = newValue
|
|
}
|
|
}
|
|
|
|
Toggle(isOn: $generator.includeLoserBracket, label: {
|
|
Text("Tableau des matchs de classements")
|
|
})
|
|
.disabled(generator.includeBracket == false)
|
|
|
|
if tournament.groupStages().isEmpty == false {
|
|
Toggle(isOn: $generator.includeGroupStage, label: {
|
|
Text("Poules")
|
|
})
|
|
}
|
|
}
|
|
|
|
Section {
|
|
Picker(selection: $generator.zoomLevel) {
|
|
Text("1 page").tag(nil as Optional<CGFloat>)
|
|
Text("50%").tag(2.0 as Optional<CGFloat>)
|
|
Text("100%").tag(1.0 as Optional<CGFloat>)
|
|
} label: {
|
|
Text("Zoom")
|
|
}
|
|
.onChange(of: generator.zoomLevel) {
|
|
if generator.zoomLevel == nil {
|
|
generator.landscape = false
|
|
}
|
|
}
|
|
|
|
if generator.zoomLevel != nil {
|
|
Toggle(isOn: $generator.landscape, label: {
|
|
Text("Format paysage")
|
|
})
|
|
}
|
|
|
|
HStack {
|
|
Text("Nombre de page A4 à imprimer")
|
|
Spacer()
|
|
Text(generator.estimatedPageCount.formatted())
|
|
}
|
|
} header: {
|
|
Text("Tableau principal")
|
|
}
|
|
|
|
if generating == false {
|
|
RowButtonView("Générer le PDF", systemImage: "printer") {
|
|
await MainActor.run() {
|
|
self.generating = true
|
|
}
|
|
generator.preparePDF { result in
|
|
switch result {
|
|
case .success(true):
|
|
if generator.includeGroupStage && generator.groupStageIsReady == false && tournament.groupStages().isEmpty == false {
|
|
self.prepareGroupStage = true
|
|
self.generationGroupStageId = UUID()
|
|
} else {
|
|
self.presentShareView = true
|
|
self.generating = false
|
|
}
|
|
case .success(false):
|
|
print("didn't save pdf")
|
|
break
|
|
case .failure(let error):
|
|
print(error)
|
|
break
|
|
}
|
|
}
|
|
self.prepareGroupStage = false
|
|
self.generationId = UUID()
|
|
}
|
|
.disabled(generator.includeBracket == false && generator.includeGroupStage == false)
|
|
} else {
|
|
LabeledContent {
|
|
ProgressView()
|
|
} label: {
|
|
Text("Préparation du PDF")
|
|
}
|
|
.id(generationId)
|
|
}
|
|
|
|
Section {
|
|
NavigationLink {
|
|
WebViewPreview()
|
|
.environmentObject(generator)
|
|
} label: {
|
|
Text("Aperçu du tableau")
|
|
}
|
|
|
|
ForEach(tournament.rounds()) { round in
|
|
if round.index > 0 {
|
|
NavigationLink {
|
|
WebViewPreview(round: round)
|
|
.environmentObject(generator)
|
|
} label: {
|
|
Text("Aperçu \(round.correspondingLoserRoundTitle())")
|
|
}
|
|
}
|
|
}
|
|
|
|
ForEach(tournament.groupStages()) { groupStage in
|
|
NavigationLink {
|
|
WebViewPreview(groupStage: groupStage)
|
|
.environmentObject(generator)
|
|
} label: {
|
|
Text("Aperçu de la \(groupStage.groupStageTitle())")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.background {
|
|
if generating {
|
|
_backgroundGenerationWebView()
|
|
_backgroundGroupStageWebView()
|
|
}
|
|
}
|
|
.navigationTitle("Imprimer")
|
|
.ifAvailableiOS26 {
|
|
if #available(iOS 26.0, *) {
|
|
$0.navigationSubtitle(tournament.tournamentTitle())
|
|
}
|
|
}
|
|
.toolbarBackground(.visible, for: .navigationBar)
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.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(options: generator.options)) {
|
|
Text("Poule")
|
|
}
|
|
}
|
|
|
|
if let round = tournament.rounds().first {
|
|
ShareLink(item: generator.generateLoserBracketHtml(upperRound: round)) {
|
|
Text("Classement")
|
|
}
|
|
}
|
|
|
|
} header: {
|
|
Text("Partager le code source HTML")
|
|
}
|
|
} label: {
|
|
LabelOptions()
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
@ViewBuilder
|
|
private func _backgroundGenerationWebView() -> some View {
|
|
WebView(htmlRawData: generator.generateHtml(), loadStatusChanged: { loaded, error, webView in
|
|
if let error {
|
|
print("preparePDF", error)
|
|
} else if loaded == false {
|
|
generator.generateWebView(webView: webView)
|
|
} else {
|
|
print("preparePDF", "is loading")
|
|
}
|
|
})
|
|
.opacity(0)
|
|
.id(generationId)
|
|
}
|
|
|
|
private func _backgroundGroupStageWebView() -> some View {
|
|
Group {
|
|
if prepareGroupStage {
|
|
ForEach(tournament.groupStages()) { groupStage in
|
|
WebView(htmlRawData: HtmlService.groupstage(groupStage: groupStage).html(options: generator.options), loadStatusChanged: { loaded, error, webView in
|
|
if let error {
|
|
print("preparePDF", error)
|
|
} else if loaded == false {
|
|
generator.generateGroupStage(webView: webView)
|
|
} else {
|
|
print("preparePDF", "is loading")
|
|
}
|
|
}).opacity(0)
|
|
}
|
|
}
|
|
}
|
|
.id(generationGroupStageId)
|
|
}
|
|
}
|
|
|
|
// MARK: Share Sheet
|
|
struct ShareSheet: UIViewControllerRepresentable{
|
|
|
|
var urls: [Any]
|
|
|
|
func makeUIViewController(context: Context) -> UIActivityViewController {
|
|
let controller = UIActivityViewController(activityItems: urls, applicationActivities: nil)
|
|
|
|
return controller
|
|
}
|
|
|
|
func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {
|
|
|
|
}
|
|
}
|
|
|
|
struct WebView: UIViewRepresentable {
|
|
var htmlRawData: String? = nil
|
|
var url: URL? = nil
|
|
var loadStatusChanged: ((Bool, Error?, WKWebView) -> Void)? = nil
|
|
|
|
func makeCoordinator() -> WebView.Coordinator {
|
|
Coordinator(self)
|
|
}
|
|
|
|
func makeUIView(context: Context) -> WKWebView {
|
|
let view = WKWebView()
|
|
view.navigationDelegate = context.coordinator
|
|
|
|
if let htmlRawData {
|
|
view.loadHTMLString(htmlRawData, baseURL: nil)
|
|
}
|
|
if let url {
|
|
view.loadFileURL(url, allowingReadAccessTo: url)
|
|
}
|
|
return view
|
|
}
|
|
|
|
func updateUIView(_ uiView: WKWebView, context: Context) {
|
|
// you can access environment via context.environment here
|
|
// Note that this method will be called A LOT
|
|
}
|
|
|
|
class Coordinator: NSObject, WKNavigationDelegate {
|
|
let parent: WebView
|
|
|
|
init(_ parent: WebView) {
|
|
self.parent = parent
|
|
}
|
|
|
|
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
|
|
parent.loadStatusChanged?(true, nil, webView)
|
|
}
|
|
|
|
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
|
parent.loadStatusChanged?(false, nil, webView)
|
|
}
|
|
|
|
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
|
|
parent.loadStatusChanged?(false, error, webView)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
struct WebViewPreview: View {
|
|
@EnvironmentObject var generator: HtmlGenerator
|
|
let groupStage: GroupStage?
|
|
let round: Round?
|
|
|
|
@State private var html: String?
|
|
|
|
init(groupStage: GroupStage? = nil, round: Round? = nil) {
|
|
self.round = round
|
|
self.groupStage = groupStage
|
|
}
|
|
|
|
var body: some View {
|
|
Group {
|
|
if let html {
|
|
WebView(htmlRawData: html, loadStatusChanged: { loaded, error, webView in
|
|
})
|
|
} else {
|
|
ProgressView()
|
|
.onAppear {
|
|
if let groupStage {
|
|
html = HtmlService.groupstage(groupStage: groupStage).html(options: generator.options)
|
|
} else if let round {
|
|
html = generator.generateLoserBracketHtml(upperRound: round)
|
|
} else {
|
|
html = generator.generateHtml()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|