From 5f4c995fb8821da65f9518b1d6a233cee7fe1fa5 Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Wed, 17 Apr 2024 07:22:11 +0200 Subject: [PATCH] clean up --- PadelClub.xcodeproj/project.pbxproj | 16 +- PadelClub/Data/Tournament.swift | 39 ++-- PadelClub/Data/User.swift | 13 +- PadelClub/Manager/ContactManager.swift | 15 +- .../CallMessageCustomizationView.swift | 188 ++++++++++++++++++ .../Views/Calling/CallSettingsView.swift | 25 ++- .../CashierDetailView.swift | 0 .../Screen => Cashier}/CashierView.swift | 0 .../Views/Components/RowButtonView.swift | 2 +- PadelClub/Views/Event/EventCreationView.swift | 11 +- .../Event/TournamentConfiguratorView.swift | 12 +- .../Views/Planning/PlanningSettingsView.swift | 19 +- PadelClub/Views/Planning/PlanningView.swift | 109 ++-------- .../TournamentDurationManagerView.swift | 12 +- .../TournamentFieldsManagerView.swift | 11 +- .../Tournament/TournamentRunningView.swift | 12 +- 16 files changed, 308 insertions(+), 176 deletions(-) create mode 100644 PadelClub/Views/Calling/CallMessageCustomizationView.swift rename PadelClub/Views/{Tournament/Screen => Cashier}/CashierDetailView.swift (100%) rename PadelClub/Views/{Tournament/Screen => Cashier}/CashierView.swift (100%) diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index f613ca7..c4f6018 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -85,6 +85,7 @@ FF0EC5752BB195E20056B6D1 /* CLASSEMENT-PADEL-DAMES-11-2022.csv in Resources */ = {isa = PBXBuildFile; fileRef = FF0EC5342BB195CA0056B6D1 /* CLASSEMENT-PADEL-DAMES-11-2022.csv */; }; FF0EC5762BB195E20056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-04-2023.csv in Resources */ = {isa = PBXBuildFile; fileRef = FF0EC5452BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-04-2023.csv */; }; FF0EC5772BB195E20056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-10-2022.csv in Resources */ = {isa = PBXBuildFile; fileRef = FF0EC54A2BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-10-2022.csv */; }; + FF11627A2BCF8109000C4809 /* CallMessageCustomizationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1162792BCF8109000C4809 /* CallMessageCustomizationView.swift */; }; FF1CBC1B2BB53D1F0036DAAB /* FederalTournament.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC182BB53D1F0036DAAB /* FederalTournament.swift */; }; FF1CBC1D2BB53DC10036DAAB /* Calendar+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC1C2BB53DC10036DAAB /* Calendar+Extensions.swift */; }; FF1CBC1F2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC1E2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift */; }; @@ -354,6 +355,7 @@ FF0EC54A2BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-10-2022.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-10-2022.csv"; sourceTree = ""; }; FF0EC54B2BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-11-2022.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-11-2022.csv"; sourceTree = ""; }; FF0EC54C2BB195CA0056B6D1 /* CLASSEMENT-PADEL-MESSIEURS-12-2022.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = "CLASSEMENT-PADEL-MESSIEURS-12-2022.csv"; sourceTree = ""; }; + FF1162792BCF8109000C4809 /* CallMessageCustomizationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallMessageCustomizationView.swift; sourceTree = ""; }; FF1CBC182BB53D1F0036DAAB /* FederalTournament.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FederalTournament.swift; sourceTree = ""; }; FF1CBC1C2BB53DC10036DAAB /* Calendar+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Calendar+Extensions.swift"; sourceTree = ""; }; FF1CBC1E2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FederalTournamentSearchScope.swift; sourceTree = ""; }; @@ -642,6 +644,7 @@ FF089EB92BB011EE00F0AEC7 /* Player */, FF9267FD2BCE94520080F940 /* Calling */, FFF964512BC2628600EEF017 /* Planning */, + FF11627B2BCF937F000C4809 /* Cashier */, FF3F74F72B919F96004CFE0E /* Tournament */, C4A47D882B7BBB5000ADC637 /* Subscription */, C4A47D852B7BA33F00ADC637 /* User */, @@ -766,6 +769,15 @@ path = CSV; sourceTree = ""; }; + FF11627B2BCF937F000C4809 /* Cashier */ = { + isa = PBXGroup; + children = ( + FF9267F92BCE78EB0080F940 /* CashierDetailView.swift */, + FF9267F72BCE78C70080F940 /* CashierView.swift */, + ); + path = Cashier; + sourceTree = ""; + }; FF1DC54D2BAB34FA00FD8220 /* Club */ = { isa = PBXGroup; children = ( @@ -825,8 +837,6 @@ FF8F26532BAE1E4400650388 /* TableStructureView.swift */, FF0E0B6C2BC254C6005F00A9 /* TournamentScheduleView.swift */, FF9268062BCE94D90080F940 /* TournamentCallView.swift */, - FF9267F72BCE78C70080F940 /* CashierView.swift */, - FF9267F92BCE78EB0080F940 /* CashierDetailView.swift */, FF8F26522BAE0E4E00650388 /* Components */, ); path = Screen; @@ -950,6 +960,7 @@ FF9268002BCE94920080F940 /* SeedsCallingView.swift */, FF9268022BCE94A30080F940 /* GroupStageCallingView.swift */, FF9268082BCEDC2C0080F940 /* CallView.swift */, + FF1162792BCF8109000C4809 /* CallMessageCustomizationView.swift */, ); path = Calling; sourceTree = ""; @@ -1362,6 +1373,7 @@ FF8F263D2BAD627A00650388 /* TournamentConfiguratorView.swift in Sources */, FFC1E10C2BAC7FB0008D6F59 /* ClubImportView.swift in Sources */, FF3B60A32BC49BBC008C2E66 /* MatchScheduler.swift in Sources */, + FF11627A2BCF8109000C4809 /* CallMessageCustomizationView.swift in Sources */, FF5DA1952BB927E800A33061 /* GenericDestinationPickerView.swift in Sources */, FF8F26542BAE1E4400650388 /* TableStructureView.swift in Sources */, C45BAE442BCA753E002EEC8A /* Purchase.swift in Sources */, diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index 67690a4..c1859cf 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -448,7 +448,7 @@ class Tournament : ModelObject, Storable { //todo var clubName: String? { - nil + eventObject?.clubObject?.name } //todo @@ -629,16 +629,11 @@ class Tournament : ModelObject, Storable { } func umpireMail() -> [String]? { - if let mail = UserDefaults.standard.string(forKey: "umpireMail"), mail.isEmpty == false { - return [mail] + if let email = DataStore.shared.user?.email { + return [email] } else { return nil } - -// if let umpireMail = federalTournament?.courrielEngagement { -// return [umpireMail] -// } else { -// } } func earnings() -> Double { @@ -655,19 +650,29 @@ class Tournament : ModelObject, Storable { return Double(selectedPlayers.filter { $0.hasPaid() }.count) / Double(selectedPlayers.count) } - func cashierStatus() -> String { - //todo - return "todo" + typealias TournamentStatus = (label:String, completion: String) + func cashierStatus() -> TournamentStatus { + let selectedPlayers = selectedPlayers() + let paid = selectedPlayers.filter({ $0.hasPaid() }) + let label = paid.count.formatted() + " / " + selectedPlayers.count.formatted() + " joueurs encaissés" + let completion = (Double(paid.count) / Double(selectedPlayers.count)).formatted(.percent.precision(.fractionLength(0))) + return TournamentStatus(label: label, completion: completion) } - func scheduleStatus() -> String { - //todo - return "todo" + func scheduleStatus() -> TournamentStatus { + let allMatches = allMatches() + let ready = allMatches.filter({ $0.startDate != nil }) + let label = ready.count.formatted() + " / " + allMatches.count.formatted() + " matchs programmés" + let completion = (Double(ready.count) / Double(allMatches.count)).formatted(.percent.precision(.fractionLength(0))) + return TournamentStatus(label: label, completion: completion) } - func callStatus() -> String { - //todo - return "todo" + func callStatus() -> TournamentStatus { + let selectedSortedTeams = selectedSortedTeams() + let called = selectedSortedTeams.filter{ $0.called() } + let label = called.count.formatted() + " / " + selectedSortedTeams.count.formatted() + " paires convoquées" + let completion = (Double(called.count) / Double(selectedSortedTeams.count)).formatted(.percent.precision(.fractionLength(0))) + return TournamentStatus(label: label, completion: completion) } func bracketStatus() -> String { diff --git a/PadelClub/Data/User.swift b/PadelClub/Data/User.swift index 1626594..63a3ac4 100644 --- a/PadelClub/Data/User.swift +++ b/PadelClub/Data/User.swift @@ -27,7 +27,12 @@ class User: UserBase { var lastName: String var phone: String? var country: String? - + var callMessageBody : String? = nil + var callMessageSignature: String? = nil + var callDisplayFormat: Bool = false + var callDisplayEntryFee: Bool = false + var callUseFullCustomMessage: Bool = false + init(username: String, email: String, firstName: String, lastName: String, phone: String?, country: String?) { self.username = username self.firstName = firstName @@ -64,6 +69,12 @@ class User: UserBase { case _lastName = "lastName" case _phone = "phone" case _country = "country" + case _callMessageBody = "callMessageBody" + case _callMessageSignature = "callMessageSignature" + case _callDisplayFormat = "callDisplayFormat" + case _callDisplayEntryFee = "callDisplayEntryFee" + case _callUseFullCustomMessage = "callUseFullCustomMessage" + } } diff --git a/PadelClub/Manager/ContactManager.swift b/PadelClub/Manager/ContactManager.swift index d139a89..5c381cd 100644 --- a/PadelClub/Manager/ContactManager.swift +++ b/PadelClub/Manager/ContactManager.swift @@ -8,6 +8,7 @@ import Foundation import SwiftUI import MessageUI +import LeStorage enum ContactManagerError: LocalizedError { case mailFailed @@ -33,7 +34,7 @@ extension ContactType { static let defaultSignature = "" static func callingGroupStageCustomMessage(tournament: Tournament?, startDate: Date?, roundLabel: String) -> String { - let tournamentCustomMessage = UserDefaults.standard.string(forKey: "customMessage") ?? defaultCustomMessage + let tournamentCustomMessage = DataStore.shared.user?.callMessageBody ?? defaultCustomMessage let clubName = tournament?.clubName ?? "" var text = tournamentCustomMessage @@ -48,7 +49,7 @@ extension ContactType { text = text.replacingOccurrences(of: "#jour", with: "\(date.formatted(Date.FormatStyle().weekday(.wide).day().month(.wide)))") text = text.replacingOccurrences(of: "#horaire", with: "\(date.formatted(Date.FormatStyle().hour().minute()))") - let signature = UserDefaults.standard.string(forKey: "mySelf") ?? defaultSignature + let signature = DataStore.shared.user?.callMessageSignature ?? defaultSignature text = text.replacingOccurrences(of: "#signature", with: signature) return text @@ -56,7 +57,7 @@ extension ContactType { static func callingGroupStageMessage(tournament: Tournament?, startDate: Date?, roundLabel: String, matchFormat: MatchFormat?) -> String { - let useFullCustomMessage = UserDefaults.standard.bool(forKey: "useFullCustomMessage") + let useFullCustomMessage = DataStore.shared.user?.callUseFullCustomMessage ?? false if useFullCustomMessage { return callingGroupStageCustomMessage(tournament: tournament, startDate: startDate, roundLabel: roundLabel) @@ -65,17 +66,17 @@ extension ContactType { let date = startDate ?? tournament?.startDate ?? Date() let clubName = tournament?.clubName ?? "" - let message = UserDefaults.standard.string(forKey: "customMessage") ?? defaultCustomMessage - let signature = UserDefaults.standard.string(forKey: "mySelf") ?? defaultSignature + let message = DataStore.shared.user?.callMessageBody ?? defaultCustomMessage + let signature = DataStore.shared.user?.callMessageSignature ?? defaultSignature let localizedCalled = "convoqué" + (tournament?.tournamentCategory == .women ? "e" : "") + "s" var formatMessage: String? { - UserDefaults.standard.bool(forKey: "displayFormat") ? matchFormat?.computedLongLabel.appending(".") : nil + (DataStore.shared.user?.callDisplayFormat ?? false) ? matchFormat?.computedLongLabel.appending(".") : nil } var entryFeeMessage: String? { - UserDefaults.standard.bool(forKey: "displayEntryFee") ? tournament?.entryFeeMessage : nil + (DataStore.shared.user?.callDisplayEntryFee ?? false) ? tournament?.entryFeeMessage : nil } var computedMessage: String { diff --git a/PadelClub/Views/Calling/CallMessageCustomizationView.swift b/PadelClub/Views/Calling/CallMessageCustomizationView.swift new file mode 100644 index 0000000..6d8f309 --- /dev/null +++ b/PadelClub/Views/Calling/CallMessageCustomizationView.swift @@ -0,0 +1,188 @@ +// +// CallMessageCustomizationView.swift +// Padel Tournament +// +// Created by Razmig Sarkissian on 02/11/2023. +// + +import SwiftUI + +struct CallMessageCustomizationView: View { + @EnvironmentObject var dataStore: DataStore + var tournament: Tournament + var user: User + + @FocusState private var textEditor: Bool + @State private var customClubName: String = "" + @State private var customCallMessageBody: String = "" + @State private var customCallMessageSignature: String = "" + + init(tournament: Tournament, user: User) { + self.tournament = tournament + self.user = user + _customCallMessageBody = State(wrappedValue: user.callMessageBody ?? "") + _customCallMessageSignature = State(wrappedValue: user.callMessageSignature ?? "") + _customClubName = State(wrappedValue: tournament.clubName ?? "") + } + + var clubName: String { + customClubName + } + + var formatMessage: String? { + user.callDisplayFormat ? tournament.matchFormat.computedLongLabel + "." : nil + } + + var entryFeeMessage: String? { + user.callDisplayEntryFee ? tournament.entryFeeMessage : nil + } + + var computedMessage: String { + [formatMessage, entryFeeMessage, customCallMessageBody].compacted().map { $0.trimmed }.joined(separator: "\n") + } + + var finalMessage: String? { + let localizedCalled = "convoqué" + (tournament.tournamentCategory == .women ? "e" : "") + "s" + return "Bonjour,\n\nVous êtes \(localizedCalled) pour jouer en \(RoundRule.roundName(fromRoundIndex: 2).lowercased()) du \(tournament.tournamentTitle()) au \(clubName) le \(Date().formatted(Date.FormatStyle().weekday(.wide).day().month(.wide))) à \(Date().formatted(Date.FormatStyle().hour().minute())).\n\n" + computedMessage + "\n\n\(customCallMessageSignature)" + } + + var body: some View { + @Bindable var user = user + List { + Section { + ZStack { + Text(customCallMessageBody).hidden() + .padding(.vertical, 20) + TextEditor(text: $customCallMessageBody) + .autocorrectionDisabled() + .focused($textEditor) + } + } header: { + Text("Personnalisation du message de convocation") + } + + Section { + ZStack { + Text(customCallMessageSignature).hidden() + TextEditor(text: $customCallMessageSignature) + .autocorrectionDisabled() + .focused($textEditor) + } + } header: { + Text("Signature du message") + } + + Section { + TextField("Nom du club", text: $customClubName) + .autocorrectionDisabled() + .onSubmit { + if let eventClub = tournament.eventObject?.clubObject { + eventClub.name = customClubName + try? dataStore.clubs.addOrUpdate(instance: eventClub) + } + } + } header: { + Text("Nom du club") + } + + Section { + if user.callUseFullCustomMessage { + Text(self.computedFullCustomMessage()) + .contextMenu { + Button("Coller dans le presse-papier") { + UIPasteboard.general.string = self.computedFullCustomMessage() + } + } + } + else if let finalMessage { + Text(finalMessage) + .contextMenu { + Button("Coller dans le presse-papier") { + UIPasteboard.general.string = finalMessage + } + } + } + } header: { + Text("Exemple") + } + + Section { + LabeledContent { + Toggle(isOn: $user.callUseFullCustomMessage) { + + } + } label: { + Text("contrôle complet du message") + } + } header: { + Text("Personnalisation complète") + } footer: { + Text("Utilisez ces balises dans votre texte : #titre, #jour, #horaire, #club, #signature") + } + } + .navigationTitle("Message de convocation") + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + Menu { + Picker(selection: $user.callDisplayFormat) { + Text("Afficher le format").tag(true) + Text("Masquer le format").tag(false) + } label: { + + } + Picker(selection: $user.callDisplayEntryFee) { + Text("Afficher le prix d'inscription").tag(true) + Text("Masquer le prix d'inscription").tag(false) + } label: { + + } + } label: { + LabelOptions() + } + } + ToolbarItemGroup(placement: .keyboard) { + if textEditor { + Spacer() + Button { + textEditor = false + } label: { + Label("Fermer", systemImage: "xmark") + } + } + } + } + .onChange(of: user.callUseFullCustomMessage) { + if user.callUseFullCustomMessage == false { + user.callMessageBody = ContactType.defaultCustomMessage + } + _save() + } + .onChange(of: customCallMessageBody) { + user.callMessageBody = customCallMessageBody + _save() + } + .onChange(of: customCallMessageSignature) { + user.callMessageSignature = customCallMessageSignature + _save() + } + .onChange(of: user.callDisplayEntryFee) { + _save() + } + .onChange(of: user.callDisplayFormat) { + _save() + } + } + + private func _save() { + try? dataStore.setUser(user) + } + + func computedFullCustomMessage() -> String { + var text = customCallMessageBody.replacingOccurrences(of: "#titre", with: tournament.tournamentTitle()) + text = text.replacingOccurrences(of: "#club", with: clubName) + text = text.replacingOccurrences(of: "#jour", with: "\(Date().formatted(Date.FormatStyle().weekday(.wide).day().month(.wide)))") + text = text.replacingOccurrences(of: "#horaire", with: "\(Date().formatted(Date.FormatStyle().hour().minute()))") + text = text.replacingOccurrences(of: "#signature", with: customCallMessageSignature) + return text + } +} diff --git a/PadelClub/Views/Calling/CallSettingsView.swift b/PadelClub/Views/Calling/CallSettingsView.swift index f794e23..48d868e 100644 --- a/PadelClub/Views/Calling/CallSettingsView.swift +++ b/PadelClub/Views/Calling/CallSettingsView.swift @@ -14,15 +14,24 @@ struct CallSettingsView: View { var body: some View { List { + if let user = dataStore.user { + Section { + NavigationLink { + CallMessageCustomizationView(tournament: tournament, user: user) + } label: { + Text("Personnaliser le message de convocation") + } + } + } + Section { - NavigationLink { - } label: { - Text("Modifier le message de convocation") + RowButtonView("Envoyer un message à tout le monde") { + } } Section { - RowButtonView("Annuler toutes les convocations") { + RowButtonView("Annuler toutes les convocations", role: .destructive) { let teams = tournament.unsortedTeams() teams.forEach { team in team.callDate = nil @@ -32,13 +41,7 @@ struct CallSettingsView: View { } Section { - RowButtonView("Envoyer un message à tout le monde") { - - } - } - - Section { - RowButtonView("Tout le monde a été convoqué") { + RowButtonView("Tout le monde a été convoqué", role: .destructive) { let teams = tournament.unsortedTeams() teams.forEach { team in team.callDate = Date() diff --git a/PadelClub/Views/Tournament/Screen/CashierDetailView.swift b/PadelClub/Views/Cashier/CashierDetailView.swift similarity index 100% rename from PadelClub/Views/Tournament/Screen/CashierDetailView.swift rename to PadelClub/Views/Cashier/CashierDetailView.swift diff --git a/PadelClub/Views/Tournament/Screen/CashierView.swift b/PadelClub/Views/Cashier/CashierView.swift similarity index 100% rename from PadelClub/Views/Tournament/Screen/CashierView.swift rename to PadelClub/Views/Cashier/CashierView.swift diff --git a/PadelClub/Views/Components/RowButtonView.swift b/PadelClub/Views/Components/RowButtonView.swift index b63c450..b8c3b34 100644 --- a/PadelClub/Views/Components/RowButtonView.swift +++ b/PadelClub/Views/Components/RowButtonView.swift @@ -66,7 +66,7 @@ struct RowButtonView: View { .disabled(animatedProgress) .frame(maxWidth: .infinity) .buttonStyle(.borderedProminent) - .tint(role == .destructive ? Color.red : Color.launchScreenBackground) + .tint(role == .destructive ? Color.red : Color.master) .listRowBackground(Color.clear) .listRowInsets(EdgeInsets(.zero)) .confirmationDialog("Confirmation", diff --git a/PadelClub/Views/Event/EventCreationView.swift b/PadelClub/Views/Event/EventCreationView.swift index 3b9670f..c908431 100644 --- a/PadelClub/Views/Event/EventCreationView.swift +++ b/PadelClub/Views/Event/EventCreationView.swift @@ -40,12 +40,11 @@ struct EventCreationView: View { } if eventType == .approvedTournament { - Stepper(value: $duration, in: 1...3) { - HStack { - Text("Durée") - Spacer() - Text("\(duration) jour" + duration.pluralSuffix) - } + LabeledContent { + StepperView(count: $duration, minimum: 1, maximum: 3) + } label: { + Text("Durée") + Text("\(duration) jour" + duration.pluralSuffix) } } diff --git a/PadelClub/Views/Event/TournamentConfiguratorView.swift b/PadelClub/Views/Event/TournamentConfiguratorView.swift index 1f1231c..222fdaf 100644 --- a/PadelClub/Views/Event/TournamentConfiguratorView.swift +++ b/PadelClub/Views/Event/TournamentConfiguratorView.swift @@ -35,13 +35,11 @@ struct TournamentConfigurationView: View { Text(type.localizedLabel()).tag(type.rawValue) } } - - Stepper(value: $tournament.teamCount, in: minimumTeamsCount...maximumTeamsCount) { - HStack { - Text("Équipes souhaitées") - Spacer() - Text(tournament.teamCount.formatted()) - } + LabeledContent { + StepperView(count: $tournament.teamCount, minimum: minimumTeamsCount, maximum: maximumTeamsCount) + } label: { + Text("Équipes souhaitées") + Text(tournament.teamCount.formatted()) } } } diff --git a/PadelClub/Views/Planning/PlanningSettingsView.swift b/PadelClub/Views/Planning/PlanningSettingsView.swift index 69e9559..0721e80 100644 --- a/PadelClub/Views/Planning/PlanningSettingsView.swift +++ b/PadelClub/Views/Planning/PlanningSettingsView.swift @@ -39,12 +39,11 @@ struct PlanningSettingsView: View { List { Section { DatePicker(tournament.startDate.formatted(.dateTime.weekday()), selection: $tournament.startDate) - Stepper(value: $tournament.dayDuration, in: 1...1_000) { - HStack { - Text("Durée") - Spacer() - Text("\(tournament.dayDuration) jour" + tournament.dayDuration.pluralSuffix) - } + LabeledContent { + StepperView(count: $tournament.dayDuration, minimum: 1, maximum: 1_000) + } label: { + Text("Durée") + Text("\(tournament.dayDuration) jour" + tournament.dayDuration.pluralSuffix) } } header: { Text("Démarrage et durée du tournoi") @@ -114,14 +113,6 @@ struct PlanningSettingsView: View { } } } - - Section { - NavigationLink { - - } label: { - Text("Modifier le message de convocation") - } - } } .onChange(of: groupStageCourtCount) { tournament.groupStageCourtCount = groupStageCourtCount diff --git a/PadelClub/Views/Planning/PlanningView.swift b/PadelClub/Views/Planning/PlanningView.swift index 6214d5b..0d688fd 100644 --- a/PadelClub/Views/Planning/PlanningView.swift +++ b/PadelClub/Views/Planning/PlanningView.swift @@ -9,7 +9,6 @@ import SwiftUI struct PlanningView: View { @EnvironmentObject var dataStore: DataStore - @Environment(\.editMode) private var editMode let matches: [Match] @State private var timeSlots: [Date:[Match]] @@ -30,85 +29,27 @@ struct PlanningView: View { Section { ForEach(keys.filter({ $0.dayInt == day.dayInt }), id: \.self) { key in if let _matches = timeSlots[key] { - if editMode?.wrappedValue.isEditing == true { - HStack { - VStack(alignment: .leading) { - let index = keys.firstIndex(of: key) - Button { - let previousKey = keys[index! - 1] - let previousMatches = timeSlots[previousKey] - previousMatches?.forEach { match in - match.startDate = key - } - _matches.forEach { match in - match.startDate = previousKey - } - _update() - } label: { - Image(systemName: "arrow.up") - } - .buttonStyle(.bordered) - .disabled(index == 0) - Button { - let nextKey = keys[index! + 1] - let nextMatches = timeSlots[nextKey] - nextMatches?.forEach { match in - match.startDate = key - } - _matches.forEach { match in - match.startDate = nextKey - } - _update() - } label: { - Image(systemName: "arrow.down") - } - .buttonStyle(.bordered) - .disabled(index == keys.count - 1) - } - VStack(alignment: .leading) { + DisclosureGroup { + ForEach(_matches) { match in + NavigationLink { + MatchDetailView(match: match, matchViewStyle: .sectionedStandardStyle) + } label: { LabeledContent { - Text(_matches.count.formatted() + " match" + _matches.count.pluralSuffix) - } label: { - Text(key.formatted(date: .omitted, time: .shortened)).font(.largeTitle) - } - - ForEach(_matches) { match in - LabeledContent { - Text(match.matchFormat.format) - } label: { - if let groupStage = match.groupStageObject { - Text(groupStage.groupStageTitle()) - } else if let round = match.roundObject { - Text(round.roundTitle()) - } - Text(match.matchTitle()) + if let court = match.court { + Text(court) } - } - } - } - } else { - DisclosureGroup { - ForEach(_matches) { match in - NavigationLink { - MatchDetailView(match: match, matchViewStyle: .sectionedStandardStyle) } label: { - LabeledContent { - if let court = match.court { - Text(court) - } - } label: { - if let groupStage = match.groupStageObject { - Text(groupStage.groupStageTitle()) - } else if let round = match.roundObject { - Text(round.roundTitle()) - } - Text(match.matchTitle()) + if let groupStage = match.groupStageObject { + Text(groupStage.groupStageTitle()) + } else if let round = match.roundObject { + Text(round.roundTitle()) } + Text(match.matchTitle()) } } - } label: { - _timeSlotView(key: key, matches: _matches) } + } label: { + _timeSlotView(key: key, matches: _matches) } } } @@ -118,29 +59,9 @@ struct PlanningView: View { .headerProminence(.increased) } } - .toolbar { - EditButton() - } - .onChange(of: isEditing) { old, new in - if old == true && new == false { - print("save") - try? dataStore.matches.addOrUpdate(contentOfs: matches) - } - } .navigationTitle("Programmation") } - - private func _update() { - let timeSlots = Dictionary(grouping: matches) { $0.startDate ?? .distantFuture } - self.timeSlots = timeSlots - self.days = Set(timeSlots.keys.map { $0.startOfDay }).sorted() - self.keys = timeSlots.keys.sorted() - } - - private var isEditing: Bool { - editMode?.wrappedValue.isEditing == true - } - + private func _timeSlotView(key: Date, matches: [Match]) -> some View { LabeledContent { Text(matches.count.formatted() + " match" + matches.count.pluralSuffix) diff --git a/PadelClub/Views/Tournament/Screen/Components/TournamentDurationManagerView.swift b/PadelClub/Views/Tournament/Screen/Components/TournamentDurationManagerView.swift index f6e5b78..dd4887d 100644 --- a/PadelClub/Views/Tournament/Screen/Components/TournamentDurationManagerView.swift +++ b/PadelClub/Views/Tournament/Screen/Components/TournamentDurationManagerView.swift @@ -12,13 +12,11 @@ struct TournamentDurationManagerView: View { var body: some View { @Bindable var tournament = tournament - - Stepper(value: $tournament.dayDuration, in: 1...3) { - LabeledContent { - Text("\(tournament.dayDuration) jour" + tournament.dayDuration.pluralSuffix) - } label: { - Text("Durée") - } + LabeledContent { + StepperView(count: $tournament.dayDuration, minimum: 1, maximum: 3) + } label: { + Text("Durée") + Text("\(tournament.dayDuration) jour" + tournament.dayDuration.pluralSuffix) } } } diff --git a/PadelClub/Views/Tournament/Screen/Components/TournamentFieldsManagerView.swift b/PadelClub/Views/Tournament/Screen/Components/TournamentFieldsManagerView.swift index 8f46f49..56bf2d7 100644 --- a/PadelClub/Views/Tournament/Screen/Components/TournamentFieldsManagerView.swift +++ b/PadelClub/Views/Tournament/Screen/Components/TournamentFieldsManagerView.swift @@ -12,12 +12,11 @@ struct TournamentFieldsManagerView: View { @Binding var count: Int var body: some View { - Stepper(value: $count, in: 1...1_000) { - LabeledContent { - Text(count.formatted()) - } label: { - Text(localizedStringKey) - } + LabeledContent { + StepperView(count: $count, minimum: 1, maximum: 1_000) + } label: { + Text(localizedStringKey) + Text(count.formatted()) } } } diff --git a/PadelClub/Views/Tournament/TournamentRunningView.swift b/PadelClub/Views/Tournament/TournamentRunningView.swift index fad5286..3d1194c 100644 --- a/PadelClub/Views/Tournament/TournamentRunningView.swift +++ b/PadelClub/Views/Tournament/TournamentRunningView.swift @@ -14,26 +14,32 @@ struct TournamentRunningView: View { var body: some View { Section { NavigationLink(value: Screen.schedule) { + let tournamentStatus = tournament.scheduleStatus() LabeledContent { - Text(tournament.scheduleStatus()) + Text(tournamentStatus.completion).foregroundStyle(.master) } label: { Text("Horaires") + Text(tournamentStatus.label) } } NavigationLink(value: Screen.call) { + let tournamentStatus = tournament.callStatus() LabeledContent { - Text(tournament.callStatus()) + Text(tournamentStatus.completion).foregroundStyle(.master) } label: { Text("Convocations") + Text(tournamentStatus.label) } } NavigationLink(value: Screen.cashier) { + let tournamentStatus = tournament.cashierStatus() LabeledContent { - Text(tournament.cashierStatus()) + Text(tournamentStatus.completion).foregroundStyle(.master) } label: { Text("Encaissement") + Text(tournamentStatus.label) } } }