diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index 19cae54..5f5df08 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -114,6 +114,9 @@ FF5D0D872BB48AFD005CB568 /* NumberFormatter+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D862BB48AFD005CB568 /* NumberFormatter+Extensions.swift */; }; FF5D0D892BB4935C005CB568 /* ClubRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D882BB4935C005CB568 /* ClubRowView.swift */; }; FF5D0D8B2BB4D1E3005CB568 /* CalendarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5D0D8A2BB4D1E3005CB568 /* CalendarView.swift */; }; + FF5DA18F2BB9268800A33061 /* GroupStageSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5DA18E2BB9268800A33061 /* GroupStageSettingsView.swift */; }; + FF5DA1932BB9279B00A33061 /* RoundSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5DA1922BB9279B00A33061 /* RoundSettingsView.swift */; }; + FF5DA1952BB927E800A33061 /* GenericDestinationPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5DA1942BB927E800A33061 /* GenericDestinationPickerView.swift */; }; FF6EC8F72B94773200EA7F5A /* RowButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC8F62B94773100EA7F5A /* RowButtonView.swift */; }; FF6EC8FB2B94788600EA7F5A /* TournamentButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC8FA2B94788600EA7F5A /* TournamentButtonView.swift */; }; FF6EC8FE2B94792300EA7F5A /* Screen.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6EC8FD2B94792300EA7F5A /* Screen.swift */; }; @@ -340,6 +343,9 @@ FF5D0D862BB48AFD005CB568 /* NumberFormatter+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NumberFormatter+Extensions.swift"; sourceTree = ""; }; FF5D0D882BB4935C005CB568 /* ClubRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClubRowView.swift; sourceTree = ""; }; FF5D0D8A2BB4D1E3005CB568 /* CalendarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarView.swift; sourceTree = ""; }; + FF5DA18E2BB9268800A33061 /* GroupStageSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupStageSettingsView.swift; sourceTree = ""; }; + FF5DA1922BB9279B00A33061 /* RoundSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundSettingsView.swift; sourceTree = ""; }; + FF5DA1942BB927E800A33061 /* GenericDestinationPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericDestinationPickerView.swift; sourceTree = ""; }; FF6EC8F62B94773100EA7F5A /* RowButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RowButtonView.swift; sourceTree = ""; }; FF6EC8FA2B94788600EA7F5A /* TournamentButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentButtonView.swift; sourceTree = ""; }; FF6EC8FD2B94792300EA7F5A /* Screen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Screen.swift; sourceTree = ""; }; @@ -603,6 +609,7 @@ isa = PBXGroup; children = ( C4A47D9E2B7D0BCE00ADC637 /* StepperView.swift */, + FF5DA1942BB927E800A33061 /* GenericDestinationPickerView.swift */, FF6EC8F62B94773100EA7F5A /* RowButtonView.swift */, FF967CF72BAEDF0000A9A3BD /* Labels.swift */, ); @@ -846,6 +853,7 @@ children = ( FF967CFA2BAEE13800A9A3BD /* GroupStageView.swift */, FF967CFB2BAEE13900A9A3BD /* GroupStagesView.swift */, + FF5DA18E2BB9268800A33061 /* GroupStageSettingsView.swift */, ); path = GroupStage; sourceTree = ""; @@ -878,6 +886,7 @@ children = ( FFC83D4E2BB807D100750834 /* RoundsView.swift */, FFC83D502BB8087E00750834 /* RoundView.swift */, + FF5DA1922BB9279B00A33061 /* RoundSettingsView.swift */, ); path = Round; sourceTree = ""; @@ -1147,6 +1156,7 @@ FF8F264F2BAE0B9600650388 /* MatchTypeSelectionView.swift in Sources */, FF967D062BAF3C4200A9A3BD /* MatchSetupView.swift in Sources */, FF4AB6B52B9248200002987F /* NetworkManager.swift in Sources */, + FF5DA1932BB9279B00A33061 /* RoundSettingsView.swift in Sources */, FF5D0D742BB41DF8005CB568 /* Color+Extensions.swift in Sources */, C4A47DB12B86375E00ADC637 /* MainUserView.swift in Sources */, FF7091682B90F79F00AB08DA /* TournamentCellView.swift in Sources */, @@ -1192,6 +1202,7 @@ C4A47D7D2B73CDC300ADC637 /* ClubV1.swift in Sources */, FF8F263D2BAD627A00650388 /* TournamentConfiguratorView.swift in Sources */, FFC1E10C2BAC7FB0008D6F59 /* ClubImportView.swift in Sources */, + FF5DA1952BB927E800A33061 /* GenericDestinationPickerView.swift in Sources */, FF8F26542BAE1E4400650388 /* TableStructureView.swift in Sources */, FF6EC8FE2B94792300EA7F5A /* Screen.swift in Sources */, FF967CEE2BAECBD700A9A3BD /* Round.swift in Sources */, @@ -1234,6 +1245,7 @@ FF8F26452BAE0A3400650388 /* TournamentDurationManagerView.swift in Sources */, FF1DC5532BAB354A00FD8220 /* MockData.swift in Sources */, FF967D092BAF3D4000A9A3BD /* TeamDetailView.swift in Sources */, + FF5DA18F2BB9268800A33061 /* GroupStageSettingsView.swift in Sources */, FF8F26382BAD523300650388 /* PadelRule.swift in Sources */, FF967CF42BAECC0B00A9A3BD /* TeamRegistration.swift in Sources */, FFF8ACDB2B923F48008466FA /* Date+Extensions.swift in Sources */, diff --git a/PadelClub/Data/GroupStage.swift b/PadelClub/Data/GroupStage.swift index 4923833..96cd026 100644 --- a/PadelClub/Data/GroupStage.swift +++ b/PadelClub/Data/GroupStage.swift @@ -114,3 +114,8 @@ extension GroupStage { } } +extension GroupStage: Selectable { + func selectionLabel() -> String { + groupStageTitle() + } +} diff --git a/PadelClub/Data/Round.swift b/PadelClub/Data/Round.swift index 8442c08..05f93aa 100644 --- a/PadelClub/Data/Round.swift +++ b/PadelClub/Data/Round.swift @@ -77,3 +77,9 @@ class Round: ModelObject, Storable { case _format = "format" } } + +extension Round: Selectable { + func selectionLabel() -> String { + roundTitle() + } +} diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index 5b8cdcc..8f1cad9 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -139,6 +139,11 @@ class Tournament : ModelObject, Storable { Store.main.filter { $0.tournament == self.id }.sorted(by: \.index) } + func getActiveGroupStage() -> GroupStage? { + let groupStages = groupStages() + return groupStages.filter({ $0.hasStarted() && $0.hasEnded() == false }).sorted(by: \.index).first ?? groupStages.first + } + func getActiveRound() -> Round? { let rounds = rounds() return rounds.filter({ $0.hasStarted() && $0.hasEnded() == false }).sorted(by: \.index).reversed().first ?? rounds.first diff --git a/PadelClub/Views/Components/GenericDestinationPickerView.swift b/PadelClub/Views/Components/GenericDestinationPickerView.swift new file mode 100644 index 0000000..4c0ac5a --- /dev/null +++ b/PadelClub/Views/Components/GenericDestinationPickerView.swift @@ -0,0 +1,61 @@ +// +// GenericDestinationPickerView.swift +// PadelClub +// +// Created by Razmig Sarkissian on 31/03/2024. +// + +import SwiftUI + +protocol Selectable { + func selectionLabel() -> String +} + +struct GenericDestinationPickerView: View { + @Binding var selectedDestination: T? + let destinations: [T] + + var body: some View { + ScrollView(.horizontal) { + HStack { + Button { + selectedDestination = nil + } label: { + Image(systemName: "wrench.and.screwdriver") + } + .padding() + .background { + Circle() + .fill(Color.white) + .opacity(selectedDestination == nil ? 1.0 : 0.5) + } + .buttonStyle(.plain) + + ForEach(destinations) { destination in + Button { + selectedDestination = destination + } label: { + Text(destination.selectionLabel()) + } + .padding() + .background { + Capsule() + .fill(Color.white) + .opacity(selectedDestination?.id == destination.id ? 1.0 : 0.5) + } + .buttonStyle(.plain) + } + } + .fixedSize() + .padding(8) + } + .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) + .background(Material.ultraThinMaterial) + .overlay { + VStack(spacing: 0) { + Spacer() + Divider() + } + } + } +} diff --git a/PadelClub/Views/GroupStage/GroupStageSettingsView.swift b/PadelClub/Views/GroupStage/GroupStageSettingsView.swift new file mode 100644 index 0000000..2ba3077 --- /dev/null +++ b/PadelClub/Views/GroupStage/GroupStageSettingsView.swift @@ -0,0 +1,145 @@ +// +// GroupStageSettingsView.swift +// PadelClub +// +// Created by Razmig Sarkissian on 31/03/2024. +// + +import SwiftUI + +struct GroupStageSettingsView: View { + @Environment(Tournament.self) var tournament: Tournament + + var body: some View { + List { + if tournament.missingQualifiedFromGroupStages().isEmpty == false && tournament.qualifiedTeams().count >= tournament.qualifiedFromGroupStage() && tournament.groupStageAdditionalQualified > 0 { + NavigationLink { + //DrawView(tournament: tournament) + } label: { + LabeledContent { + Text(tournament.moreQualifiedToDraw().formatted() + "/" + tournament.groupStageAdditionalQualified.formatted()) + } label: { + Text("Qualifié\(tournament.groupStageAdditionalQualified.pluralSuffix) supplémentaire\(tournament.groupStageAdditionalQualified.pluralSuffix)") + let message = [tournament.groupStageAdditionalQualified.formatted(), " meilleur", tournament.groupStageAdditionalQualified.pluralSuffix, " ", (tournament.qualifiedPerGroupStage + 1).ordinalFormatted()].joined() + Text(message) + } + } + } + +// if (tournament.groupStagesAreWrong || (tournament.emptySlotInGroupStages > 0 && tournament.entriesCount >= tournament.teamsFromGroupStages)) { +// Section { +// RowButtonView(title: "Reconstruire les poules") { +// confirmGroupStageRebuild = true +// } +// .modify { +// if UIDevice.current.userInterfaceIdiom == .pad { +// $0.alert("Êtes-vous sûr ?", isPresented: $confirmGroupStageRebuild) { +// +// Button(role: .destructive) { +// tournament.refreshGroupStages() +// save() +// } label: { +// Text("Reconstruire") +// } +// +// +// Button(role: .cancel) { +// +// } label: { +// Text("Annuler") +// } +// } message: { +// Text("Attention, cela peut modifier les poules existants.") +// +// } +// } else { +// $0.confirmationDialog("Êtes-vous sûr ?", isPresented: $confirmGroupStageRebuild) { +// Button(role: .destructive) { +// tournament.refreshGroupStages() +// save() +// } label: { +// Text("Reconstruire") +// } +// } message: { +// Text("Attention, cela peut modifier les poules existants.") +// } +// } +// } +// } header: { +// Text("Erreur détectée") +// } +// } +// + +// if tournament.isRoundSwissTournament() == false && (tournament.orderedGroupStages.allSatisfy({ $0.orderedMatches.count > 0 }) == false && tournament.groupStagesAreOver == false && tournament.groupStagesCount > 0) { +// Section { +// RowButtonView(title: "Générer les matchs de poules") { +// startAllGroupStageConfirmation = true +// } +// .modify { +// if UIDevice.current.userInterfaceIdiom == .pad { +// $0.alert("Êtes-vous sûr ?", isPresented: $startAllGroupStageConfirmation) { +// Button("Générer") { +// tournament.orderedGroupStages.forEach { +// if $0.orderedMatches.isEmpty { +// $0.startGroupStage() +// } +// } +// save() +// } +// Button(role: .cancel) { +// +// } label: { +// Text("Annuler") +// } +// } +// +// } else { +// $0.confirmationDialog("Êtes-vous sûr ?", isPresented: $startAllGroupStageConfirmation) { +// Button("Générer") { +// tournament.orderedGroupStages.forEach { +// if $0.orderedMatches.isEmpty { +// $0.startGroupStage() +// } +// } +// save() +// } +// } +// } +// } +// } +// } +// + if tournament.groupStagesAreOver() == false { +// Section { +// GroupStageMatchAvailableToStartView(tournament: tournament, groupStageIndex: selectedGroupStageIndex) +// } header: { +// if selectedGroupStageIndex == -1 { +// Text("Matchs de poules prêt à démarrer") +// } else { +// Text("Matchs de la poule \(selectedGroupStageIndex) prêt à démarrer") +// } +// } footer: { +// Text("présence d'au moins 2 équipes d'une même poule ayant réglé.") +// } + } + +// if tournament.teamsPerGroupStage == 3 && tournament.qualifiedPerGroupStage == 1 && tournament.numberOfGroupStages%2 == 0 && tournament.moreQualifiedFromGroupStages == 0 { +// Section { +// NavigationLink { +// GroupStageMissingMatchView(tournament: tournament) +// } label: { +// Text("Matchs de classement de poules") +// } +// } +// } + + + } + } +} + +#Preview { + GroupStageSettingsView() + .environment(Tournament.mock()) +} diff --git a/PadelClub/Views/GroupStage/GroupStageView.swift b/PadelClub/Views/GroupStage/GroupStageView.swift index c45b87e..7653dfa 100644 --- a/PadelClub/Views/GroupStage/GroupStageView.swift +++ b/PadelClub/Views/GroupStage/GroupStageView.swift @@ -54,142 +54,155 @@ struct GroupStageView: View { } var body: some View { - Section { - groupStageView -// .disabled(canUpdateTournament == false) -// .sheet(item: $selectedMenuLink) { selectedMenuLink in -// switch selectedMenuLink { -// case .prepare: -// PrepareGroupStageView(groupStage: groupStage) -// } -// } - } header: { - HStack { - if groupStage.isBroadcasted() { - Label(groupStage.groupStageTitle(), systemImage: "airplayvideo") - } else { - Text(groupStage.groupStageTitle()) - } - Spacer() - if let startDate = groupStage.startDate { - Text(startDate.formatted(Date.FormatStyle().weekday(.wide)).capitalized + " à partir de " + startDate.formatted(.dateTime.hour().minute())) + List { + Section { + groupStageView + // .disabled(canUpdateTournament == false) + // .sheet(item: $selectedMenuLink) { selectedMenuLink in + // switch selectedMenuLink { + // case .prepare: + // PrepareGroupStageView(groupStage: groupStage) + // } + // } + } header: { + HStack { + if groupStage.isBroadcasted() { + Label(groupStage.groupStageTitle(), systemImage: "airplayvideo") + } else { + Text(groupStage.groupStageTitle()) + } + Spacer() + if let startDate = groupStage.startDate { + Text(startDate.formatted(Date.FormatStyle().weekday(.wide)).capitalized + " à partir de " + startDate.formatted(.dateTime.hour().minute())) + } } - } - } footer: { - HStack { - if groupStage.matches.isEmpty { - Button { - //groupStage.startGroupStage() - //save() + } footer: { + HStack { + if groupStage.matches.isEmpty { + Button { + //groupStage.startGroupStage() + //save() + } label: { + Text("Créer les matchs") + } + .buttonStyle(.borderless) + } + Spacer() + Menu { + // Button { + // selectedMenuLink = .prepare + // } label: { + // Label("Préparer", systemImage: "calendar") + // } + // + // Menu { + // MenuWarnView(warningSender: groupStage) + // } label: { + // Label("Prévenir", systemImage: "person.crop.circle") + // } + // + // if groupStage.isBroadcasted() { + // Button { + // groupStage.refreshBroadcast() + // } label: { + // Label("Rafraîchir", systemImage: "arrow.up.circle.fill") + // } + // Button { + // groupStage.stopBroadcast() + // save() + // } label: { + // Label("Arrêter la diffusion", systemImage: "stop.circle.fill") + // } + // } else if groupStage.tournament?.canBroadcast() == true { + // Button { + // Task { + // try? await groupStage.broadcastGroupStage() + // save() + // } + // } label: { + // Label("Diffuser", systemImage: "airplayvideo") + // } + // } + // + // Divider() + // if groupStage.tournament?.canBroadcast() == true { + // Menu { + // Button { + // Task { + // try? await groupStage.broadcastGroupStageMatches() + // save() + // } + // } label: { + // Label("Diffuser", systemImage: "airplayvideo") + // } + // + // Button { + // groupStage.refreshBroadcastMatches() + // } label: { + // Label("Rafraîchir", systemImage: "arrow.up.circle.fill") + // } + // Button { + // groupStage.stopBroadcastMatches() + // save() + // } label: { + // Label("Arrêter la diffusion", systemImage: "stop.circle.fill") + // } + // } label: { + // Text("Diffusion des matchs") + // } + // } + // + // Divider() + // Menu { + // if groupStage.orderedMatches.isEmpty == false { + // Button(role: .destructive) { + // groupStage.startGroupStage() + // save() + // } label: { + // Label("Re-démarrer les matchs de la \(groupStage.titleLabel.lowercased())", systemImage: "trash") + // } + // } + // + // if groupStage.orderedMatches.isEmpty == false { + // Button(role: .destructive) { + // groupStage.removeMatches() + // save() + // } label: { + // Label("Supprimer les matchs de la \(groupStage.titleLabel.lowercased())", systemImage: "trash") + // } + // } + // + // Button(role: .destructive) { + // groupStage.tournament?.completeEntries.filter { $0.groupStagePosition == groupStage.index }.forEach { $0.resetGroupStagePosition() } + // groupStage.tournament?.removeFromGroupStages(groupStage) + // groupStage.tournament?.numberOfGroupStages -= 1 + // save() + // } label: { + // Label("Supprimer la \(groupStage.titleLabel.lowercased())", systemImage: "trash") + // } + // } label: { + // Text("Éditer") + // } } label: { - Text("Créer les matchs") + HStack { + Spacer() + Label("Options", systemImage: "ellipsis.circle").labelStyle(.titleOnly) + } } .buttonStyle(.borderless) } - Spacer() - Menu { -// Button { -// selectedMenuLink = .prepare -// } label: { -// Label("Préparer", systemImage: "calendar") -// } -// -// Menu { -// MenuWarnView(warningSender: groupStage) -// } label: { -// Label("Prévenir", systemImage: "person.crop.circle") -// } -// -// if groupStage.isBroadcasted() { -// Button { -// groupStage.refreshBroadcast() -// } label: { -// Label("Rafraîchir", systemImage: "arrow.up.circle.fill") -// } -// Button { -// groupStage.stopBroadcast() -// save() -// } label: { -// Label("Arrêter la diffusion", systemImage: "stop.circle.fill") -// } -// } else if groupStage.tournament?.canBroadcast() == true { -// Button { -// Task { -// try? await groupStage.broadcastGroupStage() -// save() -// } -// } label: { -// Label("Diffuser", systemImage: "airplayvideo") -// } -// } -// -// Divider() -// if groupStage.tournament?.canBroadcast() == true { -// Menu { -// Button { -// Task { -// try? await groupStage.broadcastGroupStageMatches() -// save() -// } -// } label: { -// Label("Diffuser", systemImage: "airplayvideo") -// } -// -// Button { -// groupStage.refreshBroadcastMatches() -// } label: { -// Label("Rafraîchir", systemImage: "arrow.up.circle.fill") -// } -// Button { -// groupStage.stopBroadcastMatches() -// save() -// } label: { -// Label("Arrêter la diffusion", systemImage: "stop.circle.fill") -// } -// } label: { -// Text("Diffusion des matchs") -// } -// } -// -// Divider() -// Menu { -// if groupStage.orderedMatches.isEmpty == false { -// Button(role: .destructive) { -// groupStage.startGroupStage() -// save() -// } label: { -// Label("Re-démarrer les matchs de la \(groupStage.titleLabel.lowercased())", systemImage: "trash") -// } -// } -// -// if groupStage.orderedMatches.isEmpty == false { -// Button(role: .destructive) { -// groupStage.removeMatches() -// save() -// } label: { -// Label("Supprimer les matchs de la \(groupStage.titleLabel.lowercased())", systemImage: "trash") -// } -// } -// -// Button(role: .destructive) { -// groupStage.tournament?.completeEntries.filter { $0.groupStagePosition == groupStage.index }.forEach { $0.resetGroupStagePosition() } -// groupStage.tournament?.removeFromGroupStages(groupStage) -// groupStage.tournament?.numberOfGroupStages -= 1 -// save() -// } label: { -// Label("Supprimer la \(groupStage.titleLabel.lowercased())", systemImage: "trash") -// } -// } label: { -// Text("Éditer") -// } - } label: { - HStack { - Spacer() - Label("Options", systemImage: "ellipsis.circle").labelStyle(.titleOnly) + } + + if groupStage.matches.isEmpty == false { + Section { + ForEach(groupStage.matches) { match in + MatchRowView(match: match, setupSeedContext: false, matchViewStyle: .sectionedStandardStyle) } + } header: { + Text("Matchs de la " + groupStage.groupStageTitle()) } - .buttonStyle(.borderless) } + } // .onAppear { // if let tournament = groupStage.tournament { diff --git a/PadelClub/Views/GroupStage/GroupStagesView.swift b/PadelClub/Views/GroupStage/GroupStagesView.swift index a49dfc7..deb21d0 100644 --- a/PadelClub/Views/GroupStage/GroupStagesView.swift +++ b/PadelClub/Views/GroupStage/GroupStagesView.swift @@ -8,206 +8,29 @@ import SwiftUI struct GroupStagesView: View { - @Environment(Tournament.self) var tournament: Tournament - @State private var selectedGroupStageIndex: Int = -1 - @State private var startAllGroupStageConfirmation: Bool = false - @State private var confirmGroupStageRebuild: Bool = false + var tournament: Tournament + @State private var selectedGroupStage: GroupStage? - func displayGroupStage(_ groupStage: GroupStage) -> Bool { - selectedGroupStageIndex == groupStage.index || selectedGroupStageIndex == -1 + init(tournament: Tournament) { + self.tournament = tournament + _selectedGroupStage = State(wrappedValue: tournament.getActiveGroupStage()) } - - var dynamicTitle: String { - switch selectedGroupStageIndex { - case -1: - return "Toutes les poules" - default: - return tournament.groupStages()[selectedGroupStageIndex].groupStageTitle() - } - } -// -// init(tournament: Tournament) { -// _tournament = ObservedObject(wrappedValue: tournament) -// if let index = tournament.orderedGroupStages.firstIndex(where: { $0.isRunning }) { -// _selectedGroupStageIndex = State(wrappedValue: index.int64Value + 1) -// } -// } - - var body: some View { - List { - if tournament.missingQualifiedFromGroupStages().isEmpty == false && tournament.qualifiedTeams().count >= tournament.qualifiedFromGroupStage() && tournament.groupStageAdditionalQualified > 0 { - NavigationLink { - //DrawView(tournament: tournament) - } label: { - LabeledContent { - Text(tournament.moreQualifiedToDraw().formatted() + "/" + tournament.groupStageAdditionalQualified.formatted()) - } label: { - Text("Qualifié\(tournament.groupStageAdditionalQualified.pluralSuffix) supplémentaire\(tournament.groupStageAdditionalQualified.pluralSuffix)") - let message = [tournament.groupStageAdditionalQualified.formatted(), " meilleur", tournament.groupStageAdditionalQualified.pluralSuffix, " ", (tournament.qualifiedPerGroupStage + 1).ordinalFormatted()].joined() - Text(message) - } - } - } - -// if (tournament.groupStagesAreWrong || (tournament.emptySlotInGroupStages > 0 && tournament.entriesCount >= tournament.teamsFromGroupStages)) { -// Section { -// RowButtonView(title: "Reconstruire les poules") { -// confirmGroupStageRebuild = true -// } -// .modify { -// if UIDevice.current.userInterfaceIdiom == .pad { -// $0.alert("Êtes-vous sûr ?", isPresented: $confirmGroupStageRebuild) { -// -// Button(role: .destructive) { -// tournament.refreshGroupStages() -// save() -// } label: { -// Text("Reconstruire") -// } -// -// -// Button(role: .cancel) { -// -// } label: { -// Text("Annuler") -// } -// } message: { -// Text("Attention, cela peut modifier les poules existants.") -// -// } -// } else { -// $0.confirmationDialog("Êtes-vous sûr ?", isPresented: $confirmGroupStageRebuild) { -// Button(role: .destructive) { -// tournament.refreshGroupStages() -// save() -// } label: { -// Text("Reconstruire") -// } -// } message: { -// Text("Attention, cela peut modifier les poules existants.") -// } -// } -// } -// } header: { -// Text("Erreur détectée") -// } -// } -// -// if tournament.isRoundSwissTournament() == false && (tournament.orderedGroupStages.allSatisfy({ $0.orderedMatches.count > 0 }) == false && tournament.groupStagesAreOver == false && tournament.groupStagesCount > 0) { -// Section { -// RowButtonView(title: "Générer les matchs de poules") { -// startAllGroupStageConfirmation = true -// } -// .modify { -// if UIDevice.current.userInterfaceIdiom == .pad { -// $0.alert("Êtes-vous sûr ?", isPresented: $startAllGroupStageConfirmation) { -// Button("Générer") { -// tournament.orderedGroupStages.forEach { -// if $0.orderedMatches.isEmpty { -// $0.startGroupStage() -// } -// } -// save() -// } -// Button(role: .cancel) { -// -// } label: { -// Text("Annuler") -// } -// } -// -// } else { -// $0.confirmationDialog("Êtes-vous sûr ?", isPresented: $startAllGroupStageConfirmation) { -// Button("Générer") { -// tournament.orderedGroupStages.forEach { -// if $0.orderedMatches.isEmpty { -// $0.startGroupStage() -// } -// } -// save() -// } -// } -// } -// } -// } -// } -// - if tournament.groupStagesAreOver() == false { -// Section { -// GroupStageMatchAvailableToStartView(tournament: tournament, groupStageIndex: selectedGroupStageIndex) -// } header: { -// if selectedGroupStageIndex == -1 { -// Text("Matchs de poules prêt à démarrer") -// } else { -// Text("Matchs de la poule \(selectedGroupStageIndex) prêt à démarrer") -// } -// } footer: { -// Text("présence d'au moins 2 équipes d'une même poule ayant réglé.") -// } - } - -// if tournament.teamsPerGroupStage == 3 && tournament.qualifiedPerGroupStage == 1 && tournament.numberOfGroupStages%2 == 0 && tournament.moreQualifiedFromGroupStages == 0 { -// Section { -// NavigationLink { -// GroupStageMissingMatchView(tournament: tournament) -// } label: { -// Text("Matchs de classement de poules") -// } -// } -// } - - ForEach(tournament.groupStages()) { groupStage in - if displayGroupStage(groupStage) && groupStage.hasEnded() == false { - GroupStageView(groupStage: groupStage) - if groupStage.matches.isEmpty == false { - Section { - ForEach(groupStage.matches) { match in - MatchRowView(match: match, setupSeedContext: false, matchViewStyle: .sectionedStandardStyle) - } - } header: { - Text("Matchs de la " + groupStage.groupStageTitle()) - } - } - } + var body: some View { + VStack(spacing: 0) { + GenericDestinationPickerView(selectedDestination: $selectedGroupStage, destinations: tournament.groupStages()) + switch selectedGroupStage { + case .none: + GroupStageSettingsView() + .navigationTitle("Réglages") + case .some(let groupStage): + GroupStageView(groupStage: groupStage) + .navigationTitle(groupStage.groupStageTitle()) } } + .navigationBarTitleDisplayMode(.inline) + .toolbarBackground(.visible, for: .navigationBar) .toolbar { - ToolbarItem(placement: .principal) { - if tournament.groupStages().count < 6 { - Picker(selection: $selectedGroupStageIndex) { - Text("Toutes").tag(-1) - ForEach(tournament.groupStages()) { groupStage in - Text(groupStage.groupStageTitle(.short)).tag(groupStage.index) - } - } label: { - - } - .labelsHidden() - .pickerStyle(.segmented) - } else if tournament.groupStages().count < 8 { - Picker(selection: $selectedGroupStageIndex) { - Image(systemName: "square.stack").tag(-1) - ForEach(tournament.groupStages()) { groupStage in - Text(groupStage.groupStageTitle(.short)).tag(groupStage.index) - } - } label: { - - } - .labelsHidden() - .pickerStyle(.segmented) - } else { - Picker(selection: $selectedGroupStageIndex) { - Text("Voir toutes les poules").tag(-1) - ForEach(tournament.groupStages()) { groupStage in - Text(groupStage.groupStageTitle()).tag(groupStage.index) - } - } label: { - Text("\(tournament.groupStages().count.formatted()) poules") - } - } - } - ToolbarItem(placement: .topBarTrailing) { Menu { // menuAddGroupStage diff --git a/PadelClub/Views/Round/RoundSettingsView.swift b/PadelClub/Views/Round/RoundSettingsView.swift new file mode 100644 index 0000000..3b40592 --- /dev/null +++ b/PadelClub/Views/Round/RoundSettingsView.swift @@ -0,0 +1,22 @@ +// +// RoundSettingsView.swift +// PadelClub +// +// Created by Razmig Sarkissian on 31/03/2024. +// + +import SwiftUI + +struct RoundSettingsView: View { + @Environment(Tournament.self) var tournament: Tournament + + var body: some View { + List { + } + } +} + +#Preview { + RoundSettingsView() + .environment(Tournament.mock()) +} diff --git a/PadelClub/Views/Round/RoundsView.swift b/PadelClub/Views/Round/RoundsView.swift index 4787023..a1f1af5 100644 --- a/PadelClub/Views/Round/RoundsView.swift +++ b/PadelClub/Views/Round/RoundsView.swift @@ -7,52 +7,6 @@ import SwiftUI -protocol Selectable { - func selectionLabel() -> String -} - -extension Round: Selectable { - func selectionLabel() -> String { - roundTitle() - } -} - -struct GenericDestinationPickerView: View { - @Binding var selectedDestination: T? - let destinations: [T] - - var body: some View { - ScrollView(.horizontal) { - HStack { - ForEach(destinations) { destination in - Button { - selectedDestination = destination - } label: { - Text(destination.selectionLabel()) - } - .padding() - .background { - Capsule() - .fill(Color.white) - .opacity(selectedDestination?.id == destination.id ? 1.0 : 0.5) - } - .buttonStyle(.plain) - } - } - .fixedSize() - .padding(8) - } - .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) - .background(Material.ultraThinMaterial) - .overlay { - VStack(spacing: 0) { - Spacer() - Divider() - } - } - } -} - struct RoundsView: View { var tournament: Tournament @State private var selectedRound: Round? @@ -65,11 +19,15 @@ struct RoundsView: View { var body: some View { VStack(spacing: 0) { GenericDestinationPickerView(selectedDestination: $selectedRound, destinations: tournament.rounds()) - if let selectedRound { + switch selectedRound { + case .none: + RoundSettingsView() + .navigationTitle("Réglages") + case .some(let selectedRound): RoundView(round: selectedRound) + .navigationTitle(selectedRound.roundTitle()) } } - .navigationTitle(selectedRound?.roundTitle() ?? "") .navigationBarTitleDisplayMode(.inline) .toolbarBackground(.visible, for: .navigationBar) } diff --git a/PadelClub/Views/Tournament/TournamentView.swift b/PadelClub/Views/Tournament/TournamentView.swift index 43fe7c6..7d219e0 100644 --- a/PadelClub/Views/Tournament/TournamentView.swift +++ b/PadelClub/Views/Tournament/TournamentView.swift @@ -75,7 +75,7 @@ struct TournamentView: View { case .inscription: InscriptionManagerView(tournament: tournament) case .groupStage: - GroupStagesView() + GroupStagesView(tournament: tournament) case .round: RoundsView(tournament: tournament) }