From 883a46baea94dda619c0adf757eb0c784c2faad9 Mon Sep 17 00:00:00 2001 From: Raz Date: Fri, 27 Sep 2024 14:18:37 +0200 Subject: [PATCH] fix planning views and match scheduler for groupstages --- PadelClub.xcodeproj/project.pbxproj | 8 ++-- PadelClub/Data/GroupStage.swift | 6 ++- PadelClub/Data/Match.swift | 5 +- PadelClub/Data/MatchScheduler.swift | 31 +++++++------ .../Components/GroupStageTeamView.swift | 10 +++- .../Components/MatchTeamDetailView.swift | 15 +++++- PadelClub/Views/Match/MatchSummaryView.swift | 2 +- .../Views/Planning/PlanningByCourtView.swift | 1 + PadelClub/Views/Planning/PlanningView.swift | 46 ++++++++++++++++++- 9 files changed, 99 insertions(+), 25 deletions(-) diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index 4e3d4c8..f97f18d 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -3134,7 +3134,7 @@ CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 6; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; @@ -3178,7 +3178,7 @@ CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 6; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_TEAM = BQ3Y44M3Q6; @@ -3293,7 +3293,7 @@ CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; @@ -3335,7 +3335,7 @@ CODE_SIGN_ENTITLEMENTS = PadelClub/PadelClub.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\""; DEVELOPMENT_TEAM = BQ3Y44M3Q6; diff --git a/PadelClub/Data/GroupStage.swift b/PadelClub/Data/GroupStage.swift index eadf491..da3e0fe 100644 --- a/PadelClub/Data/GroupStage.swift +++ b/PadelClub/Data/GroupStage.swift @@ -50,7 +50,7 @@ final class GroupStage: ModelObject, Storable { // MARK: - Computed dependencies func _matches() -> [Match] { - return self.tournamentStore.matches.filter { $0.groupStage == self.id } + return self.tournamentStore.matches.filter { $0.groupStage == self.id }.sorted(by: \.index) // Store.main.filter { $0.groupStage == self.id } } @@ -276,6 +276,10 @@ final class GroupStage: ModelObject, Storable { } } + func indexOf(_ matchIndex: Int) -> Int { + _matchOrder().firstIndex(of: matchIndex) ?? matchIndex + } + private func _matchUp(for matchIndex: Int) -> [Int] { Array((0.. [Match] { diff --git a/PadelClub/Data/MatchScheduler.swift b/PadelClub/Data/MatchScheduler.swift index d42973b..69d1011 100644 --- a/PadelClub/Data/MatchScheduler.swift +++ b/PadelClub/Data/MatchScheduler.swift @@ -199,22 +199,24 @@ final class MatchScheduler : ModelObject, Storable { while slots.count < flattenedMatches.count { teamsPerRotation[rotationIndex] = [] freeCourtPerRotation[rotationIndex] = [] + let previousRotationBracketIndexes = slots.filter { $0.rotationIndex == rotationIndex - 1 }.map { ($0.groupIndex, 1) } + let counts = Dictionary(previousRotationBracketIndexes, uniquingKeysWith: +) + var rotationMatches = Array(availableMatchs.filter({ match in + teamsPerRotation[rotationIndex]!.allSatisfy({ match.containsTeamId($0) == false }) == true + }).prefix(numberOfCourtsAvailablePerRotation)) + + if rotationIndex > 0 { + rotationMatches = rotationMatches.sorted(by: { + if counts[$0.groupStageObject!.index] ?? 0 == counts[$1.groupStageObject!.index] ?? 0 { + return $0.groupStageObject!.index < $1.groupStageObject!.index + } else { + return counts[$0.groupStageObject!.index] ?? 0 < counts[$1.groupStageObject!.index] ?? 0 + } + }) + } + (0.. 0 { - rotationMatches = rotationMatches.sorted(by: { - if counts[$0.groupStageObject!.index] ?? 0 == counts[$1.groupStageObject!.index] ?? 0 { - return $0.groupStageObject!.index < $1.groupStageObject!.index - } else { - return counts[$0.groupStageObject!.index] ?? 0 < counts[$1.groupStageObject!.index] ?? 0 - } - }) - } - if let first = rotationMatches.first(where: { match in let estimatedDuration = match.matchFormat.getEstimatedDuration(additionalEstimationDuration) let timeIntervalToAdd = (Double(rotationIndex)) * Double(estimatedDuration) * 60 @@ -228,6 +230,7 @@ final class MatchScheduler : ModelObject, Storable { } }) { let timeMatch = GroupStageTimeMatch(matchID: first.id, rotationIndex: rotationIndex, courtIndex: courtIndex, groupIndex: first.groupStageObject!.index) + print(first.matchTitle()) slots.append(timeMatch) teamsPerRotation[rotationIndex]!.append(contentsOf: first.teamIds()) rotationMatches.removeAll(where: { $0.id == first.id }) diff --git a/PadelClub/Views/GroupStage/Components/GroupStageTeamView.swift b/PadelClub/Views/GroupStage/Components/GroupStageTeamView.swift index 0d94139..af1b072 100644 --- a/PadelClub/Views/GroupStage/Components/GroupStageTeamView.swift +++ b/PadelClub/Views/GroupStage/Components/GroupStageTeamView.swift @@ -37,6 +37,14 @@ struct GroupStageTeamView: View { } } + private func _editingOptions() -> [EditablePlayerView.PlayerEditingOption] { + if tournament.isFree() { + return [.licenceId, .name, .presence] + } else { + return [.licenceId, .name, .payment] + } + } + var body: some View { List { Section { @@ -44,7 +52,7 @@ struct GroupStageTeamView: View { Text(name).foregroundStyle(.secondary) } ForEach(team.players()) { player in - EditablePlayerView(player: player, editingOptions: [.licenceId, .name, .payment]) + EditablePlayerView(player: player, editingOptions: _editingOptions()) } } diff --git a/PadelClub/Views/Match/Components/MatchTeamDetailView.swift b/PadelClub/Views/Match/Components/MatchTeamDetailView.swift index 435f181..cf952d0 100644 --- a/PadelClub/Views/Match/Components/MatchTeamDetailView.swift +++ b/PadelClub/Views/Match/Components/MatchTeamDetailView.swift @@ -32,13 +32,26 @@ struct MatchTeamDetailView: View { private func _teamDetailView(_ team: TeamRegistration, inTournament tournament: Tournament?) -> some View { Section { ForEach(team.players()) { player in - EditablePlayerView(player: player, editingOptions: [.licenceId, .name, .payment]) + EditablePlayerView(player: player, editingOptions: _editingOptions()) } } header: { TeamHeaderView(team: team, teamIndex: tournament?.indexOf(team: team)) } } + private func _isFree() -> Bool { + let tournament = match.currentTournament() + return tournament?.isFree() == true + } + + private func _editingOptions() -> [EditablePlayerView.PlayerEditingOption] { + if _isFree() { + return [.licenceId, .name, .presence] + } else { + return [.licenceId, .name, .payment] + } + } + } //#Preview { diff --git a/PadelClub/Views/Match/MatchSummaryView.swift b/PadelClub/Views/Match/MatchSummaryView.swift index 1e4bda1..5ba96eb 100644 --- a/PadelClub/Views/Match/MatchSummaryView.swift +++ b/PadelClub/Views/Match/MatchSummaryView.swift @@ -57,7 +57,7 @@ struct MatchSummaryView: View { } } Spacer() - if let courtName, matchViewStyle != .feedStyle { + if let courtName { Spacer() Text(courtName) .foregroundStyle(.gray) diff --git a/PadelClub/Views/Planning/PlanningByCourtView.swift b/PadelClub/Views/Planning/PlanningByCourtView.swift index 96302fd..25cc794 100644 --- a/PadelClub/Views/Planning/PlanningByCourtView.swift +++ b/PadelClub/Views/Planning/PlanningByCourtView.swift @@ -40,6 +40,7 @@ struct PlanningByCourtView: View { var body: some View { List { _byCourtView() + .id(selectedCourt) } .overlay { if matches.allSatisfy({ $0.startDate == nil }) { diff --git a/PadelClub/Views/Planning/PlanningView.swift b/PadelClub/Views/Planning/PlanningView.swift index e490a08..9dd42da 100644 --- a/PadelClub/Views/Planning/PlanningView.swift +++ b/PadelClub/Views/Planning/PlanningView.swift @@ -16,6 +16,23 @@ struct PlanningView: View { @State private var timeSlots: [Date:[Match]] @State private var days: [Date] @State private var keys: [Date] + @State private var filterOption: PlanningFilterOption = .byDefault + + enum PlanningFilterOption: Int, CaseIterable, Identifiable { + var id: Int { self.rawValue } + + case byDefault + case byCourt + + func localizedPlanningLabel() -> String { + switch self { + case .byCourt: + return "Par terrain" + case .byDefault: + return "Par défaut" + } + } + } init(matches: [Match], selectedScheduleDestination: Binding) { self.matches = matches @@ -30,6 +47,24 @@ struct PlanningView: View { List { _bySlotView() } + .toolbar(content: { + ToolbarItem(placement: .topBarTrailing) { + Menu { + Picker(selection: $filterOption) { + ForEach(PlanningFilterOption.allCases) { + Text($0.localizedPlanningLabel()).tag($0) + } + } label: { + Text("Option de filtrage") + } + .labelsHidden() + .pickerStyle(.inline) + } label: { + Label("Filtrer", systemImage: "line.3.horizontal.decrease.circle") + .symbolVariant(filterOption == .byCourt ? .fill : .none) + } + } + }) .overlay { if matches.allSatisfy({ $0.startDate == nil }) { ContentUnavailableView { @@ -53,7 +88,7 @@ struct PlanningView: View { ForEach(keys.filter({ $0.dayInt == day.dayInt }), id: \.self) { key in if let _matches = timeSlots[key] { DisclosureGroup { - ForEach(_matches) { match in + ForEach(_matches.sorted(by: filterOption == .byDefault ? \.computedOrder : \.courtIndexForSorting)) { match in NavigationLink { MatchDetailView(match: match, matchViewStyle: .sectionedStandardStyle) } label: { @@ -98,7 +133,14 @@ struct PlanningView: View { Text(self._formattedMatchCount(matches.count)) } label: { Text(key.formatted(date: .omitted, time: .shortened)).font(.title).fontWeight(.semibold) - Text(Set(matches.compactMap { $0.roundTitle() }).joined(separator: ", ")) + let names = matches.sorted(by: \.computedOrder) + .compactMap({ $0.roundTitle() }) + .reduce(into: [String]()) { uniqueNames, name in + if !uniqueNames.contains(name) { + uniqueNames.append(name) + } + } + Text(names.joined(separator: ", ")) } }