You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
210 lines
8.5 KiB
210 lines
8.5 KiB
//
|
|
// PlanningSettingsView.swift
|
|
// PadelClub
|
|
//
|
|
// Created by Razmig Sarkissian on 07/04/2024.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
struct PlanningSettingsView: View {
|
|
@EnvironmentObject var dataStore: DataStore
|
|
var tournament: Tournament
|
|
@State private var scheduleSetup: Bool = false
|
|
@State private var randomCourtDistribution: Bool
|
|
@State private var groupStageCourtCount: Int
|
|
@State private var upperBracketBreakTime: Bool
|
|
@State private var loserBracketBreakTime: Bool
|
|
@State private var rotationDifferenceIsImportant: Bool
|
|
@State private var loserBracketRotationDifference: Int
|
|
@State private var upperBracketRotationDifference: Int
|
|
@State private var timeDifferenceLimit: Double
|
|
@State private var shouldHandleUpperRoundSlice: Bool
|
|
|
|
init(tournament: Tournament) {
|
|
self.tournament = tournament
|
|
self._groupStageCourtCount = State(wrappedValue: tournament.groupStageCourtCount ?? 1)
|
|
self._loserBracketRotationDifference = State(wrappedValue: MatchScheduler.shared.loserBracketRotationDifference)
|
|
self._upperBracketRotationDifference = State(wrappedValue: MatchScheduler.shared.upperBracketRotationDifference)
|
|
self._timeDifferenceLimit = State(wrappedValue: MatchScheduler.shared.timeDifferenceLimit)
|
|
self._rotationDifferenceIsImportant = State(wrappedValue: MatchScheduler.shared.rotationDifferenceIsImportant())
|
|
self._randomCourtDistribution = State(wrappedValue: MatchScheduler.shared.randomizeCourts())
|
|
self._upperBracketBreakTime = State(wrappedValue: MatchScheduler.shared.accountUpperBracketBreakTime())
|
|
self._loserBracketBreakTime = State(wrappedValue: MatchScheduler.shared.accountLoserBracketBreakTime())
|
|
self._shouldHandleUpperRoundSlice = State(wrappedValue: MatchScheduler.shared.shouldHandleUpperRoundSlice())
|
|
}
|
|
|
|
var body: some View {
|
|
@Bindable var tournament = tournament
|
|
List {
|
|
Section {
|
|
DatePicker(tournament.startDate.formatted(.dateTime.weekday()), selection: $tournament.startDate)
|
|
LabeledContent {
|
|
StepperView(count: $tournament.dayDuration, minimum: 1, maximum: 1_000)
|
|
} label: {
|
|
Text("Durée")
|
|
Text("\(tournament.dayDuration) jour" + tournament.dayDuration.pluralSuffix)
|
|
}
|
|
} header: {
|
|
Text("Démarrage et durée du tournoi")
|
|
} footer: {
|
|
Text("todo: Expliquer ce que ca fait")
|
|
}
|
|
|
|
Section {
|
|
TournamentFieldsManagerView(localizedStringKey: "Terrains maximum", count: $tournament.courtCount)
|
|
|
|
if tournament.groupStages().isEmpty == false {
|
|
TournamentFieldsManagerView(localizedStringKey: "Terrains par poule", count: $groupStageCourtCount)
|
|
}
|
|
|
|
NavigationLink {
|
|
|
|
} label: {
|
|
Text("Disponibilité des terrains")
|
|
}
|
|
}
|
|
|
|
Section {
|
|
|
|
Toggle(isOn: $randomCourtDistribution) {
|
|
Text("Distribuer les terrains au hasard")
|
|
}
|
|
|
|
Toggle(isOn: $shouldHandleUpperRoundSlice) {
|
|
Text("Équilibrer les matchs d'une manche sur plusieurs tours")
|
|
}
|
|
|
|
Toggle(isOn: $upperBracketBreakTime) {
|
|
Text("Tableau : tenir compte des pauses")
|
|
}
|
|
|
|
Toggle(isOn: $loserBracketBreakTime) {
|
|
Text("Classement : tenir compte des pauses")
|
|
}
|
|
|
|
Toggle(isOn: $rotationDifferenceIsImportant) {
|
|
Text("Forcer un créneau supplémentaire entre 2 phases")
|
|
}
|
|
|
|
LabeledContent {
|
|
StepperView(count: $upperBracketRotationDifference, minimum: 0, maximum: 2)
|
|
} label: {
|
|
Text("Tableau")
|
|
}
|
|
.disabled(rotationDifferenceIsImportant == false)
|
|
|
|
LabeledContent {
|
|
StepperView(count: $loserBracketRotationDifference, minimum: 0, maximum: 2)
|
|
} label: {
|
|
Text("Classement")
|
|
}
|
|
.disabled(rotationDifferenceIsImportant == false)
|
|
|
|
//timeDifferenceLimit
|
|
|
|
RowButtonView("Horaire intelligent", role: .destructive) {
|
|
_setupSchedule()
|
|
}
|
|
|
|
if scheduleSetup {
|
|
HStack {
|
|
Image(systemName: "checkmark")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.onChange(of: groupStageCourtCount) {
|
|
tournament.groupStageCourtCount = groupStageCourtCount
|
|
_save()
|
|
}
|
|
.onChange(of: tournament.startDate) {
|
|
_save()
|
|
}
|
|
.onChange(of: tournament.courtCount) {
|
|
_save()
|
|
}
|
|
.onChange(of: tournament.groupStageCourtCount) {
|
|
_save()
|
|
}
|
|
.onChange(of: tournament.dayDuration) {
|
|
_save()
|
|
}
|
|
}
|
|
|
|
private func _setupSchedule() {
|
|
let groupStageCourtCount = tournament.groupStageCourtCount ?? 1
|
|
let groupStages = tournament.groupStages()
|
|
let numberOfCourtsAvailablePerRotation: Int = tournament.courtCount
|
|
let matchScheduler = MatchScheduler.shared
|
|
matchScheduler.options.removeAll()
|
|
|
|
if randomCourtDistribution {
|
|
matchScheduler.options.insert(.randomizeCourts)
|
|
}
|
|
|
|
if shouldHandleUpperRoundSlice {
|
|
matchScheduler.options.insert(.shouldHandleUpperRoundSlice)
|
|
}
|
|
|
|
if upperBracketBreakTime {
|
|
matchScheduler.options.insert(.accountUpperBracketBreakTime)
|
|
}
|
|
|
|
if loserBracketBreakTime {
|
|
matchScheduler.options.insert(.accountLoserBracketBreakTime)
|
|
}
|
|
|
|
if rotationDifferenceIsImportant {
|
|
matchScheduler.options.insert(.rotationDifferenceIsImportant)
|
|
}
|
|
|
|
matchScheduler.loserBracketRotationDifference = loserBracketRotationDifference
|
|
matchScheduler.upperBracketRotationDifference = upperBracketRotationDifference
|
|
matchScheduler.timeDifferenceLimit = timeDifferenceLimit
|
|
|
|
let matches = tournament.groupStages().flatMap({ $0._matches() })
|
|
matches.forEach({ $0.startDate = nil })
|
|
|
|
// var times = Set(groupStages.compactMap { $0.startDate }.filter { $0 >= tournament.startDate } )
|
|
// if times.isEmpty {
|
|
// groupStages.forEach({ $0.startDate = tournament.startDate })
|
|
// times.insert(tournament.startDate)
|
|
// try? dataStore.groupStages.addOrUpdate(contentOfs: groupStages)
|
|
// }
|
|
|
|
var lastDate : Date = tournament.startDate
|
|
groupStages.chunked(into: groupStageCourtCount).forEach { groups in
|
|
groups.forEach({ $0.startDate = lastDate })
|
|
try? dataStore.groupStages.addOrUpdate(contentOfs: groups)
|
|
|
|
let dispatch = matchScheduler.groupStageDispatcher(numberOfCourtsAvailablePerRotation: numberOfCourtsAvailablePerRotation, groupStages: groups, startingDate: lastDate)
|
|
|
|
dispatch.timedMatches.forEach { matchSchedule in
|
|
if let match = matches.first(where: { $0.id == matchSchedule.matchID }) {
|
|
let timeIntervalToAdd = (Double(matchSchedule.rotationIndex)) * Double(match.matchFormat.estimatedDuration) * 60
|
|
if let startDate = match.groupStageObject?.startDate {
|
|
let matchStartDate = startDate.addingTimeInterval(timeIntervalToAdd)
|
|
match.startDate = matchStartDate
|
|
lastDate = matchStartDate.addingTimeInterval(Double(match.matchFormat.estimatedDuration) * 60)
|
|
}
|
|
match.setCourt(matchSchedule.courtIndex + 1)
|
|
}
|
|
}
|
|
}
|
|
try? dataStore.matches.addOrUpdate(contentOfs: matches)
|
|
|
|
matchScheduler.updateSchedule(tournament: tournament, fromRoundId: nil, fromMatchId: nil, startDate: lastDate)
|
|
|
|
scheduleSetup = true
|
|
|
|
}
|
|
|
|
private func _save() {
|
|
try? dataStore.tournaments.addOrUpdate(instance: tournament)
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
PlanningSettingsView(tournament: Tournament.mock())
|
|
}
|
|
|