From 27fa26f86e010f7443cdc10d79de8888173d20c0 Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Wed, 5 Jun 2024 08:18:55 +0200 Subject: [PATCH] b40 --- PadelClub.xcodeproj/project.pbxproj | 8 +- PadelClub/Data/Tournament.swift | 8 +- PadelClub/Utils/Tips.swift | 2 +- PadelClub/Utils/URLs.swift | 5 +- .../Tournament/Screen/BroadcastView.swift | 20 +++-- .../Shared/TournamentBroadcastRowView.swift | 35 ++++++++ .../Tournament/TournamentBuildView.swift | 45 ++++++---- .../Views/Tournament/TournamentInitView.swift | 20 +---- .../TournamentInscriptionView.swift | 28 +++---- .../Views/Tournament/TournamentView.swift | 14 +++- PadelClub/Views/User/LoginView.swift | 82 ++++++++++--------- 11 files changed, 160 insertions(+), 107 deletions(-) create mode 100644 PadelClub/Views/Tournament/Shared/TournamentBroadcastRowView.swift diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index e802fbe..9b24afa 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -202,6 +202,7 @@ FFA1B1292BB71773006CE248 /* PadelClubButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA1B1282BB71773006CE248 /* PadelClubButtonView.swift */; }; FFA6D7852BB0B795003A31F3 /* FileImportManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA6D7842BB0B795003A31F3 /* FileImportManager.swift */; }; FFA6D7872BB0B7A2003A31F3 /* CloudConvert.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA6D7862BB0B7A2003A31F3 /* CloudConvert.swift */; }; + FFB1C98B2C10255100B154A7 /* TournamentBroadcastRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB1C98A2C10255100B154A7 /* TournamentBroadcastRowView.swift */; }; FFB9C8712BBADDE200A0EF4F /* Selectable.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB9C8702BBADDE200A0EF4F /* Selectable.swift */; }; FFB9C8752BBADDF700A0EF4F /* SeedInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB9C8742BBADDF700A0EF4F /* SeedInterval.swift */; }; FFBF065C2BBD2657009D6715 /* GroupStageTeamView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBF065B2BBD2657009D6715 /* GroupStageTeamView.swift */; }; @@ -525,6 +526,7 @@ FFA6D7842BB0B795003A31F3 /* FileImportManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileImportManager.swift; sourceTree = ""; }; FFA6D7862BB0B7A2003A31F3 /* CloudConvert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudConvert.swift; sourceTree = ""; }; FFA6D78A2BB0BEB3003A31F3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + FFB1C98A2C10255100B154A7 /* TournamentBroadcastRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentBroadcastRowView.swift; sourceTree = ""; }; FFB9C8702BBADDE200A0EF4F /* Selectable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Selectable.swift; sourceTree = ""; }; FFB9C8742BBADDF700A0EF4F /* SeedInterval.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedInterval.swift; sourceTree = ""; }; FFBF065B2BBD2657009D6715 /* GroupStageTeamView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupStageTeamView.swift; sourceTree = ""; }; @@ -952,6 +954,7 @@ FF7091672B90F79F00AB08DA /* TournamentCellView.swift */, FF7091692B90F95E00AB08DA /* DateBoxView.swift */, FFA1B1282BB71773006CE248 /* PadelClubButtonView.swift */, + FFB1C98A2C10255100B154A7 /* TournamentBroadcastRowView.swift */, ); path = Shared; sourceTree = ""; @@ -1483,6 +1486,7 @@ FF025AE12BD0EB9000A86CF8 /* TournamentClubSettingsView.swift in Sources */, FFBF065C2BBD2657009D6715 /* GroupStageTeamView.swift in Sources */, FF5DA1932BB9279B00A33061 /* RoundSettingsView.swift in Sources */, + FFB1C98B2C10255100B154A7 /* TournamentBroadcastRowView.swift in Sources */, FF025ADF2BD0CE0A00A86CF8 /* TeamWeightView.swift in Sources */, FF9268012BCE94920080F940 /* SeedsCallingView.swift in Sources */, FF9268092BCEDC2C0080F940 /* CallView.swift in Sources */, @@ -1855,7 +1859,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 39; + CURRENT_PROJECT_VERSION = 40; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_TEAM = BQ3Y44M3Q6; @@ -1893,7 +1897,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 39; + CURRENT_PROJECT_VERSION = 40; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_TEAM = BQ3Y44M3Q6; diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index 6b4d20b..e2ad3f6 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -446,8 +446,12 @@ class Tournament : ModelObject, Storable { } func shareURL(_ pageLink: PageLink = .matches) -> URL? { - if pageLink == .broadcast, let club = club(), let broadcastCode = club.broadcastCode { - return URLs.main.url.appending(path: "c/\(broadcastCode)") + if pageLink == .clubBroadcast { + if let club = club(), let broadcastCode = club.broadcastCode { + return URLs.main.url.appending(path: "c/\(broadcastCode)") + } else { + return nil + } } return URLs.main.url.appending(path: "tournament/\(id)").appending(path: pageLink.path) } diff --git a/PadelClub/Utils/Tips.swift b/PadelClub/Utils/Tips.swift index bf609a9..6acd02c 100644 --- a/PadelClub/Utils/Tips.swift +++ b/PadelClub/Utils/Tips.swift @@ -418,7 +418,7 @@ struct CreateAccountTip: Tip { } var message: Text? { - let message = "Un compte est nécessaire pour publier le tournoi sur [Padel Club](\(URLs.main.rawValue)) et profiter de toutes du site, comme le mode TV pour transformer l'expérience de vos tournois !" + let message = "Un compte est nécessaire pour publier le tournoi sur [Padel Club](\(URLs.main.rawValue)) et profiter de toutes les pages du site, comme le mode TV pour transformer l'expérience de vos tournois !" return Text(.init(message)) } diff --git a/PadelClub/Utils/URLs.swift b/PadelClub/Utils/URLs.swift index e437869..4d97f73 100644 --- a/PadelClub/Utils/URLs.swift +++ b/PadelClub/Utils/URLs.swift @@ -28,7 +28,8 @@ enum PageLink: String, Identifiable, CaseIterable { case groupStages = "Poules" case matches = "Matchs" case rankings = "Classement" - case broadcast = "Broadcast" + case broadcast = "Mode TV (Tournoi)" + case clubBroadcast = "Mode TV (Club)" var id: String { self.rawValue } @@ -50,6 +51,8 @@ enum PageLink: String, Identifiable, CaseIterable { return "group-stages" case .broadcast: return "broadcast" + case .clubBroadcast: + return "" } } } diff --git a/PadelClub/Views/Tournament/Screen/BroadcastView.swift b/PadelClub/Views/Tournament/Screen/BroadcastView.swift index be88b5a..9ecb6c6 100644 --- a/PadelClub/Views/Tournament/Screen/BroadcastView.swift +++ b/PadelClub/Views/Tournament/Screen/BroadcastView.swift @@ -63,7 +63,7 @@ struct BroadcastView: View { } if tournament.isPrivate == false { - if let url = tournament.shareURL(.broadcast) { + if let url = tournament.shareURL(.clubBroadcast) { Section { Link(destination: url) { Text(url.absoluteString) @@ -251,14 +251,20 @@ struct BroadcastView: View { Text("Padel Club") } - if let club = tournament.club(), let clubURL = club.shareURL() { - LabeledContent { + let club = tournament.club() + LabeledContent { + if let clubURL = club?.shareURL() { actionForURL(clubURL) - } label: { - Text("Club") + } + } label: { + Text("Club") + if let club { + Text(club.clubTitle()) + } else { + Text("Aucun club indiqué pour ce tournoi") } } - + if let url = tournament.shareURL(pageLink) { LabeledContent { actionForURL(url) @@ -268,7 +274,7 @@ struct BroadcastView: View { } } - let links : [PageLink] = [.teams, .summons, .groupStages, .matches, .rankings] + let links : [PageLink] = [.teams, .summons, .groupStages, .matches, .rankings, .broadcast, .clubBroadcast] Picker(selection: $pageLink) { ForEach(links) { pageLink in Text(pageLink.localizedLabel()).tag(pageLink) diff --git a/PadelClub/Views/Tournament/Shared/TournamentBroadcastRowView.swift b/PadelClub/Views/Tournament/Shared/TournamentBroadcastRowView.swift new file mode 100644 index 0000000..cb4e79b --- /dev/null +++ b/PadelClub/Views/Tournament/Shared/TournamentBroadcastRowView.swift @@ -0,0 +1,35 @@ +// +// TournamentBroadcastRowView.swift +// PadelClub +// +// Created by Razmig Sarkissian on 05/06/2024. +// + +import SwiftUI +import LeStorage + +struct TournamentBroadcastRowView: View { + var tournament: Tournament + + var body: some View { + NavigationLink(value: Screen.broadcast) { + LabeledContent { + if Store.main.userId == nil { + Image(systemName: "xmark.circle.fill") + .foregroundStyle(.logoRed) + } else { + if tournament.isPrivate { + Text("tournoi privé").foregroundStyle(.logoRed) + } else { + Text("Automatique") + } + } + } label: { + Text("Publication") + if Store.main.userId == nil { + Text("Un compte Padel Club est nécessaire") + } + } + } + } +} diff --git a/PadelClub/Views/Tournament/TournamentBuildView.swift b/PadelClub/Views/Tournament/TournamentBuildView.swift index 1860e54..4f5cb61 100644 --- a/PadelClub/Views/Tournament/TournamentBuildView.swift +++ b/PadelClub/Views/Tournament/TournamentBuildView.swift @@ -17,6 +17,8 @@ struct TournamentBuildView: View { @ViewBuilder var body: some View { + let state = tournament.state() + if tournament.hasEnded() { Section { NavigationLink(value: Screen.rankings) { @@ -70,9 +72,13 @@ struct TournamentBuildView: View { } Section { - if tournament.state() != .finished { - NavigationLink(value: Screen.schedule) { - let tournamentStatus = scheduleStatus + if state == .running || state == .finished { + TournamentBroadcastRowView(tournament: tournament) + } + + if state == .running || state == .finished { + NavigationLink(value: Screen.cashier) { + let tournamentStatus = cashierStatus LabeledContent { if let tournamentStatus { Text(tournamentStatus.completion) @@ -80,7 +86,7 @@ struct TournamentBuildView: View { ProgressView() } } label: { - Text("Horaires") + Text("Encaissement") if let tournamentStatus { Text(tournamentStatus.label).lineLimit(1) } else { @@ -89,11 +95,13 @@ struct TournamentBuildView: View { } } .task { - scheduleStatus = await tournament.scheduleStatus() + cashierStatus = await tournament.cashierStatus() } - - NavigationLink(value: Screen.call) { - let tournamentStatus = callStatus + } + + if state != .finished { + NavigationLink(value: Screen.schedule) { + let tournamentStatus = scheduleStatus LabeledContent { if let tournamentStatus { Text(tournamentStatus.completion) @@ -101,7 +109,7 @@ struct TournamentBuildView: View { ProgressView() } } label: { - Text("Convocations") + Text("Horaires") if let tournamentStatus { Text(tournamentStatus.label).lineLimit(1) } else { @@ -110,13 +118,11 @@ struct TournamentBuildView: View { } } .task { - callStatus = await tournament.callStatus() + scheduleStatus = await tournament.scheduleStatus() } - } - - if tournament.state() == .running || tournament.state() == .finished { - NavigationLink(value: Screen.cashier) { - let tournamentStatus = cashierStatus + + NavigationLink(value: Screen.call) { + let tournamentStatus = callStatus LabeledContent { if let tournamentStatus { Text(tournamentStatus.completion) @@ -124,7 +130,7 @@ struct TournamentBuildView: View { ProgressView() } } label: { - Text("Encaissement") + Text("Convocations") if let tournamentStatus { Text(tournamentStatus.label).lineLimit(1) } else { @@ -133,9 +139,14 @@ struct TournamentBuildView: View { } } .task { - cashierStatus = await tournament.cashierStatus() + callStatus = await tournament.callStatus() } } + + if state == .running || state == .finished { + TournamentInscriptionView(tournament: tournament) + } + } } } diff --git a/PadelClub/Views/Tournament/TournamentInitView.swift b/PadelClub/Views/Tournament/TournamentInitView.swift index ba3c6ef..65c92a7 100644 --- a/PadelClub/Views/Tournament/TournamentInitView.swift +++ b/PadelClub/Views/Tournament/TournamentInitView.swift @@ -42,25 +42,7 @@ struct TournamentInitView: View { } } - NavigationLink(value: Screen.broadcast) { - LabeledContent { - if Store.main.userId == nil { - Image(systemName: "xmark.circle.fill") - .foregroundStyle(.logoRed) - } else { - if tournament.isPrivate { - Text("tournoi privé").foregroundStyle(.logoRed) - } else { - Text("Automatique") - } - } - } label: { - Text("Publication") - if Store.main.userId == nil { - Text("Un compte Padel Club est nécessaire") - } - } - } + TournamentBroadcastRowView(tournament: tournament) NavigationLink(value: Screen.print) { Text("Imprimer") diff --git a/PadelClub/Views/Tournament/TournamentInscriptionView.swift b/PadelClub/Views/Tournament/TournamentInscriptionView.swift index ba99109..fcd1a68 100644 --- a/PadelClub/Views/Tournament/TournamentInscriptionView.swift +++ b/PadelClub/Views/Tournament/TournamentInscriptionView.swift @@ -14,23 +14,21 @@ struct TournamentInscriptionView: View { @ViewBuilder var body: some View { - Section { - NavigationLink(value: Screen.inscription) { - LabeledContent { - Text(tournament.unsortedTeamsWithoutWO().count.formatted() + "/" + tournament.teamCount.formatted()) - } label: { - Text("Gestion des inscriptions") - if let closedRegistrationDate = tournament.closedRegistrationDate { - Text("clôturé le " + closedRegistrationDate.formatted(date: .abbreviated, time: .shortened)) - } + NavigationLink(value: Screen.inscription) { + LabeledContent { + Text(tournament.unsortedTeamsWithoutWO().count.formatted() + "/" + tournament.teamCount.formatted()) + } label: { + Text("Gestion des inscriptions") + if let closedRegistrationDate = tournament.closedRegistrationDate { + Text("clôturé le " + closedRegistrationDate.formatted(date: .abbreviated, time: .shortened)) } } - if let endOfInscriptionDate = tournament.mandatoryRegistrationCloseDate(), tournament.inscriptionClosed() == false && tournament.hasStarted() == false { - LabeledContent { - Text(endOfInscriptionDate.formatted(date: .abbreviated, time: .shortened)) - } label: { - Text("Date limite") - } + } + if let endOfInscriptionDate = tournament.mandatoryRegistrationCloseDate(), tournament.inscriptionClosed() == false && tournament.hasStarted() == false { + LabeledContent { + Text(endOfInscriptionDate.formatted(date: .abbreviated, time: .shortened)) + } label: { + Text("Date limite") } } } diff --git a/PadelClub/Views/Tournament/TournamentView.swift b/PadelClub/Views/Tournament/TournamentView.swift index 6b93243..0f3d4a9 100644 --- a/PadelClub/Views/Tournament/TournamentView.swift +++ b/PadelClub/Views/Tournament/TournamentView.swift @@ -56,14 +56,20 @@ struct TournamentView: View { } } case .initial: - TournamentInscriptionView(tournament: tournament) + Section { + TournamentInscriptionView(tournament: tournament) + } TournamentInitView(tournament: tournament) case .build: - TournamentInscriptionView(tournament: tournament) + Section { + TournamentInscriptionView(tournament: tournament) + } TournamentInitView(tournament: tournament) TournamentBuildView(tournament: tournament) - case .running, .finished: - TournamentInscriptionView(tournament: tournament) + case .running: + TournamentRunningView(tournament: tournament) + TournamentBuildView(tournament: tournament) + case .finished: TournamentBuildView(tournament: tournament) TournamentRunningView(tournament: tournament) } diff --git a/PadelClub/Views/User/LoginView.swift b/PadelClub/Views/User/LoginView.swift index 2ed3117..b5092ee 100644 --- a/PadelClub/Views/User/LoginView.swift +++ b/PadelClub/Views/User/LoginView.swift @@ -11,6 +11,7 @@ import LeStorage struct LoginView: View { @EnvironmentObject var dataStore: DataStore + @EnvironmentObject var networkMonitor: NetworkMonitor @State var username: String = "" @State var password: String = "" @@ -20,6 +21,18 @@ struct LoginView: View { @State var errorText: String? = nil + @State var showSubscriptionView: Bool = false + + var loginFailed: Binding { + Binding { + errorText != nil + } set: { newValue in + if newValue == false { + errorText = nil + } + } + } + var showEmailValidationMessage: Bool = false var handler: (User) -> () @@ -41,26 +54,12 @@ struct LoginView: View { } Section { - Button(action: { - self._login() - }, label: { - if self.isLoading { - HStack { - Spacer() - ProgressView() - Spacer() - } - } else { - Text("Connexion") - .buttonStyle(.borderedProminent) - .tint(.orange) - .listRowBackground(Color.clear) - .frame(maxWidth: .infinity) - } - }) - if let error = self.errorText { - Text(error).font(.callout).foregroundStyle(.red) + RowButtonView("Connexion") { + await self._login() } +// if let error = self.errorText { +// Text(error).font(.callout).foregroundStyle(.red) +// } } if !self.showEmailValidationMessage { @@ -86,6 +85,13 @@ struct LoginView: View { } } + .alert("Un problème est survenu", isPresented: loginFailed) { + Button("OK") { + } + } message: { + let message = [networkMonitor.connected == false ? "L'appareil n'est pas connecté à internet." as String? : nil, errorText].compacted().joined(separator: "\n") + Text(message) + } .navigationTitle("Connexion") .onAppear { #if DEBUG @@ -99,29 +105,27 @@ struct LoginView: View { } } - fileprivate func _login() { + fileprivate func _login() async { self.errorText = nil // reset error self.isLoading = true - Task { - do { - let service = try Store.main.service() - let user: User = try await service.login( - username: self.username, - password: self.password) - self.dataStore.user = user - self.isLoading = false - self.handler(user) - } catch { - self.isLoading = false - switch error { - case ServiceError.responseError(let reason): - self.errorText = reason - default: - self.errorText = error.localizedDescription - } - - Logger.error(error) + do { + let service = try Store.main.service() + let user: User = try await service.login( + username: self.username, + password: self.password) + self.dataStore.user = user + self.isLoading = false + self.handler(user) + } catch { + self.isLoading = false + switch error { + case ServiceError.responseError(let reason): + self.errorText = reason + default: + self.errorText = error.localizedDescription } + + Logger.error(error) } }