From a51adc6bbe0b6a9a01aefd9f1c21499430d1b4cb Mon Sep 17 00:00:00 2001 From: Raz Date: Fri, 18 Oct 2024 10:38:46 +0200 Subject: [PATCH] add QoL features on summoning screen --- PadelClub/Utils/DisplayContext.swift | 5 + .../Views/Calling/BracketCallingView.swift | 4 +- PadelClub/Views/Calling/CallView.swift | 128 +++++++++++++---- .../Views/Calling/GroupStageCallingView.swift | 2 +- .../Views/Calling/SeedsCallingView.swift | 2 +- .../Views/Calling/TeamsCallingView.swift | 130 +++++++++--------- .../Components/InscriptionInfoView.swift | 9 +- 7 files changed, 177 insertions(+), 103 deletions(-) diff --git a/PadelClub/Utils/DisplayContext.swift b/PadelClub/Utils/DisplayContext.swift index 71786af..7eafd7d 100644 --- a/PadelClub/Utils/DisplayContext.swift +++ b/PadelClub/Utils/DisplayContext.swift @@ -21,6 +21,11 @@ enum DisplayStyle { case short } +enum SummoningDisplayContext { + case footer + case menu +} + enum MatchViewStyle { case standardStyle // vue normal case sectionedStandardStyle // vue normal avec des sections indiquant déjà la manche diff --git a/PadelClub/Views/Calling/BracketCallingView.swift b/PadelClub/Views/Calling/BracketCallingView.swift index 2c20386..810919e 100644 --- a/PadelClub/Views/Calling/BracketCallingView.swift +++ b/PadelClub/Views/Calling/BracketCallingView.swift @@ -162,7 +162,7 @@ struct BracketCallingView: View { if badCalled.isEmpty == false { Section { ForEach(badCalled) { team in - CallView.TeamView(team: team) + TeamCallView(team: team) } } header: { HStack { @@ -179,7 +179,7 @@ struct BracketCallingView: View { Section { ForEach(seeds) { team in - CallView.TeamView(team: team) + TeamCallView(team: team) } } header: { HStack { diff --git a/PadelClub/Views/Calling/CallView.swift b/PadelClub/Views/Calling/CallView.swift index 514da7f..85fb5cb 100644 --- a/PadelClub/Views/Calling/CallView.swift +++ b/PadelClub/Views/Calling/CallView.swift @@ -41,14 +41,6 @@ struct CallView: View { } } - struct TeamView: View { - let team: TeamRegistration - - var body: some View { - TeamRowView(team: team, displayCallDate: true) - } - } - @EnvironmentObject var dataStore: DataStore @EnvironmentObject var networkMonitor: NetworkMonitor @@ -58,6 +50,7 @@ struct CallView: View { let callDate: Date let matchFormat: MatchFormat let roundLabel: String + let displayContext: SummoningDisplayContext @State private var contactType: ContactType? = nil @State private var sentError: ContactManagerError? = nil @@ -76,6 +69,7 @@ struct CallView: View { self.matchFormat = matchFormat self.roundLabel = roundLabel self.simpleMode = false + self.displayContext = .footer } init(teams: [TeamRegistration]) { @@ -84,6 +78,30 @@ struct CallView: View { self.matchFormat = MatchFormat.nineGames self.roundLabel = "" self.simpleMode = true + self.displayContext = .footer + } + + init(team: TeamRegistration, displayContext: SummoningDisplayContext) { + self.teams = [team] + let expectedSummonDate = team.expectedSummonDate() + self.displayContext = displayContext + + if let expectedSummonDate, let initialMatch = team.initialMatch() { + self.callDate = expectedSummonDate + self.matchFormat = initialMatch.matchFormat + self.roundLabel = initialMatch.roundTitle() ?? "tableau" + self.simpleMode = false + } else if let expectedSummonDate, let initialGroupStage = team.groupStageObject() { + self.callDate = expectedSummonDate + self.matchFormat = initialGroupStage.matchFormat + self.roundLabel = "poule" + self.simpleMode = false + } else { + self.callDate = Date() + self.matchFormat = MatchFormat.nineGames + self.roundLabel = "" + self.simpleMode = true + } } var tournamentStore: TournamentStore { @@ -107,6 +125,9 @@ struct CallView: View { if success { calledTeams.forEach { team in team.callDate = callDate + if reSummon { + team.confirmationDate = nil + } } do { try self.tournamentStore.teamRegistrations.addOrUpdate(contentOfs: calledTeams) @@ -141,28 +162,14 @@ struct CallView: View { } var body: some View { - let callWord : String = (reSummon ? "Reconvoquer" : mainWord) - HStack { - if self.teams.count == 1 { - if simpleMode { - Text("\(callWord) cette paire par") - } else { - if let previousCallDate = teams.first?.callDate, Calendar.current.compare(previousCallDate, to: callDate, toGranularity: .minute) != .orderedSame { - Text("Reconvoquer \(self.callDate.localizedDate()) par") - } else { - Text("\(callWord) cette paire par") - } - } - } else { - Text("\(callWord) ces \(self.teams.count) paires par") + Group { + switch displayContext { + case .footer: + _footerStyleView() + case .menu: + _menuStyleView() } - - self._summonMenu(byMessage: true) - Text("ou") - self._summonMenu(byMessage: false) } - .font(.subheadline) - .buttonStyle(.borderless) .alert("Un problème est survenu", isPresented: messageSentFailed) { Button("OK") { } @@ -258,6 +265,54 @@ struct CallView: View { } }) } + + private func _footerStyleView() -> some View { + HStack { + let callWord : String = (reSummon ? "Reconvoquer" : mainWord) + if self.teams.count == 1 { + if simpleMode { + Text("\(callWord) cette paire par") + } else { + if let previousCallDate = teams.first?.callDate, Calendar.current.compare(previousCallDate, to: callDate, toGranularity: .minute) != .orderedSame { + Text("Reconvoquer \(self.callDate.localizedDate()) par") + } else { + Text("\(callWord) cette paire par") + } + } + } else { + Text("\(callWord) ces \(self.teams.count) paires par") + } + + self._summonMenu(byMessage: true) + Text("ou") + self._summonMenu(byMessage: false) + } + .font(.subheadline) + .buttonStyle(.borderless) + } + + private func _menuStyleView() -> some View { + Menu { + self._summonMenu(byMessage: true) + self._summonMenu(byMessage: false) + } label: { + let callWord : String = (reSummon ? "Reconvoquer" : mainWord) + if self.teams.count == 1 { + if simpleMode { + Text("\(callWord) cette paire") + } else { + if let previousCallDate = teams.first?.callDate, Calendar.current.compare(previousCallDate, to: callDate, toGranularity: .minute) != .orderedSame { + Text("Reconvoquer \(self.callDate.localizedDate())") + } else { + Text("\(callWord) cette paire") + } + } + } else { + Text("\(callWord) ces \(self.teams.count) paires") + } + } + } + @ViewBuilder private func _summonMenu(byMessage: Bool) -> some View { @@ -334,3 +389,20 @@ struct CallView: View { } } + +struct TeamCallView: View { + @Environment(Tournament.self) var tournament: Tournament + let team: TeamRegistration + var action: (() -> Void)? + + var body: some View { + NavigationLink { + CallMenuOptionsView(team: team, action: action) + .environment(tournament) + } label: { + TeamRowView(team: team, displayCallDate: true) + } + .buttonStyle(.plain) + .listRowView(isActive: team.confirmed(), color: .green, hideColorVariation: true) + } +} diff --git a/PadelClub/Views/Calling/GroupStageCallingView.swift b/PadelClub/Views/Calling/GroupStageCallingView.swift index 6a419e1..cb12cd4 100644 --- a/PadelClub/Views/Calling/GroupStageCallingView.swift +++ b/PadelClub/Views/Calling/GroupStageCallingView.swift @@ -86,7 +86,7 @@ struct GroupStageCallingView: View { ForEach(teams) { team in if let startDate = groupStage.initialStartDate(forTeam: team) { Section { - CallView.TeamView(team: team) + TeamCallView(team: team) } header: { Text(startDate.localizedDate()) } footer: { diff --git a/PadelClub/Views/Calling/SeedsCallingView.swift b/PadelClub/Views/Calling/SeedsCallingView.swift index 452bd9d..e7c015d 100644 --- a/PadelClub/Views/Calling/SeedsCallingView.swift +++ b/PadelClub/Views/Calling/SeedsCallingView.swift @@ -101,7 +101,7 @@ struct SeedsCallingView: View { let teams = round.seeds(inMatchIndex: match.index) Section { ForEach(teams) { team in - CallView.TeamView(team: team) + TeamCallView(team: team) } } header: { HStack { diff --git a/PadelClub/Views/Calling/TeamsCallingView.swift b/PadelClub/Views/Calling/TeamsCallingView.swift index 844459d..8a5d1e9 100644 --- a/PadelClub/Views/Calling/TeamsCallingView.swift +++ b/PadelClub/Views/Calling/TeamsCallingView.swift @@ -55,28 +55,16 @@ struct TeamsCallingView: View { Text("Paire\(confirmed.count.pluralSuffix) confirmée\(confirmed.count.pluralSuffix)") } } footer: { - Text("Vous pouvez indiquer si une équipe vous a confirmé sa convocation en appuyant sur ") + Text(Image(systemName: "ellipsis.circle")) + Text("Vous pouvez filtrer cette liste en appuyant sur ") + Text(Image(systemName: "line.3.horizontal.decrease.circle")) } } - if teams.isEmpty == false { + if filteredTeams.isEmpty == false { Section { ForEach(filteredTeams) { team in - Menu { - _menuOptions(team: team) - } label: { - HStack { - TeamRowView(team: team, displayCallDate: true) - Spacer() - Menu { - _menuOptions(team: team) - } label: { - LabelOptions().labelStyle(.iconOnly) - } - } + TeamCallView(team: team) { + searchText = "" } - .buttonStyle(.plain) - .listRowView(isActive: team.confirmed(), color: .green, hideColorVariation: true) } } header: { HStack { @@ -115,63 +103,79 @@ struct TeamsCallingView: View { .navigationBarTitleDisplayMode(.inline) .toolbarBackground(.visible, for: .navigationBar) } +} - @ViewBuilder - func _menuOptions(team: TeamRegistration) -> some View { - Button { +struct CallMenuOptionsView: View { + @Environment(\.dismiss) private var dismiss + @Environment(Tournament.self) var tournament: Tournament + let team: TeamRegistration + let action: (() -> Void)? + + var confirmed: Binding { + Binding { + team.confirmed() + } set: { _ in team.toggleSummonConfirmation() do { try self.tournament.tournamentStore.teamRegistrations.addOrUpdate(instance: team) } catch { Logger.error(error) } - searchText = "" - } label: { - if team.confirmed() { - Label("Confirmation reçue", systemImage: "checkmark.circle.fill").foregroundStyle(.green) - } else { - Label("Confirmation reçue", systemImage: "circle").foregroundStyle(.logoRed) - } + action?() } - - Divider() - - NavigationLink { - EditingTeamView(team: team) - .environment(tournament) - } label: { - Text("Détails de l'équipe") - } - - Divider() - - Button(role: .destructive) { - team.callDate = nil - do { - try self.tournament.tournamentStore.teamRegistrations.addOrUpdate(instance: team) - } catch { - Logger.error(error) + } + + var body: some View { + List { + Section { + TeamRowView(team: team, displayCallDate: true) + Toggle(isOn: confirmed) { + Text("Confirmation reçue") + } + if team.expectedSummonDate() != nil { + CallView(team: team, displayContext: .menu) + } + } footer: { + CallView(teams: [team]) } - searchText = "" - } label: { - Text("Effacer la date de convocation") - } - - - Divider() - - Button(role: .destructive) { - team.callDate = team.initialMatch()?.startDate ?? tournament.startDate - do { - try self.tournament.tournamentStore.teamRegistrations.addOrUpdate(instance: team) - } catch { - Logger.error(error) + + Section { + NavigationLink { + EditingTeamView(team: team) + .environment(tournament) + } label: { + Text("Détails de l'équipe") + } + } + + Section { + RowButtonView("Effacer la date de convocation", role: .destructive) { + team.callDate = nil + do { + try self.tournament.tournamentStore.teamRegistrations.addOrUpdate(instance: team) + } catch { + Logger.error(error) + } + action?() + dismiss() + } + } + + Section { + RowButtonView("Indiquer comme convoquée", role: .destructive) { + team.callDate = team.initialMatch()?.startDate ?? tournament.startDate + do { + try self.tournament.tournamentStore.teamRegistrations.addOrUpdate(instance: team) + } catch { + Logger.error(error) + } + action?() + dismiss() + } } - searchText = "" - } label: { - Text("Indiquer comme convoquée") } - - + .navigationTitle("Options de convocation") + .navigationBarTitleDisplayMode(.inline) + .toolbarBackground(.visible, for: .navigationBar) } } diff --git a/PadelClub/Views/Tournament/Screen/Components/InscriptionInfoView.swift b/PadelClub/Views/Tournament/Screen/Components/InscriptionInfoView.swift index fe03ff1..a52b8c5 100644 --- a/PadelClub/Views/Tournament/Screen/Components/InscriptionInfoView.swift +++ b/PadelClub/Views/Tournament/Screen/Components/InscriptionInfoView.swift @@ -57,14 +57,7 @@ struct InscriptionInfoView: View { Section { DisclosureGroup { ForEach(callDateIssue) { team in - CallView.TeamView(team: team) - if let groupStage = team.groupStageObject(), let callDate = groupStage.startDate { - CallView(teams: [team], callDate: callDate, matchFormat: groupStage.matchFormat, roundLabel: "poule") - } else if let initialRound = team.initialRound(), - let initialMatch = team.initialMatch(), - let callDate = initialMatch.startDate { - CallView(teams: [team], callDate: callDate, matchFormat: initialMatch.matchFormat, roundLabel: initialRound.roundTitle()) - } + TeamCallView(team: team) } } label: { LabeledContent {