fix planning views and match scheduler for groupstages

sync2
Raz 1 year ago
parent f691681e94
commit 883a46baea
  1. 8
      PadelClub.xcodeproj/project.pbxproj
  2. 6
      PadelClub/Data/GroupStage.swift
  3. 5
      PadelClub/Data/Match.swift
  4. 11
      PadelClub/Data/MatchScheduler.swift
  5. 10
      PadelClub/Views/GroupStage/Components/GroupStageTeamView.swift
  6. 15
      PadelClub/Views/Match/Components/MatchTeamDetailView.swift
  7. 2
      PadelClub/Views/Match/MatchSummaryView.swift
  8. 1
      PadelClub/Views/Planning/PlanningByCourtView.swift
  9. 46
      PadelClub/Views/Planning/PlanningView.swift

@ -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;

@ -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..<size).combinations(ofCount: 2))[safe: matchIndex] ?? []
}

@ -470,8 +470,11 @@ defer {
}
var computedOrder: Int {
if let groupStageObject {
return (groupStageObject.index + 1) * 100 + groupStageObject.indexOf(index)
}
guard let roundObject else { return index }
return roundObject.isLoserBracket() ? roundObject.index * 100 + indexInRound() : roundObject.index * 1000 + indexInRound()
return roundObject.isLoserBracket() ? (roundObject.index + 1) * 1000 + indexInRound() : (roundObject.index + 1) * 10000 + indexInRound()
}
func previousMatches() -> [Match] {

@ -199,11 +199,11 @@ final class MatchScheduler : ModelObject, Storable {
while slots.count < flattenedMatches.count {
teamsPerRotation[rotationIndex] = []
freeCourtPerRotation[rotationIndex] = []
(0..<numberOfCourtsAvailablePerRotation).forEach { courtIndex in
//print(mt.map { ($0.bracket!.index.intValue, counts[$0.bracket!.index.intValue]) })
let previousRotationBracketIndexes = slots.map { ($0.groupIndex, 1) }
let previousRotationBracketIndexes = slots.filter { $0.rotationIndex == rotationIndex - 1 }.map { ($0.groupIndex, 1) }
let counts = Dictionary(previousRotationBracketIndexes, uniquingKeysWith: +)
var rotationMatches = Array(availableMatchs)
var rotationMatches = Array(availableMatchs.filter({ match in
teamsPerRotation[rotationIndex]!.allSatisfy({ match.containsTeamId($0) == false }) == true
}).prefix(numberOfCourtsAvailablePerRotation))
if rotationIndex > 0 {
rotationMatches = rotationMatches.sorted(by: {
@ -215,6 +215,8 @@ final class MatchScheduler : ModelObject, Storable {
})
}
(0..<numberOfCourtsAvailablePerRotation).forEach { courtIndex in
//print(mt.map { ($0.bracket!.index.intValue, counts[$0.bracket!.index.intValue]) })
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 })

@ -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())
}
}

@ -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 {

@ -57,7 +57,7 @@ struct MatchSummaryView: View {
}
}
Spacer()
if let courtName, matchViewStyle != .feedStyle {
if let courtName {
Spacer()
Text(courtName)
.foregroundStyle(.gray)

@ -40,6 +40,7 @@ struct PlanningByCourtView: View {
var body: some View {
List {
_byCourtView()
.id(selectedCourt)
}
.overlay {
if matches.allSatisfy({ $0.startDate == nil }) {

@ -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<ScheduleDestination?>) {
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: ", "))
}
}

Loading…
Cancel
Save