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.
 
 
PadelClub/PadelClub/Views/Planning/PlanningView.swift

156 lines
7.3 KiB

//
// PlanningView.swift
// PadelClub
//
// Created by Razmig Sarkissian on 07/04/2024.
//
import SwiftUI
struct PlanningView: View {
@EnvironmentObject var dataStore: DataStore
@Environment(\.editMode) private var editMode
let matches: [Match]
@State private var timeSlots: [Date:[Match]]
@State private var days: [Date]
@State private var keys: [Date]
init(matches: [Match]) {
self.matches = matches
let timeSlots = Dictionary(grouping: matches) { $0.startDate ?? .distantFuture }
_timeSlots = State(wrappedValue: timeSlots)
_days = State(wrappedValue: Set(timeSlots.keys.map { $0.startOfDay }).sorted())
_keys = State(wrappedValue: timeSlots.keys.sorted())
}
var body: some View {
List {
ForEach(days, id: \.self) { day in
Section {
ForEach(keys.filter({ $0.dayInt == day.dayInt }), id: \.self) { key in
if let _matches = timeSlots[key] {
if editMode?.wrappedValue.isEditing == true {
HStack {
VStack(alignment: .leading) {
let index = keys.firstIndex(of: key)
Button {
let previousKey = keys[index! - 1]
let previousMatches = timeSlots[previousKey]
previousMatches?.forEach { match in
match.startDate = key
}
_matches.forEach { match in
match.startDate = previousKey
}
_update()
} label: {
Image(systemName: "arrow.up")
}
.buttonStyle(.bordered)
.disabled(index == 0)
Button {
let nextKey = keys[index! + 1]
let nextMatches = timeSlots[nextKey]
nextMatches?.forEach { match in
match.startDate = key
}
_matches.forEach { match in
match.startDate = nextKey
}
_update()
} label: {
Image(systemName: "arrow.down")
}
.buttonStyle(.bordered)
.disabled(index == keys.count - 1)
}
VStack(alignment: .leading) {
LabeledContent {
Text(_matches.count.formatted() + " match" + _matches.count.pluralSuffix)
} label: {
Text(key.formatted(date: .omitted, time: .shortened)).font(.largeTitle)
}
ForEach(_matches) { match in
LabeledContent {
Text(match.matchFormat.format)
} label: {
if let groupStage = match.groupStageObject {
Text(groupStage.groupStageTitle())
} else if let round = match.roundObject {
Text(round.roundTitle())
}
Text(match.matchTitle())
}
}
}
}
} else {
DisclosureGroup {
ForEach(_matches) { match in
NavigationLink {
MatchDetailView(match: match, matchViewStyle: .sectionedStandardStyle)
} label: {
LabeledContent {
if let court = match.court {
Text(court)
}
} label: {
if let groupStage = match.groupStageObject {
Text(groupStage.groupStageTitle())
} else if let round = match.roundObject {
Text(round.roundTitle())
}
Text(match.matchTitle())
}
}
}
} label: {
_timeSlotView(key: key, matches: _matches)
}
}
}
}
} header: {
Text(day.formatted(.dateTime.day().weekday().month().year()))
}
.headerProminence(.increased)
}
}
.toolbar {
EditButton()
}
.onChange(of: isEditing) { old, new in
if old == true && new == false {
print("save")
try? dataStore.matches.addOrUpdate(contentOfs: matches)
}
}
.navigationTitle("Programmation")
}
private func _update() {
let timeSlots = Dictionary(grouping: matches) { $0.startDate ?? .distantFuture }
self.timeSlots = timeSlots
self.days = Set(timeSlots.keys.map { $0.startOfDay }).sorted()
self.keys = timeSlots.keys.sorted()
}
private var isEditing: Bool {
editMode?.wrappedValue.isEditing == true
}
private func _timeSlotView(key: Date, matches: [Match]) -> some View {
LabeledContent {
Text(matches.count.formatted() + " match" + matches.count.pluralSuffix)
} label: {
Text(key.formatted(date: .omitted, time: .shortened)).font(.largeTitle)
Text(Set(matches.compactMap { $0.roundTitle() }).joined(separator: ", "))
}
}
}
#Preview {
PlanningView(matches: [])
}