diff --git a/PadelClub/Data/Coredata/Persistence.swift b/PadelClub/Data/Coredata/Persistence.swift index 26a14d2..69ba981 100644 --- a/PadelClub/Data/Coredata/Persistence.swift +++ b/PadelClub/Data/Coredata/Persistence.swift @@ -122,7 +122,7 @@ class PersistenceController: NSObject { // 1 var index = 0 let total = imported.count - let replacements: [(Character, Character)] = [("Á", "ç"), ("‡", "à"), ("Ù", "ô"), ("Ë", "è"), ("Ó", "î"), ("Î", "ë"), ("…", "É"), ("Ô", "ï"), ("È", "é"), ("«", "Ç"), ("»", "È")] + let replacements: [(Character, Character)] = [("Á", "ç"), ("‡", "à"), ("Ù", "ô"), ("Ë", "è"), ("Ó", "î"), ("Î", "ë"), ("…", "É"), ("Ô", "ï"), ("È", "é"), ("«", "Ç"), ("»", "È"), ("ù", "ô")] let replacementsCharacters = replacements diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index e2ad3f6..6cbc291 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -391,8 +391,17 @@ class Tournament : ModelObject, Storable { startDate } + func canBePublished() -> Bool { + switch state() { + case .build, .finished, .running: + return unsortedTeams().count > 3 + default: + return false + } + } + func isTournamentPublished() -> Bool { - Date() >= publishedTournamentDate() || publishTournament + (Date() >= publishedTournamentDate() && canBePublished()) || publishTournament } func areTeamsPublished() -> Bool { diff --git a/PadelClub/Views/GroupStage/GroupStageView.swift b/PadelClub/Views/GroupStage/GroupStageView.swift index 098ad1c..8624757 100644 --- a/PadelClub/Views/GroupStage/GroupStageView.swift +++ b/PadelClub/Views/GroupStage/GroupStageView.swift @@ -10,6 +10,7 @@ import LeStorage struct GroupStageView: View { @EnvironmentObject var dataStore: DataStore + @Environment(Tournament.self) private var tournament @Bindable var groupStage: GroupStage @State private var confirmGroupStageStart: Bool = false @State private var sortingMode: GroupStageSortingMode = .auto @@ -190,8 +191,9 @@ struct GroupStageView: View { Menu { NavigationLink { GroupStageNameEditionView(groupStage: groupStage) + .environment(tournament) } label: { - Label("Renommer", systemImage: "pencil") + Label("Modifier le nom et la taille", systemImage: "pencil") } Button("Retirer tout le monde", role: .destructive) { confirmRemoveAll = true @@ -236,9 +238,18 @@ struct GroupStageView: View { struct GroupStageNameEditionView: View { @Environment(\.dismiss) private var dismiss + @Environment(Tournament.self) private var tournament @EnvironmentObject var dataStore: DataStore - let groupStage: GroupStage - @State private var groupStageName: String = "" + @Bindable var groupStage: GroupStage + @State private var groupStageName: String + @State private var presentConfirmationButton: Bool = false + @State private var size: Int + + init(groupStage: GroupStage) { + _groupStage = Bindable(groupStage) + _groupStageName = .init(wrappedValue: groupStage.name ?? "") + _size = .init(wrappedValue: groupStage.size) + } var body: some View { Form { @@ -246,30 +257,90 @@ struct GroupStageNameEditionView: View { TextField("Nom de la poule", text: $groupStageName) .keyboardType(.alphabet) .frame(maxWidth: .infinity) - .onAppear(perform: { - groupStageName = groupStage.name ?? "" - }) .onSubmit { groupStageName = groupStageName.trimmed - groupStage.name = groupStageName - _save() - dismiss() + if groupStageName.isEmpty == false { + groupStage.name = groupStageName + _save() + dismiss() + } } } footer: { - HStack { - Spacer() - FooterButtonView("retirer le nom") { - groupStage.name = nil - groupStageName = groupStage.groupStageTitle() + if groupStage.name != nil { + HStack { + Spacer() + FooterButtonView("retirer le nom") { + groupStage.name = nil + groupStageName = "" + _save() + } + } + } + } + + Section { + LabeledContent { + StepperView(count: $size, minimum: minimumSize(), maximum: maximumSize()) + } label: { + Text("Taille de la poule") + } + + if presentConfirmationButton { + RowButtonView("Confirmer", role: .destructive, confirmationMessage: "Tous les matchs et les équipes de cette poule seront ré-initialisés") { + let teams = groupStage.teams() + teams.forEach { team in + team.groupStagePosition = nil + team.groupStage = nil + groupStage._matches().forEach({ $0.updateTeamScores() }) + } + do { + try dataStore.teamRegistrations.addOrUpdate(contentOfs: teams) + } catch { + Logger.error(error) + } + groupStage.size = size + groupStage.buildMatches() + tournament.shouldVerifyGroupStage = true _save() + presentConfirmationButton = false } } + } footer: { + Text("Vous ne pouvez réduire la taille qu'à partir de la dernière poule et augmentez la taille qu'à partir de la première poule. Une poule ne peut pas avoir moins de 3 équipes et plus d'une équipe de différence par rapport aux autres poules.") } + + } + .onChange(of: size) { + presentConfirmationButton = true } .navigationTitle(groupStage.groupStageTitle()) .toolbarBackground(.visible, for: .navigationBar) } + private func maximumSize() -> Int { + if groupStage.index == 0 { + return tournament.teamsPerGroupStage + 1 + } + + if let previousGroupStage = tournament.groupStages().first(where: { $0.index == groupStage.index - 1 }), previousGroupStage.size > groupStage.size { + return tournament.teamsPerGroupStage + 1 + } + + return tournament.teamsPerGroupStage + } + + private func minimumSize() -> Int { + if groupStage.index == tournament.groupStageCount - 1 { + return max(3, tournament.teamsPerGroupStage - 1) + } + + if let nextGroupStage = tournament.groupStages().first(where: { $0.index == groupStage.index + 1 }), nextGroupStage.size < groupStage.size { + return max(3, tournament.teamsPerGroupStage - 1) + } + + return tournament.teamsPerGroupStage + } + private func _save() { do { try dataStore.groupStages.addOrUpdate(instance: groupStage) diff --git a/PadelClub/Views/Navigation/Umpire/UmpireView.swift b/PadelClub/Views/Navigation/Umpire/UmpireView.swift index 236cd49..21def8b 100644 --- a/PadelClub/Views/Navigation/Umpire/UmpireView.swift +++ b/PadelClub/Views/Navigation/Umpire/UmpireView.swift @@ -54,6 +54,9 @@ struct UmpireView: View { AccountView(user: dataStore.user) { } } label: { AccountRowView(userName: dataStore.user.username) + if dataStore.user.email.isEmpty == false { + Text(dataStore.user.email) + } } } else { NavigationLink { diff --git a/PadelClub/Views/Tournament/Screen/BroadcastView.swift b/PadelClub/Views/Tournament/Screen/BroadcastView.swift index 9ecb6c6..3542a95 100644 --- a/PadelClub/Views/Tournament/Screen/BroadcastView.swift +++ b/PadelClub/Views/Tournament/Screen/BroadcastView.swift @@ -96,10 +96,14 @@ struct BroadcastView: View { Text("Publication prévue") } } + + if tournament.canBePublished() == false { + Text("Pour être visible automatiquement, le tournoi doit avoir été créé il y a 24h, avoir une structure et au moins 4 inscriptions.") + } } header: { Text("Information sur le tournoi") } footer: { - if Date() < tournament.publishedTournamentDate() { + if Date() < tournament.publishedTournamentDate() || tournament.canBePublished() == false { HStack { Spacer() FooterButtonView(tournament.publishTournament ? "masquer sur le site" : "publier maintenant") { diff --git a/PadelClub/Views/User/UserCreationView.swift b/PadelClub/Views/User/UserCreationView.swift index 0dfdb7c..a83cf0a 100644 --- a/PadelClub/Views/User/UserCreationView.swift +++ b/PadelClub/Views/User/UserCreationView.swift @@ -10,9 +10,13 @@ import LeStorage struct UserCreationFormView: View { + @EnvironmentObject var networkMonitor: NetworkMonitor + @Binding var isPresented: Bool @Binding var showEmailValidationMessage: Bool +// @Binding var showLoginScreen: Bool + @State var username: String = "" @State var password1: String = "" @State var password2: String = "" @@ -64,15 +68,21 @@ struct UserCreationFormView: View { .autocorrectionDisabled() TextField("Téléphone", text: self.$phone) .autocorrectionDisabled() - Picker("Pays", selection: $selectedCountryIndex) { - ForEach(0..