commit
ee8a297f13
@ -0,0 +1,103 @@ |
|||||||
|
// |
||||||
|
// DrawLog.swift |
||||||
|
// PadelClub |
||||||
|
// |
||||||
|
// Created by razmig on 22/10/2024. |
||||||
|
// |
||||||
|
|
||||||
|
import Foundation |
||||||
|
import SwiftUI |
||||||
|
import LeStorage |
||||||
|
|
||||||
|
@Observable |
||||||
|
final class DrawLog: ModelObject, Storable { |
||||||
|
static func resourceName() -> String { return "draw-logs" } |
||||||
|
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } |
||||||
|
static func filterByStoreIdentifier() -> Bool { return false } |
||||||
|
static var relationshipNames: [String] = [] |
||||||
|
|
||||||
|
var id: String = Store.randomId() |
||||||
|
var tournament: String |
||||||
|
var drawDate: Date = Date() |
||||||
|
var drawSeed: Int |
||||||
|
var drawMatchIndex: Int |
||||||
|
var drawTeamPosition: TeamPosition |
||||||
|
|
||||||
|
internal init(id: String = Store.randomId(), tournament: String, drawDate: Date = Date(), drawSeed: Int, drawMatchIndex: Int, drawTeamPosition: TeamPosition) { |
||||||
|
self.id = id |
||||||
|
self.tournament = tournament |
||||||
|
self.drawDate = drawDate |
||||||
|
self.drawSeed = drawSeed |
||||||
|
self.drawMatchIndex = drawMatchIndex |
||||||
|
self.drawTeamPosition = drawTeamPosition |
||||||
|
} |
||||||
|
|
||||||
|
func tournamentObject() -> Tournament? { |
||||||
|
Store.main.findById(self.tournament) |
||||||
|
} |
||||||
|
|
||||||
|
func computedBracketPosition() -> Int { |
||||||
|
drawMatchIndex * 2 + drawTeamPosition.rawValue |
||||||
|
} |
||||||
|
|
||||||
|
func updateTeamBracketPosition(_ team: TeamRegistration) { |
||||||
|
guard let match = drawMatch() else { return } |
||||||
|
let seedPosition: Int = match.lockAndGetSeedPosition(atTeamPosition: drawTeamPosition) |
||||||
|
team.bracketPosition = seedPosition |
||||||
|
tournamentObject()?.updateTeamScores(in: seedPosition) |
||||||
|
} |
||||||
|
|
||||||
|
func exportedDrawLog() -> String { |
||||||
|
[drawDate.localizedDate(), localizedDrawLogLabel(), localizedDrawBranch()].joined(separator: " ") |
||||||
|
} |
||||||
|
|
||||||
|
func localizedDrawSeedLabel() -> String { |
||||||
|
return "Tête de série #\(drawSeed + 1)" |
||||||
|
} |
||||||
|
|
||||||
|
func localizedDrawLogLabel() -> String { |
||||||
|
return [localizedDrawSeedLabel(), positionLabel()].joined(separator: " -> ") |
||||||
|
} |
||||||
|
|
||||||
|
func localizedDrawBranch() -> String { |
||||||
|
drawTeamPosition.localizedBranchLabel() |
||||||
|
} |
||||||
|
|
||||||
|
func drawMatch() -> Match? { |
||||||
|
let roundIndex = RoundRule.roundIndex(fromMatchIndex: drawMatchIndex) |
||||||
|
return tournamentStore.rounds.first(where: { $0.parent == nil && $0.index == roundIndex })?._matches().first(where: { $0.index == drawMatchIndex }) |
||||||
|
} |
||||||
|
|
||||||
|
func positionLabel() -> String { |
||||||
|
return drawMatch()?.roundAndMatchTitle() ?? "" |
||||||
|
} |
||||||
|
|
||||||
|
func roundLabel() -> String { |
||||||
|
return drawMatch()?.roundTitle() ?? "" |
||||||
|
} |
||||||
|
|
||||||
|
func matchLabel() -> String { |
||||||
|
return drawMatch()?.matchTitle() ?? "" |
||||||
|
} |
||||||
|
|
||||||
|
var tournamentStore: TournamentStore { |
||||||
|
return TournamentStore.instance(tournamentId: self.tournament) |
||||||
|
} |
||||||
|
|
||||||
|
override func deleteDependencies() throws { |
||||||
|
} |
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey { |
||||||
|
case _id = "id" |
||||||
|
case _tournament = "tournament" |
||||||
|
case _drawDate = "drawDate" |
||||||
|
case _drawSeed = "drawSeed" |
||||||
|
case _drawMatchIndex = "drawMatchIndex" |
||||||
|
case _drawTeamPosition = "drawTeamPosition" |
||||||
|
} |
||||||
|
|
||||||
|
func insertOnServer() throws { |
||||||
|
self.tournamentStore.drawLogs.writeChangeAndInsertOnServer(instance: self) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,69 @@ |
|||||||
|
// |
||||||
|
// DrawLogsView.swift |
||||||
|
// PadelClub |
||||||
|
// |
||||||
|
// Created by razmig on 22/10/2024. |
||||||
|
// |
||||||
|
|
||||||
|
import SwiftUI |
||||||
|
import LeStorage |
||||||
|
|
||||||
|
struct DrawLogsView: View { |
||||||
|
@Environment(Tournament.self) var tournament |
||||||
|
|
||||||
|
var drawLogs: [DrawLog] { |
||||||
|
tournament.drawLogs().reversed() |
||||||
|
} |
||||||
|
|
||||||
|
var body: some View { |
||||||
|
List { |
||||||
|
ForEach(drawLogs) { drawLog in |
||||||
|
HStack { |
||||||
|
VStack(alignment: .leading) { |
||||||
|
Text(drawLog.localizedDrawSeedLabel()) |
||||||
|
Text(drawLog.drawDate.localizedDate()) |
||||||
|
.font(.footnote) |
||||||
|
.foregroundStyle(.secondary) |
||||||
|
} |
||||||
|
Spacer() |
||||||
|
VStack(alignment: .trailing) { |
||||||
|
Text(drawLog.positionLabel()).lineLimit(1).truncationMode(.middle) |
||||||
|
Text(drawLog.localizedDrawBranch()) |
||||||
|
.font(.footnote) |
||||||
|
.foregroundStyle(.secondary) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.overlay(content: { |
||||||
|
if drawLogs.isEmpty { |
||||||
|
ContentUnavailableView("Aucun tirage", systemImage: "dice", description: Text("Aucun tirage au sort n'a été effectué.")) |
||||||
|
} |
||||||
|
}) |
||||||
|
.toolbar(content: { |
||||||
|
ToolbarItem(placement: .topBarTrailing) { |
||||||
|
Menu { |
||||||
|
ShareLink(item: tournament.exportedDrawLogs()) { |
||||||
|
Label("Partager les tirages", systemImage: "square.and.arrow.up") |
||||||
|
.labelStyle(.titleAndIcon) |
||||||
|
} |
||||||
|
|
||||||
|
Divider() |
||||||
|
|
||||||
|
Button("Tout effacer", role: .destructive) { |
||||||
|
do { |
||||||
|
try tournament.tournamentStore.drawLogs.deleteAll() |
||||||
|
} catch { |
||||||
|
Logger.error(error) |
||||||
|
} |
||||||
|
} |
||||||
|
} label: { |
||||||
|
LabelOptions() |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
.navigationBarTitleDisplayMode(.inline) |
||||||
|
.toolbarBackground(.visible, for: .navigationBar) |
||||||
|
.navigationTitle("Journal des tirages") |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,107 @@ |
|||||||
|
// |
||||||
|
// PreviewBracketPositionView.swift |
||||||
|
// PadelClub |
||||||
|
// |
||||||
|
// Created by razmig on 23/10/2024. |
||||||
|
// |
||||||
|
|
||||||
|
import SwiftUI |
||||||
|
|
||||||
|
struct PreviewBracketPositionView: View { |
||||||
|
let seeds: [TeamRegistration] |
||||||
|
let drawLogs: [DrawLog] |
||||||
|
|
||||||
|
@State private var filterOption: PreviewBracketPositionFilterOption = .difference |
||||||
|
|
||||||
|
enum PreviewBracketPositionFilterOption: Int, Identifiable, CaseIterable { |
||||||
|
var id: Int { self.rawValue } |
||||||
|
case all |
||||||
|
case difference |
||||||
|
case summon |
||||||
|
|
||||||
|
func isDisplayable(_ team: TeamRegistration, drawLog: DrawLog?) -> Bool { |
||||||
|
switch self { |
||||||
|
case .all: |
||||||
|
true |
||||||
|
case .difference: |
||||||
|
team.isDifferentPosition(drawLog?.computedBracketPosition()) == true |
||||||
|
case .summon: |
||||||
|
team.callDate != drawLog?.drawMatch()?.startDate |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
var body: some View { |
||||||
|
List { |
||||||
|
Section { |
||||||
|
ForEach(seeds.indices, id: \.self) { seedIndex in |
||||||
|
let seed = seeds[seedIndex] |
||||||
|
let drawLog = drawLogs.first(where: { $0.drawSeed == seedIndex }) |
||||||
|
if filterOption.isDisplayable(seed, drawLog: drawLog) { |
||||||
|
HStack { |
||||||
|
VStack(alignment: .leading) { |
||||||
|
Text("Tête de série #\(seedIndex + 1)").font(.caption) |
||||||
|
TeamRowView.TeamView(team: seed) |
||||||
|
TeamRowView.TeamCallDateView(team: seed) |
||||||
|
} |
||||||
|
Spacer() |
||||||
|
if let drawLog { |
||||||
|
VStack(alignment: .trailing) { |
||||||
|
Text(drawLog.roundLabel()).lineLimit(1).truncationMode(.middle).font(.caption) |
||||||
|
Text(drawLog.matchLabel()).lineLimit(1).truncationMode(.middle) |
||||||
|
Text(drawLog.localizedDrawBranch()) |
||||||
|
if let expectedDate = drawLog.drawMatch()?.startDate { |
||||||
|
Text(expectedDate.localizedDate()) |
||||||
|
.font(.caption) |
||||||
|
} else { |
||||||
|
Text("Aucun horaire") |
||||||
|
.font(.caption) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.listRowView(isActive: true, color: seed.isDifferentPosition(drawLog?.computedBracketPosition()) ? .logoRed : .green, hideColorVariation: true) |
||||||
|
} |
||||||
|
} |
||||||
|
} header: { |
||||||
|
Picker(selection: $filterOption) { |
||||||
|
Text("Tous").tag(PreviewBracketPositionFilterOption.all) |
||||||
|
Text("Changements").tag(PreviewBracketPositionFilterOption.difference) |
||||||
|
Text("Convoc.").tag(PreviewBracketPositionFilterOption.summon) |
||||||
|
} label: { |
||||||
|
Text("Filter") |
||||||
|
} |
||||||
|
.labelsHidden() |
||||||
|
.pickerStyle(.segmented) |
||||||
|
.textCase(nil) |
||||||
|
} |
||||||
|
} |
||||||
|
.overlay(content: { |
||||||
|
if seeds.isEmpty { |
||||||
|
ContentUnavailableView("Aucune équipe", systemImage: "person.2.slash", description: Text("Aucun tête de série dans le tournoi.")) |
||||||
|
} else if filterOption == .difference, noSeedHasDifferentPlace() { |
||||||
|
ContentUnavailableView("Aucun changement", systemImage: "dice", description: Text("Aucun changement dans le tableau.")) |
||||||
|
} else if filterOption == .summon, noSeedHasDifferentSummon() { |
||||||
|
ContentUnavailableView("Aucun changement", systemImage: "dice", description: Text("Aucun changement dans le tableau.")) |
||||||
|
} |
||||||
|
}) |
||||||
|
.navigationBarTitleDisplayMode(.inline) |
||||||
|
.toolbarBackground(.visible, for: .navigationBar) |
||||||
|
.navigationTitle("Aperçu du tableau tiré") |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
func noSeedHasDifferentPlace() -> Bool { |
||||||
|
seeds.enumerated().allSatisfy({ seedIndex, seed in |
||||||
|
let drawLog = drawLogs.first(where: { $0.drawSeed == seedIndex }) |
||||||
|
return seed.isDifferentPosition(drawLog?.computedBracketPosition()) == false |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
func noSeedHasDifferentSummon() -> Bool { |
||||||
|
seeds.enumerated().allSatisfy({ seedIndex, seed in |
||||||
|
let drawLog = drawLogs.first(where: { $0.drawSeed == seedIndex }) |
||||||
|
return seed.callDate == drawLog?.drawMatch()?.startDate |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue