fix calling views

paca_championship
Raz 1 year ago
parent 7c3725ce5b
commit f174ccfe57
  1. 8
      PadelClub.xcodeproj/project.pbxproj
  2. 24
      PadelClub/Views/Calling/BracketCallingView.swift
  3. 13
      PadelClub/Views/Calling/GroupStageCallingView.swift
  4. 23
      PadelClub/Views/Calling/SeedsCallingView.swift
  5. 43
      PadelClub/Views/Calling/TeamsCallingView.swift
  6. 6
      PadelClub/Views/Match/Components/MatchTeamDetailView.swift
  7. 56
      PadelClub/Views/Team/CoachListView.swift
  8. 4
      PadelClub/Views/Team/EditingTeamView.swift
  9. 38
      PadelClub/Views/Tournament/FileImportView.swift

@ -90,6 +90,9 @@
FF17CA532CBE4788003C7323 /* BracketCallingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF17CA522CBE4788003C7323 /* BracketCallingView.swift */; }; FF17CA532CBE4788003C7323 /* BracketCallingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF17CA522CBE4788003C7323 /* BracketCallingView.swift */; };
FF17CA542CBE4788003C7323 /* BracketCallingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF17CA522CBE4788003C7323 /* BracketCallingView.swift */; }; FF17CA542CBE4788003C7323 /* BracketCallingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF17CA522CBE4788003C7323 /* BracketCallingView.swift */; };
FF17CA552CBE4788003C7323 /* BracketCallingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF17CA522CBE4788003C7323 /* BracketCallingView.swift */; }; FF17CA552CBE4788003C7323 /* BracketCallingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF17CA522CBE4788003C7323 /* BracketCallingView.swift */; };
FF17CA572CC02FEA003C7323 /* CoachListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF17CA562CC02FEA003C7323 /* CoachListView.swift */; };
FF17CA582CC02FEB003C7323 /* CoachListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF17CA562CC02FEA003C7323 /* CoachListView.swift */; };
FF17CA592CC02FEB003C7323 /* CoachListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF17CA562CC02FEA003C7323 /* CoachListView.swift */; };
FF1CBC1B2BB53D1F0036DAAB /* FederalTournament.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC182BB53D1F0036DAAB /* FederalTournament.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 */; }; FF1CBC1D2BB53DC10036DAAB /* Calendar+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC1C2BB53DC10036DAAB /* Calendar+Extensions.swift */; };
FF1CBC1F2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC1E2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift */; }; FF1CBC1F2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1CBC1E2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift */; };
@ -989,6 +992,7 @@
FF17CA482CB915A1003C7323 /* MultiCourtPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiCourtPickerView.swift; sourceTree = "<group>"; }; FF17CA482CB915A1003C7323 /* MultiCourtPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiCourtPickerView.swift; sourceTree = "<group>"; };
FF17CA4C2CB9243E003C7323 /* FollowUpMatchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowUpMatchView.swift; sourceTree = "<group>"; }; FF17CA4C2CB9243E003C7323 /* FollowUpMatchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowUpMatchView.swift; sourceTree = "<group>"; };
FF17CA522CBE4788003C7323 /* BracketCallingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BracketCallingView.swift; sourceTree = "<group>"; }; FF17CA522CBE4788003C7323 /* BracketCallingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BracketCallingView.swift; sourceTree = "<group>"; };
FF17CA562CC02FEA003C7323 /* CoachListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoachListView.swift; sourceTree = "<group>"; };
FF1CBC182BB53D1F0036DAAB /* FederalTournament.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FederalTournament.swift; sourceTree = "<group>"; }; FF1CBC182BB53D1F0036DAAB /* FederalTournament.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FederalTournament.swift; sourceTree = "<group>"; };
FF1CBC1C2BB53DC10036DAAB /* Calendar+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Calendar+Extensions.swift"; sourceTree = "<group>"; }; FF1CBC1C2BB53DC10036DAAB /* Calendar+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Calendar+Extensions.swift"; sourceTree = "<group>"; };
FF1CBC1E2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FederalTournamentSearchScope.swift; sourceTree = "<group>"; }; FF1CBC1E2BB53E0C0036DAAB /* FederalTournamentSearchScope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FederalTournamentSearchScope.swift; sourceTree = "<group>"; };
@ -1815,6 +1819,7 @@
FF967D0A2BAF3D4C00A9A3BD /* TeamPickerView.swift */, FF967D0A2BAF3D4C00A9A3BD /* TeamPickerView.swift */,
FF089EB52BB00A3800F0AEC7 /* TeamRowView.swift */, FF089EB52BB00A3800F0AEC7 /* TeamRowView.swift */,
FF1162862BD004AD000C4809 /* EditingTeamView.swift */, FF1162862BD004AD000C4809 /* EditingTeamView.swift */,
FF17CA562CC02FEA003C7323 /* CoachListView.swift */,
FF025AD62BD0C0FB00A86CF8 /* Components */, FF025AD62BD0C0FB00A86CF8 /* Components */,
); );
path = Team; path = Team;
@ -2412,6 +2417,7 @@
C49EF01B2BD6A1E80077B5AA /* URLs.swift in Sources */, C49EF01B2BD6A1E80077B5AA /* URLs.swift in Sources */,
FFCFC0142BBC59FC00B82851 /* MatchDescriptor.swift in Sources */, FFCFC0142BBC59FC00B82851 /* MatchDescriptor.swift in Sources */,
FF8F264C2BAE0B4100650388 /* TournamentFormatSelectionView.swift in Sources */, FF8F264C2BAE0B4100650388 /* TournamentFormatSelectionView.swift in Sources */,
FF17CA572CC02FEA003C7323 /* CoachListView.swift in Sources */,
FFBF065E2BBD8040009D6715 /* MatchListView.swift in Sources */, FFBF065E2BBD8040009D6715 /* MatchListView.swift in Sources */,
C425D4012B6D249D002A7B48 /* PadelClubApp.swift in Sources */, C425D4012B6D249D002A7B48 /* PadelClubApp.swift in Sources */,
FF8F26432BADFE5B00650388 /* TournamentSettingsView.swift in Sources */, FF8F26432BADFE5B00650388 /* TournamentSettingsView.swift in Sources */,
@ -2684,6 +2690,7 @@
FF4CBFF02C996C0600151637 /* URLs.swift in Sources */, FF4CBFF02C996C0600151637 /* URLs.swift in Sources */,
FF4CBFF12C996C0600151637 /* MatchDescriptor.swift in Sources */, FF4CBFF12C996C0600151637 /* MatchDescriptor.swift in Sources */,
FF4CBFF22C996C0600151637 /* TournamentFormatSelectionView.swift in Sources */, FF4CBFF22C996C0600151637 /* TournamentFormatSelectionView.swift in Sources */,
FF17CA592CC02FEB003C7323 /* CoachListView.swift in Sources */,
FF4CBFF32C996C0600151637 /* MatchListView.swift in Sources */, FF4CBFF32C996C0600151637 /* MatchListView.swift in Sources */,
FF4CBFF42C996C0600151637 /* PadelClubApp.swift in Sources */, FF4CBFF42C996C0600151637 /* PadelClubApp.swift in Sources */,
FF4CBFF52C996C0600151637 /* TournamentSettingsView.swift in Sources */, FF4CBFF52C996C0600151637 /* TournamentSettingsView.swift in Sources */,
@ -2935,6 +2942,7 @@
FF70FB6F2C90584900129CC2 /* URLs.swift in Sources */, FF70FB6F2C90584900129CC2 /* URLs.swift in Sources */,
FF70FB702C90584900129CC2 /* MatchDescriptor.swift in Sources */, FF70FB702C90584900129CC2 /* MatchDescriptor.swift in Sources */,
FF70FB712C90584900129CC2 /* TournamentFormatSelectionView.swift in Sources */, FF70FB712C90584900129CC2 /* TournamentFormatSelectionView.swift in Sources */,
FF17CA582CC02FEB003C7323 /* CoachListView.swift in Sources */,
FF70FB722C90584900129CC2 /* MatchListView.swift in Sources */, FF70FB722C90584900129CC2 /* MatchListView.swift in Sources */,
FF70FB732C90584900129CC2 /* PadelClubApp.swift in Sources */, FF70FB732C90584900129CC2 /* PadelClubApp.swift in Sources */,
FF70FB742C90584900129CC2 /* TournamentSettingsView.swift in Sources */, FF70FB742C90584900129CC2 /* TournamentSettingsView.swift in Sources */,

@ -60,11 +60,14 @@ struct BracketCallingView: View {
var body: some View { var body: some View {
List { List {
NavigationLink { let uncalledTeams = teams.filter({ $0.callDate == nil })
TeamsCallingView(teams: teams.filter({ $0.callDate == nil })) if uncalledTeams.isEmpty == false {
.environment(tournament) NavigationLink {
} label: { TeamsCallingView(teams: uncalledTeams)
LabeledContent("Équipes non contactées", value: teams.filter({ $0.callDate == nil }).count.formatted()) .environment(tournament)
} label: {
LabeledContent("Équipe\(uncalledTeams.count.pluralSuffix) non contactée\(uncalledTeams.count.pluralSuffix)", value: uncalledTeams.count.formatted())
}
} }
PlayersWithoutContactView(players: teams.flatMap({ $0.unsortedPlayers() }).sorted(by: \.computedRank)) PlayersWithoutContactView(players: teams.flatMap({ $0.unsortedPlayers() }).sorted(by: \.computedRank))
@ -119,8 +122,15 @@ struct BracketCallingView: View {
@ViewBuilder @ViewBuilder
private func _roundView(round: Round, seeds: [TeamRegistration]) -> some View { private func _roundView(round: Round, seeds: [TeamRegistration]) -> some View {
List { List {
NavigationLink("Équipes non contactées") {
TeamsCallingView(teams: seeds.filter({ $0.callDate == nil })) let uncalledTeams = seeds.filter({ $0.callDate == nil })
if uncalledTeams.isEmpty == false {
NavigationLink {
TeamsCallingView(teams: uncalledTeams)
.environment(tournament)
} label: {
LabeledContent("Équipe\(uncalledTeams.count.pluralSuffix) non contactée\(uncalledTeams.count.pluralSuffix)", value: uncalledTeams.count.formatted())
}
} }
let startDate = round.startDate ?? round.playedMatches().first?.startDate let startDate = round.startDate ?? round.playedMatches().first?.startDate

@ -15,11 +15,14 @@ struct GroupStageCallingView: View {
let groupStages = tournament.groupStages() let groupStages = tournament.groupStages()
List { List {
NavigationLink { let uncalled = groupStages.flatMap({ $0.unsortedTeams() }).filter({ $0.callDate == nil })
TeamsCallingView(teams: groupStages.flatMap({ $0.unsortedTeams() }).filter({ $0.callDate == nil })) if uncalled.isEmpty == false {
.environment(tournament) NavigationLink {
} label: { TeamsCallingView(teams: uncalled)
LabeledContent("Équipes non contactées", value: groupStages.flatMap({ $0.unsortedTeams() }).filter({ $0.callDate == nil }).count.formatted()) .environment(tournament)
} label: {
LabeledContent("Équipe\(uncalled.count.pluralSuffix) non contactée\(uncalled.count.pluralSuffix)", value: uncalled.count.formatted())
}
} }
PlayersWithoutContactView(players: groupStages.flatMap({ $0.unsortedTeams() }).flatMap({ $0.unsortedPlayers() }).sorted(by: \.computedRank)) PlayersWithoutContactView(players: groupStages.flatMap({ $0.unsortedTeams() }).flatMap({ $0.unsortedPlayers() }).sorted(by: \.computedRank))

@ -14,12 +14,15 @@ struct SeedsCallingView: View {
var body: some View { var body: some View {
List { List {
let tournamentRounds = tournament.rounds() let tournamentRounds = tournament.rounds()
let uncalledSeeds = tournament.seededTeams().filter({ $0.callDate == nil })
NavigationLink { if uncalledSeeds.isEmpty == false {
TeamsCallingView(teams: tournament.seededTeams().filter({ $0.callDate == nil })) NavigationLink {
.environment(tournament) TeamsCallingView(teams: uncalledSeeds)
} label: { .environment(tournament)
LabeledContent("Équipes non contactées", value: tournament.seededTeams().filter({ $0.callDate == nil }).count.formatted()) } label: {
LabeledContent("Équipe\(uncalledSeeds.count.pluralSuffix) non contactée\(uncalledSeeds.count.pluralSuffix)", value: uncalledSeeds.count.formatted())
}
} }
PlayersWithoutContactView(players: tournament.seededTeams().flatMap({ $0.unsortedPlayers() }).sorted(by: \.computedRank)) PlayersWithoutContactView(players: tournament.seededTeams().flatMap({ $0.unsortedPlayers() }).sorted(by: \.computedRank))
@ -63,8 +66,14 @@ struct SeedsCallingView: View {
} }
} }
NavigationLink("Équipes non contactées") { let uncalledTeams = round.teams().filter({ $0.callDate == nil })
TeamsCallingView(teams: round.teams().filter({ $0.callDate == nil })) if uncalledTeams.isEmpty == false {
NavigationLink {
TeamsCallingView(teams: uncalledTeams)
.environment(tournament)
} label: {
LabeledContent("Équipe\(uncalledTeams.count.pluralSuffix) non contactée\(uncalledTeams.count.pluralSuffix)", value: uncalledTeams.count.formatted())
}
} }

@ -21,31 +21,34 @@ struct TeamsCallingView: View {
let label = "\(justCalled.count.formatted()) / \(teams.count.formatted()) convoquées (dont \(called.count.formatted()) au bon horaire)" let label = "\(justCalled.count.formatted()) / \(teams.count.formatted()) convoquées (dont \(called.count.formatted()) au bon horaire)"
Text(label) if teams.isEmpty == false {
Section {
Text(label)
} footer: {
Text("Vous pouvez indiquer si une équipe vous a confirmé sa convocation en appuyant sur 􀍡")
}
Section { Section {
ForEach(teams) { team in ForEach(teams) { team in
Menu { Menu {
_menuOptions(team: team) _menuOptions(team: team)
} label: { } label: {
HStack { HStack {
TeamRowView(team: team, displayCallDate: true) TeamRowView(team: team, displayCallDate: true)
Spacer() Spacer()
Menu { Menu {
_menuOptions(team: team) _menuOptions(team: team)
} label: { } label: {
LabelOptions().labelStyle(.iconOnly) LabelOptions().labelStyle(.iconOnly)
}
} }
} }
.buttonStyle(.plain)
.listRowView(isActive: team.confirmed(), color: .green, hideColorVariation: true)
} }
.buttonStyle(.plain)
.listRowView(isActive: team.confirmed(), color: .green, hideColorVariation: true)
}
} footer: {
HStack {
Text("Vous pouvez indiquer si une équipe vous a confirmé sa convocation en appuyant sur ")
Image(systemName: "ellipsis.circle").font(.footnote)
} }
} else {
ContentUnavailableView("Aucune équipe", systemImage: "person.2.slash")
} }
} }
.headerProminence(.increased) .headerProminence(.increased)

@ -31,9 +31,15 @@ struct MatchTeamDetailView: View {
@ViewBuilder @ViewBuilder
private func _teamDetailView(_ team: TeamRegistration, inTournament tournament: Tournament?) -> some View { private func _teamDetailView(_ team: TeamRegistration, inTournament tournament: Tournament?) -> some View {
Section { Section {
if let teamName = team.name, teamName.isEmpty == false {
Text(teamName).foregroundStyle(.secondary).font(.footnote)
}
ForEach(team.players()) { player in ForEach(team.players()) { player in
EditablePlayerView(player: player, editingOptions: _editingOptions()) EditablePlayerView(player: player, editingOptions: _editingOptions())
} }
if let coachList = team.comment, coachList.isEmpty == false {
Text("Coachs : " + coachList).foregroundStyle(.secondary).font(.footnote)
}
} header: { } header: {
TeamHeaderView(team: team, teamIndex: tournament?.indexOf(team: team)) TeamHeaderView(team: team, teamIndex: tournament?.indexOf(team: team))
} }

@ -0,0 +1,56 @@
//
// CoachListView.swift
// PadelClub
//
// Created by razmig on 16/10/2024.
//
import SwiftUI
import LeStorage
struct CoachListView: View {
@Environment(Tournament.self) var tournament
@State private var coachNames: String
var team: TeamRegistration
init(team: TeamRegistration) {
self.team = team
_coachNames = .init(wrappedValue: team.comment ?? "")
}
var body: some View {
Section {
TextField("Coach", text: $coachNames)
.autocorrectionDisabled()
.keyboardType(.alphabet)
.frame(maxWidth: .infinity)
.submitLabel(.done)
.onSubmit(of: .text) {
let trimmed = coachNames.trimmed
if trimmed.isEmpty {
team.comment = nil
} else {
team.comment = trimmed
}
_save()
}
} header: {
Text("Coachs")
} footer: {
FooterButtonView("effacer") {
coachNames = ""
team.comment = nil
_save()
}
}
}
private func _save() {
do {
try self.tournament.tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch {
Logger.error(error)
}
}
}

@ -164,6 +164,10 @@ struct EditingTeamView: View {
Text("Nom de l'équipe") Text("Nom de l'équipe")
} }
if tournament.tournamentLevel.coachingIsAuthorized {
CoachListView(team: team)
}
Section { Section {
RowButtonView("Retirer des poules", role: .destructive) { RowButtonView("Retirer des poules", role: .destructive) {
team.resetGroupeStagePosition() team.resetGroupeStagePosition()

@ -84,11 +84,21 @@ struct FileImportView: View {
@State private var multiImport: Bool = false @State private var multiImport: Bool = false
@State private var presentFormatHelperView: Bool = false @State private var presentFormatHelperView: Bool = false
@State private var validatedTournamentIds: Set<String> = Set() @State private var validatedTournamentIds: Set<String> = Set()
@State private var chunkByParameter: Bool = true @State private var chunkMode: ChunkMode = .byParameter
enum ChunkMode { enum ChunkMode: Int, Identifiable, CaseIterable {
var id: Int { self.rawValue }
case byParameter case byParameter
case byCoupleOfLines case byCoupleOfLines
func localizedChunkModeLabel() -> String {
switch self {
case .byParameter:
return "Nom d'équipe"
case .byCoupleOfLines:
return "Groupe de 2 lignes"
}
}
} }
init(defaultFileProvider: FileImportManager.FileProvider = .frenchFederation) { init(defaultFileProvider: FileImportManager.FileProvider = .frenchFederation) {
@ -99,6 +109,10 @@ struct FileImportView: View {
return self.tournament.tournamentStore return self.tournament.tournamentStore
} }
var chunkByParameter: Bool {
return chunkMode == .byParameter
}
private func filteredTeams(tournament: Tournament) -> [FileImportManager.TeamHolder] { private func filteredTeams(tournament: Tournament) -> [FileImportManager.TeamHolder] {
if tournament.isAnimation() { if tournament.isAnimation() {
return teams.sorted(by: \.weight) return teams.sorted(by: \.weight)
@ -146,14 +160,7 @@ struct FileImportView: View {
} }
if fileProvider == .custom || fileProvider == .customAutoSearch { if fileProvider == .custom || fileProvider == .customAutoSearch {
Toggle(isOn: $chunkByParameter) { _chunkModePickerView()
Text("Détection des équipes")
if chunkByParameter {
Text("via le nom de l'équipe")
} else {
Text("couple de deux lignes")
}
}
} }
RowButtonView("Démarrer l'importation") { RowButtonView("Démarrer l'importation") {
@ -595,6 +602,17 @@ struct FileImportView: View {
Logger.error(error) Logger.error(error)
} }
} }
private func _chunkModePickerView() -> some View {
Picker(selection: $chunkMode) {
ForEach(ChunkMode.allCases) { mode in
Text(mode.localizedChunkModeLabel()).tag(mode)
}
} label: {
Text("Détection des équipes")
}
}
} }
//#Preview { //#Preview {

Loading…
Cancel
Save