parent
38d2f7d005
commit
230181fe31
@ -0,0 +1,108 @@ |
|||||||
|
// |
||||||
|
// GroupStage_v2.swift |
||||||
|
// Padel Tournament |
||||||
|
// |
||||||
|
// Created by razmig on 10/03/2024. |
||||||
|
// |
||||||
|
|
||||||
|
import Foundation |
||||||
|
import LeStorage |
||||||
|
|
||||||
|
@Observable |
||||||
|
class GroupStage: ModelObject, Storable { |
||||||
|
static func resourceName() -> String { "group-stages" } |
||||||
|
|
||||||
|
var id: String = Store.randomId() |
||||||
|
var tournament: String |
||||||
|
var index: Int |
||||||
|
var size: Int |
||||||
|
var format: Int? |
||||||
|
var startDate: Date? |
||||||
|
|
||||||
|
var matchFormat: MatchFormat { |
||||||
|
get { |
||||||
|
MatchFormat(rawValue: format ?? 0) ?? .defaultFormatForMatchType(.groupStage) |
||||||
|
} |
||||||
|
set { |
||||||
|
format = newValue.rawValue |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal init(tournament: String, index: Int, size: Int, matchFormat: MatchFormat? = nil, startDate: Date? = nil) { |
||||||
|
self.tournament = tournament |
||||||
|
self.index = index |
||||||
|
self.size = size |
||||||
|
self.format = matchFormat?.rawValue |
||||||
|
self.startDate = startDate |
||||||
|
} |
||||||
|
|
||||||
|
func title(_ displayStyle: DisplayStyle = .wide) -> String { |
||||||
|
switch displayStyle { |
||||||
|
case .wide: |
||||||
|
return "Poule \(index + 1)" |
||||||
|
case .short: |
||||||
|
return "#\(index + 1)" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func isBroadcasted() -> Bool { |
||||||
|
false |
||||||
|
} |
||||||
|
|
||||||
|
func isRunning() -> Bool { // at least a match has started |
||||||
|
matches.anySatisfy({ $0.isRunning() }) |
||||||
|
} |
||||||
|
|
||||||
|
func hasStarted() -> Bool { // meaning at least one match is over |
||||||
|
matches.filter { $0.hasEnded() }.isEmpty == false |
||||||
|
} |
||||||
|
|
||||||
|
func hasEnded() -> Bool { |
||||||
|
if matches.isEmpty { return false } |
||||||
|
return matches.allSatisfy { $0.hasEnded() } |
||||||
|
} |
||||||
|
|
||||||
|
func buildMatches() { |
||||||
|
removeMatches() |
||||||
|
|
||||||
|
var _matches = [Match]() |
||||||
|
for i in 0..<numberOfMatchesToBuild { |
||||||
|
let newMatch = Match(groupStage: id, index: i, matchFormat: matchFormat) |
||||||
|
_matches.append(newMatch) |
||||||
|
} |
||||||
|
|
||||||
|
try? DataStore.shared.matches.append(contentOfs: _matches) |
||||||
|
} |
||||||
|
|
||||||
|
func removeMatches() { |
||||||
|
try? deleteDependencies() |
||||||
|
} |
||||||
|
|
||||||
|
var numberOfMatchesToBuild: Int { |
||||||
|
(size * (size - 1)) / 2 |
||||||
|
} |
||||||
|
|
||||||
|
var matches: [Match] { |
||||||
|
Store.main.filter { $0.groupStage == self.id } |
||||||
|
} |
||||||
|
|
||||||
|
var teams: [TeamRegistration] { |
||||||
|
Store.main.filter { $0.groupStage == self.id } |
||||||
|
} |
||||||
|
|
||||||
|
override func deleteDependencies() throws { |
||||||
|
try Store.main.deleteDependencies(items: self.matches) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
extension GroupStage { |
||||||
|
enum CodingKeys: String, CodingKey { |
||||||
|
case _id = "id" |
||||||
|
case _tournament = "tournament" |
||||||
|
case _index = "index" |
||||||
|
case _size = "size" |
||||||
|
case _format = "format" |
||||||
|
case _startDate = "startDate" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,107 @@ |
|||||||
|
// |
||||||
|
// Match_v2.swift |
||||||
|
// Padel Tournament |
||||||
|
// |
||||||
|
// Created by razmig on 10/03/2024. |
||||||
|
// |
||||||
|
|
||||||
|
import Foundation |
||||||
|
import LeStorage |
||||||
|
|
||||||
|
@Observable |
||||||
|
class Match: ModelObject, Storable { |
||||||
|
static func resourceName() -> String { "matches" } |
||||||
|
|
||||||
|
var id: String = Store.randomId() |
||||||
|
var round: String? |
||||||
|
var groupStage: String? |
||||||
|
var startDate: Date? |
||||||
|
var endDate: Date? |
||||||
|
var index: Int |
||||||
|
var format: Int? |
||||||
|
var court: String? |
||||||
|
var servingTeamId: String? |
||||||
|
var winningTeamId: String? |
||||||
|
var losingTeamId: String? |
||||||
|
var broadcasted: Bool |
||||||
|
var name: String? |
||||||
|
var order: Int |
||||||
|
|
||||||
|
internal init(round: String? = nil, groupStage: String? = nil, startDate: Date? = nil, endDate: Date? = nil, index: Int, matchFormat: MatchFormat? = nil, court: String? = nil, servingTeamId: String? = nil, winningTeamId: String? = nil, losingTeamId: String? = nil, broadcasted: Bool = false, name: String? = nil, order: Int = 0) { |
||||||
|
self.round = round |
||||||
|
self.groupStage = groupStage |
||||||
|
self.startDate = startDate |
||||||
|
self.endDate = endDate |
||||||
|
self.index = index |
||||||
|
self.format = matchFormat?.rawValue |
||||||
|
self.court = court |
||||||
|
self.servingTeamId = servingTeamId |
||||||
|
self.winningTeamId = winningTeamId |
||||||
|
self.losingTeamId = losingTeamId |
||||||
|
self.broadcasted = broadcasted |
||||||
|
self.name = name |
||||||
|
self.order = order |
||||||
|
} |
||||||
|
|
||||||
|
func isRunning() -> Bool { // at least a match has started |
||||||
|
hasStarted() && hasEnded() == false |
||||||
|
} |
||||||
|
|
||||||
|
func hasStarted() -> Bool { // meaning at least one match is over |
||||||
|
if let startDate { |
||||||
|
return startDate.timeIntervalSinceNow < 0 |
||||||
|
} |
||||||
|
if hasEnded() { |
||||||
|
return true |
||||||
|
} |
||||||
|
return false |
||||||
|
|
||||||
|
//todo scores |
||||||
|
// if let score { |
||||||
|
// return score.hasEnded == false && score.sets.isEmpty == false |
||||||
|
// } else { |
||||||
|
// return false |
||||||
|
// } |
||||||
|
} |
||||||
|
|
||||||
|
func hasEnded() -> Bool { |
||||||
|
endDate != nil |
||||||
|
} |
||||||
|
|
||||||
|
var roundObject: Round? { |
||||||
|
Store.main.filter { $0.id == self.round }.first |
||||||
|
} |
||||||
|
|
||||||
|
var groupStageObject: GroupStage? { |
||||||
|
Store.main.filter { $0.id == self.groupStage }.first |
||||||
|
} |
||||||
|
|
||||||
|
var isLoserBracket: Bool { |
||||||
|
roundObject?.loser != nil |
||||||
|
} |
||||||
|
|
||||||
|
var teamScores: [TeamScore] { |
||||||
|
Store.main.filter { $0.match == self.id } |
||||||
|
} |
||||||
|
|
||||||
|
override func deleteDependencies() throws { |
||||||
|
try Store.main.deleteDependencies(items: self.teamScores) |
||||||
|
} |
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey { |
||||||
|
case _id = "id" |
||||||
|
case _round = "round" |
||||||
|
case _groupStage = "groupStage" |
||||||
|
case _startDate = "startDate" |
||||||
|
case _endDate = "endDate" |
||||||
|
case _index = "index" |
||||||
|
case _format = "format" |
||||||
|
case _court = "court" |
||||||
|
case _servingTeamId = "servingTeamId" |
||||||
|
case _winningTeamId = "winningTeamId" |
||||||
|
case _losingTeamId = "losingTeamId" |
||||||
|
case _broadcasted = "broadcasted" |
||||||
|
case _name = "name" |
||||||
|
case _order = "order" |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,46 @@ |
|||||||
|
// |
||||||
|
// PlayerRegistration.swift |
||||||
|
// Padel Tournament |
||||||
|
// |
||||||
|
// Created by razmig on 10/03/2024. |
||||||
|
// |
||||||
|
|
||||||
|
import Foundation |
||||||
|
import LeStorage |
||||||
|
|
||||||
|
@Observable |
||||||
|
class PlayerRegistration: ModelObject, Storable { |
||||||
|
static func resourceName() -> String { "player-registrations" } |
||||||
|
|
||||||
|
var id: String = Store.randomId() |
||||||
|
var teamRegistration: String |
||||||
|
var firstName: String |
||||||
|
var lastName: String |
||||||
|
var licenceId: String? |
||||||
|
var rank: Int? |
||||||
|
var hasPaid: Bool |
||||||
|
var unranked: Bool |
||||||
|
|
||||||
|
internal init(teamRegistration: String, firstName: String, lastName: String, licenceId: String? = nil, rank: Int? = nil, hasPaid: Bool, unranked: Bool) { |
||||||
|
self.teamRegistration = teamRegistration |
||||||
|
self.firstName = firstName |
||||||
|
self.lastName = lastName |
||||||
|
self.licenceId = licenceId |
||||||
|
self.rank = rank |
||||||
|
self.hasPaid = hasPaid |
||||||
|
self.unranked = unranked |
||||||
|
} |
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey { |
||||||
|
case _id = "id" |
||||||
|
case _teamRegistration = "teamRegistration" |
||||||
|
case _firstName = "firstName" |
||||||
|
case _lastName = "lastName" |
||||||
|
case _licenceId = "licenceId" |
||||||
|
case _rank = "rank" |
||||||
|
case _hasPaid = "hasPaid" |
||||||
|
case _unranked = "unranked" |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,53 @@ |
|||||||
|
// |
||||||
|
// Round_v2.swift |
||||||
|
// Padel Tournament |
||||||
|
// |
||||||
|
// Created by razmig on 10/03/2024. |
||||||
|
// |
||||||
|
|
||||||
|
import Foundation |
||||||
|
import LeStorage |
||||||
|
|
||||||
|
@Observable |
||||||
|
class Round: ModelObject, Storable { |
||||||
|
static func resourceName() -> String { "rounds" } |
||||||
|
|
||||||
|
var id: String = Store.randomId() |
||||||
|
var tournament: String |
||||||
|
var index: Int |
||||||
|
var loser: String? |
||||||
|
var format: Int? |
||||||
|
|
||||||
|
internal init(id: String = Store.randomId(), tournament: String, index: Int, loser: String? = nil, format: Int? = nil) { |
||||||
|
self.id = id |
||||||
|
self.tournament = tournament |
||||||
|
self.index = index |
||||||
|
self.loser = loser |
||||||
|
self.format = format |
||||||
|
} |
||||||
|
|
||||||
|
var matches: [Match] { |
||||||
|
Store.main.filter { $0.round == self.id } |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
var loserRound: Round? { |
||||||
|
guard let loser else { return nil } |
||||||
|
return Store.main.findById(loser) |
||||||
|
} |
||||||
|
|
||||||
|
override func deleteDependencies() throws { |
||||||
|
try Store.main.deleteDependencies(items: self.matches) |
||||||
|
if let loserRound { |
||||||
|
try Store.main.deleteDependencies(items: [loserRound]) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey { |
||||||
|
case _id = "id" |
||||||
|
case _tournament = "tournament" |
||||||
|
case _index = "index" |
||||||
|
case _loser = "loser" |
||||||
|
case _format = "format" |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,68 @@ |
|||||||
|
// |
||||||
|
// TeamRegistration.swift |
||||||
|
// Padel Tournament |
||||||
|
// |
||||||
|
// Created by razmig on 10/03/2024. |
||||||
|
// |
||||||
|
|
||||||
|
import Foundation |
||||||
|
import LeStorage |
||||||
|
|
||||||
|
@Observable |
||||||
|
class TeamRegistration: ModelObject, Storable { |
||||||
|
static func resourceName() -> String { "team-registrations" } |
||||||
|
|
||||||
|
var id: String = Store.randomId() |
||||||
|
var tournament: String |
||||||
|
var groupStage: String? |
||||||
|
var registrationDate: Date? |
||||||
|
var callDate: Date? |
||||||
|
var bracketPosition: Int? |
||||||
|
var groupStagePosition: Int? |
||||||
|
var comment: String? |
||||||
|
var source: String? |
||||||
|
var sourceValue: String? |
||||||
|
var logo: String? |
||||||
|
var name: String? |
||||||
|
|
||||||
|
internal init(tournament: String, groupStage: String? = nil, registrationDate: Date? = nil, callDate: Date? = nil, bracketPosition: Int? = nil, groupStagePosition: Int? = nil, comment: String? = nil, source: String? = nil, sourceValue: String? = nil, logo: String? = nil, name: String? = nil) { |
||||||
|
self.tournament = tournament |
||||||
|
self.groupStage = groupStage |
||||||
|
self.registrationDate = registrationDate |
||||||
|
self.callDate = callDate |
||||||
|
self.bracketPosition = bracketPosition |
||||||
|
self.groupStagePosition = groupStagePosition |
||||||
|
self.comment = comment |
||||||
|
self.source = source |
||||||
|
self.sourceValue = sourceValue |
||||||
|
self.logo = logo |
||||||
|
self.name = name |
||||||
|
} |
||||||
|
|
||||||
|
func qualified() -> Bool { |
||||||
|
groupStagePosition != nil && bracketPosition != nil |
||||||
|
} |
||||||
|
|
||||||
|
var playerRegistrations: [PlayerRegistration] { |
||||||
|
Store.main.filter { $0.teamRegistration == self.id } |
||||||
|
} |
||||||
|
|
||||||
|
override func deleteDependencies() throws { |
||||||
|
try Store.main.deleteDependencies(items: self.playerRegistrations) |
||||||
|
} |
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey { |
||||||
|
case _id = "id" |
||||||
|
case _tournament = "tournament" |
||||||
|
case _groupStage = "groupStage" |
||||||
|
case _registrationDate = "registrationDate" |
||||||
|
case _callDate = "callDate" |
||||||
|
case _bracketPosition = "bracketPosition" |
||||||
|
case _groupStagePosition = "groupStagePosition" |
||||||
|
case _comment = "comment" |
||||||
|
case _source = "source" |
||||||
|
case _sourceValue = "sourceValue" |
||||||
|
case _logo = "logo" |
||||||
|
case _name = "name" |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,52 @@ |
|||||||
|
// |
||||||
|
// TeamScore.swift |
||||||
|
// Padel Tournament |
||||||
|
// |
||||||
|
// Created by razmig on 10/03/2024. |
||||||
|
// |
||||||
|
|
||||||
|
import Foundation |
||||||
|
import LeStorage |
||||||
|
|
||||||
|
@Observable |
||||||
|
class TeamScore: ModelObject, Storable { |
||||||
|
|
||||||
|
static func resourceName() -> String { "team-scores" } |
||||||
|
|
||||||
|
var id: String = Store.randomId() |
||||||
|
var match: String |
||||||
|
var teamRegistration: String? |
||||||
|
var playerRegistrations: [String]? |
||||||
|
var score: String? |
||||||
|
var walkOut: Int? |
||||||
|
var luckyLoser: Bool |
||||||
|
|
||||||
|
internal init(match: String, teamRegistration: String? = nil, playerRegistrations: [String]? = nil, score: String? = nil, walkOut: Int? = nil, luckyLoser: Bool) { |
||||||
|
self.match = match |
||||||
|
self.teamRegistration = teamRegistration |
||||||
|
self.playerRegistrations = playerRegistrations |
||||||
|
self.score = score |
||||||
|
self.walkOut = walkOut |
||||||
|
self.luckyLoser = luckyLoser |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
var team: TeamRegistration? { |
||||||
|
guard let teamRegistration else { |
||||||
|
return nil |
||||||
|
} |
||||||
|
return DataStore.shared.teamRegistrations.findById(teamRegistration) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey { |
||||||
|
case _id = "id" |
||||||
|
case _match = "match" |
||||||
|
case _teamRegistration = "teamRegistration" |
||||||
|
case _playerRegistrations = "playerRegistrations" |
||||||
|
case _score = "score" |
||||||
|
case _walkOut = "walkOut" |
||||||
|
case _luckyLoser = "luckyLoser" |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
// |
||||||
|
// Labels.swift |
||||||
|
// PadelClub |
||||||
|
// |
||||||
|
// Created by Razmig Sarkissian on 23/03/2024. |
||||||
|
// |
||||||
|
|
||||||
|
import SwiftUI |
||||||
|
|
||||||
|
struct LabelOptions: View { |
||||||
|
var body: some View { |
||||||
|
Label("Options", systemImage: "ellipsis.circle") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
struct LabelStructure: View { |
||||||
|
var body: some View { |
||||||
|
Label("Structure", systemImage: "hammer") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
struct LabelSettings: View { |
||||||
|
var body: some View { |
||||||
|
Label("Réglages", systemImage: "slider.horizontal.3") |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,376 @@ |
|||||||
|
// |
||||||
|
// GroupStageView.swift |
||||||
|
// Padel Tournament |
||||||
|
// |
||||||
|
// Created by Razmig Sarkissian on 02/03/2023. |
||||||
|
// |
||||||
|
|
||||||
|
import SwiftUI |
||||||
|
|
||||||
|
struct GroupStageView: View { |
||||||
|
@Bindable var groupStage: GroupStage |
||||||
|
// @State private var selectedMenuLink: MenuLink? |
||||||
|
// @State private var canUpdateTournament: Bool = false |
||||||
|
// @AppStorage("showLongLabel") private var showLongLabel: Bool = false |
||||||
|
// @AppStorage("hideRank") private var hideRank: Bool = false |
||||||
|
@State private var confirmGroupStageStart: Bool = false |
||||||
|
|
||||||
|
enum MenuLink: Int, Identifiable, Hashable { |
||||||
|
var id: Int { self.rawValue } |
||||||
|
case prepare |
||||||
|
} |
||||||
|
|
||||||
|
var groupStageView: some View { |
||||||
|
ForEach(0..<(groupStage.size), id: \.self) { index in |
||||||
|
// let entrant : Entrant? = runningGroupStageOrderedByScore ? groupStage.orderedByScore[Int(index)] : groupStage.entrantAtIndex(Int(index)) |
||||||
|
// if let entrant { |
||||||
|
// GroupStageEntrantMenuView(entrant: entrant, groupStage: groupStage, index: index.intValue) |
||||||
|
// } else { |
||||||
|
Menu { |
||||||
|
// Section { |
||||||
|
// EntrantPickerView(groupStage: groupStage, index: Int(index)) |
||||||
|
// } |
||||||
|
// |
||||||
|
// if let tournament = groupStage.tournament, let deltaLabel = tournament.deltaLabel(index.intValue, groupStageIndex: groupStage.index.intValue) { |
||||||
|
// let date = tournament.localizedDate ?? "" |
||||||
|
// Divider() |
||||||
|
// Section { |
||||||
|
// ShareLink(item: "\(tournament.localizedTitle)\n\(date)\nCherche une équipe dont le poids d'équipe " + deltaLabel) { |
||||||
|
// Text(deltaLabel) |
||||||
|
// } |
||||||
|
// } header: { |
||||||
|
// Text("Remplacer avec un poids d'équipe") |
||||||
|
// } |
||||||
|
// } |
||||||
|
} label: { |
||||||
|
HStack { |
||||||
|
Text("#\(index+1)") |
||||||
|
Text("Aucune équipe") |
||||||
|
} |
||||||
|
} |
||||||
|
// } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
var body: some View { |
||||||
|
Section { |
||||||
|
groupStageView |
||||||
|
// .disabled(canUpdateTournament == false) |
||||||
|
// .sheet(item: $selectedMenuLink) { selectedMenuLink in |
||||||
|
// switch selectedMenuLink { |
||||||
|
// case .prepare: |
||||||
|
// PrepareGroupStageView(groupStage: groupStage) |
||||||
|
// } |
||||||
|
// } |
||||||
|
} header: { |
||||||
|
HStack { |
||||||
|
if groupStage.isBroadcasted() { |
||||||
|
Label(groupStage.title(), systemImage: "airplayvideo") |
||||||
|
} else { |
||||||
|
Text(groupStage.title()) |
||||||
|
} |
||||||
|
Spacer() |
||||||
|
if let startDate = groupStage.startDate { |
||||||
|
Text(startDate.formatted(Date.FormatStyle().weekday(.wide)).capitalized + " à partir de " + startDate.formatted(.dateTime.hour().minute())) |
||||||
|
} |
||||||
|
} |
||||||
|
} footer: { |
||||||
|
HStack { |
||||||
|
if groupStage.matches.isEmpty { |
||||||
|
Button { |
||||||
|
//groupStage.startGroupStage() |
||||||
|
//save() |
||||||
|
} label: { |
||||||
|
Text("Créer les matchs") |
||||||
|
} |
||||||
|
.buttonStyle(.borderless) |
||||||
|
} |
||||||
|
Spacer() |
||||||
|
Menu { |
||||||
|
// Button { |
||||||
|
// selectedMenuLink = .prepare |
||||||
|
// } label: { |
||||||
|
// Label("Préparer", systemImage: "calendar") |
||||||
|
// } |
||||||
|
// |
||||||
|
// Menu { |
||||||
|
// MenuWarnView(warningSender: groupStage) |
||||||
|
// } label: { |
||||||
|
// Label("Prévenir", systemImage: "person.crop.circle") |
||||||
|
// } |
||||||
|
// |
||||||
|
// if groupStage.isBroadcasted() { |
||||||
|
// Button { |
||||||
|
// groupStage.refreshBroadcast() |
||||||
|
// } label: { |
||||||
|
// Label("Rafraîchir", systemImage: "arrow.up.circle.fill") |
||||||
|
// } |
||||||
|
// Button { |
||||||
|
// groupStage.stopBroadcast() |
||||||
|
// save() |
||||||
|
// } label: { |
||||||
|
// Label("Arrêter la diffusion", systemImage: "stop.circle.fill") |
||||||
|
// } |
||||||
|
// } else if groupStage.tournament?.canBroadcast() == true { |
||||||
|
// Button { |
||||||
|
// Task { |
||||||
|
// try? await groupStage.broadcastGroupStage() |
||||||
|
// save() |
||||||
|
// } |
||||||
|
// } label: { |
||||||
|
// Label("Diffuser", systemImage: "airplayvideo") |
||||||
|
// } |
||||||
|
// } |
||||||
|
// |
||||||
|
// Divider() |
||||||
|
// if groupStage.tournament?.canBroadcast() == true { |
||||||
|
// Menu { |
||||||
|
// Button { |
||||||
|
// Task { |
||||||
|
// try? await groupStage.broadcastGroupStageMatches() |
||||||
|
// save() |
||||||
|
// } |
||||||
|
// } label: { |
||||||
|
// Label("Diffuser", systemImage: "airplayvideo") |
||||||
|
// } |
||||||
|
// |
||||||
|
// Button { |
||||||
|
// groupStage.refreshBroadcastMatches() |
||||||
|
// } label: { |
||||||
|
// Label("Rafraîchir", systemImage: "arrow.up.circle.fill") |
||||||
|
// } |
||||||
|
// Button { |
||||||
|
// groupStage.stopBroadcastMatches() |
||||||
|
// save() |
||||||
|
// } label: { |
||||||
|
// Label("Arrêter la diffusion", systemImage: "stop.circle.fill") |
||||||
|
// } |
||||||
|
// } label: { |
||||||
|
// Text("Diffusion des matchs") |
||||||
|
// } |
||||||
|
// } |
||||||
|
// |
||||||
|
// Divider() |
||||||
|
// Menu { |
||||||
|
// if groupStage.orderedMatches.isEmpty == false { |
||||||
|
// Button(role: .destructive) { |
||||||
|
// groupStage.startGroupStage() |
||||||
|
// save() |
||||||
|
// } label: { |
||||||
|
// Label("Re-démarrer les matchs de la \(groupStage.titleLabel.lowercased())", systemImage: "trash") |
||||||
|
// } |
||||||
|
// } |
||||||
|
// |
||||||
|
// if groupStage.orderedMatches.isEmpty == false { |
||||||
|
// Button(role: .destructive) { |
||||||
|
// groupStage.removeMatches() |
||||||
|
// save() |
||||||
|
// } label: { |
||||||
|
// Label("Supprimer les matchs de la \(groupStage.titleLabel.lowercased())", systemImage: "trash") |
||||||
|
// } |
||||||
|
// } |
||||||
|
// |
||||||
|
// Button(role: .destructive) { |
||||||
|
// groupStage.tournament?.completeEntries.filter { $0.groupStagePosition == groupStage.index }.forEach { $0.resetGroupStagePosition() } |
||||||
|
// groupStage.tournament?.removeFromGroupStages(groupStage) |
||||||
|
// groupStage.tournament?.numberOfGroupStages -= 1 |
||||||
|
// save() |
||||||
|
// } label: { |
||||||
|
// Label("Supprimer la \(groupStage.titleLabel.lowercased())", systemImage: "trash") |
||||||
|
// } |
||||||
|
// } label: { |
||||||
|
// Text("Éditer") |
||||||
|
// } |
||||||
|
} label: { |
||||||
|
HStack { |
||||||
|
Spacer() |
||||||
|
Label("Options", systemImage: "ellipsis.circle").labelStyle(.titleOnly) |
||||||
|
} |
||||||
|
} |
||||||
|
.buttonStyle(.borderless) |
||||||
|
} |
||||||
|
} |
||||||
|
// .onAppear { |
||||||
|
// if let tournament = groupStage.tournament { |
||||||
|
// canUpdateTournament = PersistenceController.shared.container.canUpdateRecord(forManagedObjectWith: tournament.objectID) |
||||||
|
// } else { |
||||||
|
// canUpdateTournament = true |
||||||
|
// } |
||||||
|
// } |
||||||
|
} |
||||||
|
|
||||||
|
// func save() { |
||||||
|
// do { |
||||||
|
// groupStage.objectWillChange.send() |
||||||
|
// groupStage.tournament?.orderedGroupStages.forEach { $0.objectWillChange.send() } |
||||||
|
// groupStage.tournament?.objectWillChange.send() |
||||||
|
// |
||||||
|
// try viewContext.save() |
||||||
|
// } catch { |
||||||
|
// // Replace this implementation with code to handle the error appropriately. |
||||||
|
// // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. |
||||||
|
// let nsError = error as NSError |
||||||
|
// fatalError("Unresolved error \(nsError), \(nsError.userInfo)") |
||||||
|
// } |
||||||
|
// } |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
//struct GroupStageEntrantMenuView: View { |
||||||
|
// @ObservedObject var entrant: Entrant |
||||||
|
// @ObservedObject var groupStage: GroupStage |
||||||
|
// @Environment(\.managedObjectContext) private var viewContext |
||||||
|
// @AppStorage("showLongLabel") private var showLongLabel: Bool = false |
||||||
|
// @AppStorage("hideRank") private var hideRank: Bool = false |
||||||
|
// |
||||||
|
// let index: Int |
||||||
|
// |
||||||
|
// var body: some View { |
||||||
|
// Menu { |
||||||
|
// ForEach(entrant.orderedPlayers) { player in |
||||||
|
// Menu { |
||||||
|
// Text(player.formattedRank) |
||||||
|
// Text(player.localizedAge) |
||||||
|
// if let computedClubName = player.computedClubName { |
||||||
|
// Text(computedClubName) |
||||||
|
// } |
||||||
|
// } label: { |
||||||
|
// Text(player.longLabel) |
||||||
|
// } |
||||||
|
// } |
||||||
|
// |
||||||
|
// if groupStage.tournament?.isOver == false { |
||||||
|
// if entrant.qualified == false { |
||||||
|
// Divider() |
||||||
|
// Button { |
||||||
|
// entrant.addToQualifiedGroup() |
||||||
|
// entrant.objectWillChange.send() |
||||||
|
// entrant.orderedGroupStages.forEach { $0.objectWillChange.send() } |
||||||
|
// entrant.currentTournament?.objectWillChange.send() |
||||||
|
// entrant.currentTournament?.orderedMatches.forEach { $0.objectWillChange.send() } |
||||||
|
// save() |
||||||
|
// } label: { |
||||||
|
// Label("Qualifier l'équipe", systemImage: "checkmark") |
||||||
|
// } |
||||||
|
// } |
||||||
|
// |
||||||
|
// Divider() |
||||||
|
// if entrant.qualified { |
||||||
|
// Menu { |
||||||
|
// Button(role: .destructive) { |
||||||
|
// entrant.unqualified() |
||||||
|
// entrant.objectWillChange.send() |
||||||
|
// entrant.orderedGroupStages.forEach { $0.objectWillChange.send() } |
||||||
|
// entrant.currentTournament?.objectWillChange.send() |
||||||
|
// entrant.currentTournament?.orderedMatches.forEach { $0.objectWillChange.send() } |
||||||
|
// save() |
||||||
|
// } label: { |
||||||
|
// Label("Annuler la qualification", systemImage: "xmark") |
||||||
|
// } |
||||||
|
// } label: { |
||||||
|
// Text("Qualification") |
||||||
|
// } |
||||||
|
// } |
||||||
|
// |
||||||
|
// Menu { |
||||||
|
// if let deltaLabel = groupStage.tournament?.deltaLabel(index, groupStageIndex: groupStage.index.intValue) { |
||||||
|
// Section { |
||||||
|
// Button(role: .destructive) { |
||||||
|
// entrant.resetGroupStagePosition() |
||||||
|
// save() |
||||||
|
// } label: { |
||||||
|
// Text(deltaLabel) |
||||||
|
// } |
||||||
|
// Divider() |
||||||
|
// } header: { |
||||||
|
// Text("Toute l'équipe, poids: " + entrant.updatedRank.formatted()) |
||||||
|
// } |
||||||
|
// } |
||||||
|
// |
||||||
|
// ForEach(entrant.orderedPlayers) { player in |
||||||
|
// if let deltaLabel = groupStage.tournament?.playerDeltaLabel(rank: entrant.otherPlayer(player)?.currentRank, positionInGroupStage: index, groupStageIndex: groupStage.index.intValue) { |
||||||
|
// Section { |
||||||
|
// Button(role: .destructive) { |
||||||
|
// entrant.team?.removeFromPlayers(player) |
||||||
|
// save() |
||||||
|
// } label: { |
||||||
|
// Text(deltaLabel) |
||||||
|
// } |
||||||
|
// Divider() |
||||||
|
// } header: { |
||||||
|
// Text(player.longLabel + ", rang: " + player.formattedRank) |
||||||
|
// } |
||||||
|
// } |
||||||
|
// } |
||||||
|
// } label: { |
||||||
|
// Text("Remplacement") |
||||||
|
// } |
||||||
|
// |
||||||
|
// Menu { |
||||||
|
// Button(role: .destructive) { |
||||||
|
// entrant.resetGroupStagePosition() |
||||||
|
// save() |
||||||
|
// } label: { |
||||||
|
// Label("Retirer l'équipe", systemImage: "xmark") |
||||||
|
// } |
||||||
|
// } label: { |
||||||
|
// Text("Retirer") |
||||||
|
// } |
||||||
|
// |
||||||
|
// } |
||||||
|
// } label: { |
||||||
|
// HStack(alignment: .center) { |
||||||
|
// if let tournament = groupStage.tournament, groupStage.hasEnded, groupStage.groupStageRound > 0 { |
||||||
|
// Text("#\(index + Int((groupStage.index - tournament.numberOfGroupStages)*tournament.teamsPerGroupStage) + 1)") |
||||||
|
// } else { |
||||||
|
// Text("#\(index + 1)") |
||||||
|
// } |
||||||
|
// VStack(alignment: .leading, spacing: 0) { |
||||||
|
// if hideRank == false { |
||||||
|
// Text("Poids \(entrant.updatedRank)") |
||||||
|
// .font(.caption) |
||||||
|
// } |
||||||
|
// |
||||||
|
// HStack { |
||||||
|
// if let brand = entrant.team?.brand?.title { |
||||||
|
// Text(brand) |
||||||
|
// } else { |
||||||
|
// |
||||||
|
// VStack(alignment: .leading) { |
||||||
|
// Text(entrant.longLabelPlayerOne) |
||||||
|
// Text(entrant.longLabelPlayerTwo) |
||||||
|
// } |
||||||
|
// |
||||||
|
// } |
||||||
|
// |
||||||
|
// if groupStage.tournament?.isRoundSwissTournament() == true { |
||||||
|
// if entrant.groupStagePosition == groupStage.index { |
||||||
|
// Text("forcé") |
||||||
|
// } else { |
||||||
|
// Text("auto") |
||||||
|
// } |
||||||
|
// } else { |
||||||
|
// if entrant.qualified { |
||||||
|
// Image(systemName: "checkmark.seal") |
||||||
|
// } |
||||||
|
// } |
||||||
|
// } |
||||||
|
// } |
||||||
|
// Spacer() |
||||||
|
// Text(groupStage.scoreLabel(for: entrant.position(in: groupStage))) |
||||||
|
// } |
||||||
|
// } |
||||||
|
// .buttonStyle(.plain) |
||||||
|
// } |
||||||
|
// |
||||||
|
// func save() { |
||||||
|
// do { |
||||||
|
// try viewContext.save() |
||||||
|
// } catch { |
||||||
|
// // Replace this implementation with code to handle the error appropriately. |
||||||
|
// // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. |
||||||
|
// let nsError = error as NSError |
||||||
|
// fatalError("Unresolved error \(nsError), \(nsError.userInfo)") |
||||||
|
// } |
||||||
|
// } |
||||||
|
//} |
||||||
@ -0,0 +1,304 @@ |
|||||||
|
// |
||||||
|
// GroupStagesView.swift |
||||||
|
// Padel Tournament |
||||||
|
// |
||||||
|
// Created by Razmig Sarkissian on 11/12/2023. |
||||||
|
// |
||||||
|
|
||||||
|
import SwiftUI |
||||||
|
|
||||||
|
struct GroupStagesView: View { |
||||||
|
@Environment(Tournament.self) var tournament: Tournament |
||||||
|
@State private var selectedGroupStageIndex: Int = -1 |
||||||
|
@State private var startAllGroupStageConfirmation: Bool = false |
||||||
|
@State private var confirmGroupStageRebuild: Bool = false |
||||||
|
|
||||||
|
func displayGroupStage(_ groupStage: GroupStage) -> Bool { |
||||||
|
selectedGroupStageIndex == groupStage.index || selectedGroupStageIndex == -1 |
||||||
|
} |
||||||
|
|
||||||
|
var dynamicTitle: String { |
||||||
|
switch selectedGroupStageIndex { |
||||||
|
case -1: |
||||||
|
return "Toutes les poules" |
||||||
|
default: |
||||||
|
return tournament.groupStages[selectedGroupStageIndex].title() |
||||||
|
} |
||||||
|
} |
||||||
|
// |
||||||
|
// init(tournament: Tournament) { |
||||||
|
// _tournament = ObservedObject(wrappedValue: tournament) |
||||||
|
// if let index = tournament.orderedGroupStages.firstIndex(where: { $0.isRunning }) { |
||||||
|
// _selectedGroupStageIndex = State(wrappedValue: index.int64Value + 1) |
||||||
|
// } |
||||||
|
// } |
||||||
|
|
||||||
|
var body: some View { |
||||||
|
List { |
||||||
|
if tournament.missingQualifiedFromGroupStages().isEmpty == false && tournament.qualifiedTeams().count >= tournament.qualifiedFromGroupStage() && tournament.groupStageAdditionalQualified > 0 { |
||||||
|
NavigationLink { |
||||||
|
//DrawView(tournament: tournament) |
||||||
|
} label: { |
||||||
|
LabeledContent { |
||||||
|
Text(tournament.moreQualifiedToDraw().formatted() + "/" + tournament.groupStageAdditionalQualified.formatted()) |
||||||
|
} label: { |
||||||
|
Text("Qualifié\(tournament.groupStageAdditionalQualified.pluralSuffix) supplémentaire\(tournament.groupStageAdditionalQualified.pluralSuffix)") |
||||||
|
let message = [tournament.groupStageAdditionalQualified.formatted(), " meilleur", tournament.groupStageAdditionalQualified.pluralSuffix, " ", (tournament.qualifiedPerGroupStage + 1).ordinalFormatted()].joined() |
||||||
|
Text(message) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// if (tournament.groupStagesAreWrong || (tournament.emptySlotInGroupStages > 0 && tournament.entriesCount >= tournament.teamsFromGroupStages)) { |
||||||
|
// Section { |
||||||
|
// RowButtonView(title: "Reconstruire les poules") { |
||||||
|
// confirmGroupStageRebuild = true |
||||||
|
// } |
||||||
|
// .modify { |
||||||
|
// if UIDevice.current.userInterfaceIdiom == .pad { |
||||||
|
// $0.alert("Êtes-vous sûr ?", isPresented: $confirmGroupStageRebuild) { |
||||||
|
// |
||||||
|
// Button(role: .destructive) { |
||||||
|
// tournament.refreshGroupStages() |
||||||
|
// save() |
||||||
|
// } label: { |
||||||
|
// Text("Reconstruire") |
||||||
|
// } |
||||||
|
// |
||||||
|
// |
||||||
|
// Button(role: .cancel) { |
||||||
|
// |
||||||
|
// } label: { |
||||||
|
// Text("Annuler") |
||||||
|
// } |
||||||
|
// } message: { |
||||||
|
// Text("Attention, cela peut modifier les poules existants.") |
||||||
|
// |
||||||
|
// } |
||||||
|
// } else { |
||||||
|
// $0.confirmationDialog("Êtes-vous sûr ?", isPresented: $confirmGroupStageRebuild) { |
||||||
|
// Button(role: .destructive) { |
||||||
|
// tournament.refreshGroupStages() |
||||||
|
// save() |
||||||
|
// } label: { |
||||||
|
// Text("Reconstruire") |
||||||
|
// } |
||||||
|
// } message: { |
||||||
|
// Text("Attention, cela peut modifier les poules existants.") |
||||||
|
// } |
||||||
|
// } |
||||||
|
// } |
||||||
|
// } header: { |
||||||
|
// Text("Erreur détectée") |
||||||
|
// } |
||||||
|
// } |
||||||
|
// |
||||||
|
|
||||||
|
// if tournament.isRoundSwissTournament() == false && (tournament.orderedGroupStages.allSatisfy({ $0.orderedMatches.count > 0 }) == false && tournament.groupStagesAreOver == false && tournament.groupStagesCount > 0) { |
||||||
|
// Section { |
||||||
|
// RowButtonView(title: "Générer les matchs de poules") { |
||||||
|
// startAllGroupStageConfirmation = true |
||||||
|
// } |
||||||
|
// .modify { |
||||||
|
// if UIDevice.current.userInterfaceIdiom == .pad { |
||||||
|
// $0.alert("Êtes-vous sûr ?", isPresented: $startAllGroupStageConfirmation) { |
||||||
|
// Button("Générer") { |
||||||
|
// tournament.orderedGroupStages.forEach { |
||||||
|
// if $0.orderedMatches.isEmpty { |
||||||
|
// $0.startGroupStage() |
||||||
|
// } |
||||||
|
// } |
||||||
|
// save() |
||||||
|
// } |
||||||
|
// Button(role: .cancel) { |
||||||
|
// |
||||||
|
// } label: { |
||||||
|
// Text("Annuler") |
||||||
|
// } |
||||||
|
// } |
||||||
|
// |
||||||
|
// } else { |
||||||
|
// $0.confirmationDialog("Êtes-vous sûr ?", isPresented: $startAllGroupStageConfirmation) { |
||||||
|
// Button("Générer") { |
||||||
|
// tournament.orderedGroupStages.forEach { |
||||||
|
// if $0.orderedMatches.isEmpty { |
||||||
|
// $0.startGroupStage() |
||||||
|
// } |
||||||
|
// } |
||||||
|
// save() |
||||||
|
// } |
||||||
|
// } |
||||||
|
// } |
||||||
|
// } |
||||||
|
// } |
||||||
|
// } |
||||||
|
// |
||||||
|
if tournament.groupStagesAreOver() == false { |
||||||
|
// Section { |
||||||
|
// GroupStageMatchAvailableToStartView(tournament: tournament, groupStageIndex: selectedGroupStageIndex) |
||||||
|
// } header: { |
||||||
|
// if selectedGroupStageIndex == -1 { |
||||||
|
// Text("Matchs de poules prêt à démarrer") |
||||||
|
// } else { |
||||||
|
// Text("Matchs de la poule \(selectedGroupStageIndex) prêt à démarrer") |
||||||
|
// } |
||||||
|
// } footer: { |
||||||
|
// Text("présence d'au moins 2 équipes d'une même poule ayant réglé.") |
||||||
|
// } |
||||||
|
} |
||||||
|
|
||||||
|
// if tournament.teamsPerGroupStage == 3 && tournament.qualifiedPerGroupStage == 1 && tournament.numberOfGroupStages%2 == 0 && tournament.moreQualifiedFromGroupStages == 0 { |
||||||
|
// Section { |
||||||
|
// NavigationLink { |
||||||
|
// GroupStageMissingMatchView(tournament: tournament) |
||||||
|
// } label: { |
||||||
|
// Text("Matchs de classement de poules") |
||||||
|
// } |
||||||
|
// } |
||||||
|
// } |
||||||
|
|
||||||
|
ForEach(tournament.groupStages) { groupStage in |
||||||
|
if displayGroupStage(groupStage) && groupStage.hasEnded() == false { |
||||||
|
GroupStageView(groupStage: groupStage) |
||||||
|
if groupStage.matches.isEmpty == false { |
||||||
|
Section { |
||||||
|
ForEach(groupStage.matches) { match in |
||||||
|
MatchRowView(setupSeedContext: false, matchViewStyle: .sectionedStandardStyle) |
||||||
|
.environment(match) |
||||||
|
} |
||||||
|
} header: { |
||||||
|
Text("Matchs de la " + groupStage.title()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.toolbar { |
||||||
|
ToolbarItem(placement: .principal) { |
||||||
|
if tournament.groupStages.count < 6 { |
||||||
|
Picker(selection: $selectedGroupStageIndex) { |
||||||
|
Text("Toutes").tag(-1) |
||||||
|
ForEach(tournament.groupStages) { groupStage in |
||||||
|
Text(groupStage.title(.short)).tag(groupStage.index) |
||||||
|
} |
||||||
|
} label: { |
||||||
|
|
||||||
|
} |
||||||
|
.labelsHidden() |
||||||
|
.pickerStyle(.segmented) |
||||||
|
} else if tournament.groupStages.count < 8 { |
||||||
|
Picker(selection: $selectedGroupStageIndex) { |
||||||
|
Image(systemName: "square.stack").tag(-1) |
||||||
|
ForEach(tournament.groupStages) { groupStage in |
||||||
|
Text(groupStage.title(.short)).tag(groupStage.index) |
||||||
|
} |
||||||
|
} label: { |
||||||
|
|
||||||
|
} |
||||||
|
.labelsHidden() |
||||||
|
.pickerStyle(.segmented) |
||||||
|
} else { |
||||||
|
Picker(selection: $selectedGroupStageIndex) { |
||||||
|
Text("Voir toutes les poules").tag(-1) |
||||||
|
ForEach(tournament.groupStages) { groupStage in |
||||||
|
Text(groupStage.title()).tag(groupStage.index) |
||||||
|
} |
||||||
|
} label: { |
||||||
|
Text("\(tournament.groupStages.count.formatted()) poules") |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ToolbarItem(placement: .topBarTrailing) { |
||||||
|
Menu { |
||||||
|
// menuAddGroupStage |
||||||
|
// menuBuildAllGroupStages |
||||||
|
// menuGenerateGroupStage(.random) |
||||||
|
// menuGenerateGroupStage(.snake) |
||||||
|
// menuGenerateGroupStage(.swiss) |
||||||
|
} label: { |
||||||
|
LabelOptions() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// |
||||||
|
// var menuBuildAllGroupStages: some View { |
||||||
|
// Button(role: .destructive) { |
||||||
|
// tournament.orderedEntries.forEach { entrant in |
||||||
|
// if entrant.groupStagePosition > 0 { |
||||||
|
// entrant.resetGroupStagePosition() |
||||||
|
// } |
||||||
|
// } |
||||||
|
// tournament.buildGroupStages() |
||||||
|
// do { |
||||||
|
// try viewContext.save() |
||||||
|
// } catch { |
||||||
|
// // Replace this implementation with code to handle the error appropriately. |
||||||
|
// // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. |
||||||
|
// let nsError = error as NSError |
||||||
|
// fatalError("Unresolved error \(nsError), \(nsError.userInfo)") |
||||||
|
// } |
||||||
|
// |
||||||
|
// } label: { |
||||||
|
// Label("Refaire les poules", systemImage: "restart") |
||||||
|
// } |
||||||
|
// } |
||||||
|
// |
||||||
|
// @ViewBuilder |
||||||
|
// func menuGenerateGroupStage(_ mode: GroupStageOrderingMode) -> some View { |
||||||
|
// Button(role: .destructive) { |
||||||
|
// tournament.stopBroadcastGroupStages() |
||||||
|
// tournament.groupStageOrderingMode = mode |
||||||
|
// tournament.refreshGroupStages() |
||||||
|
// save() |
||||||
|
// } label: { |
||||||
|
// Label("Poule \(mode.localizedLabel.lowercased())", systemImage: mode.systemImage) |
||||||
|
// } |
||||||
|
// } |
||||||
|
// |
||||||
|
// func addGroupStage(_ size: Int64) { |
||||||
|
// let groupStage = GroupStage(context: viewContext) |
||||||
|
// groupStage.index = tournament.firstIndexToUseForNewGroupStage |
||||||
|
// groupStage.size = Int64(size) |
||||||
|
// groupStage.matchFormatRawValue = tournament.groupStageMatchFormatRawValue |
||||||
|
// print("addGroupStage groupStagesCount", tournament.groupStagesCount) |
||||||
|
// print("addGroupStage numberOfGroupStages", tournament.numberOfGroupStages) |
||||||
|
// if tournament.groupStagesCount >= tournament.numberOfGroupStages { |
||||||
|
// tournament.numberOfGroupStages += 1 |
||||||
|
// } |
||||||
|
// tournament.addToGroupStages(groupStage) |
||||||
|
// save() |
||||||
|
// } |
||||||
|
// |
||||||
|
// var menuAddGroupStage: some View { |
||||||
|
// Menu { |
||||||
|
// ForEach(-1...1) { index in |
||||||
|
// let i = tournament.teamsPerGroupStage + Int64(index) |
||||||
|
// Button { |
||||||
|
// addGroupStage(i) |
||||||
|
// } label: { |
||||||
|
// Text("Poule de \(i)") |
||||||
|
// } |
||||||
|
// .disabled(i < 2) |
||||||
|
// } |
||||||
|
// } label: { |
||||||
|
// Label("Ajouter une poule", systemImage: "server.rack") |
||||||
|
// } |
||||||
|
// |
||||||
|
// } |
||||||
|
// |
||||||
|
// |
||||||
|
// func save() { |
||||||
|
// do { |
||||||
|
// tournament.objectWillChange.send() |
||||||
|
// try viewContext.save() |
||||||
|
// viewContext.refreshAllObjects() |
||||||
|
// } catch { |
||||||
|
// // Replace this implementation with code to handle the error appropriately. |
||||||
|
// // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. |
||||||
|
// let nsError = error as NSError |
||||||
|
// fatalError("Unresolved error \(nsError), \(nsError.userInfo)") |
||||||
|
// } |
||||||
|
// } |
||||||
|
} |
||||||
@ -0,0 +1,23 @@ |
|||||||
|
// |
||||||
|
// MatchDetailView.swift |
||||||
|
// PadelClub |
||||||
|
// |
||||||
|
// Created by Razmig Sarkissian on 23/03/2024. |
||||||
|
// |
||||||
|
|
||||||
|
import SwiftUI |
||||||
|
|
||||||
|
struct MatchDetailView: View { |
||||||
|
@Environment(Match.self) var match: Match |
||||||
|
let setupSeedContext: Bool |
||||||
|
let matchViewStyle: MatchViewStyle |
||||||
|
|
||||||
|
var body: some View { |
||||||
|
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#Preview { |
||||||
|
MatchDetailView(setupSeedContext: false, matchViewStyle: .standardStyle) |
||||||
|
.environment(Match.mock()) |
||||||
|
} |
||||||
@ -0,0 +1,35 @@ |
|||||||
|
// |
||||||
|
// MatchRowView.swift |
||||||
|
// Padel Tournament |
||||||
|
// |
||||||
|
// Created by Razmig Sarkissian on 25/11/2023. |
||||||
|
// |
||||||
|
|
||||||
|
import SwiftUI |
||||||
|
|
||||||
|
struct MatchRowView: View { |
||||||
|
@Environment(Match.self) var match: Match |
||||||
|
let setupSeedContext: Bool |
||||||
|
let matchViewStyle: MatchViewStyle |
||||||
|
|
||||||
|
@ViewBuilder |
||||||
|
var body: some View { |
||||||
|
if setupSeedContext { |
||||||
|
MatchSummaryView(setupSeedContext: setupSeedContext, matchViewStyle: matchViewStyle) |
||||||
|
} else { |
||||||
|
NavigationLink { |
||||||
|
MatchDetailView(setupSeedContext: setupSeedContext, matchViewStyle: matchViewStyle) |
||||||
|
.environment(match) |
||||||
|
} label: { |
||||||
|
MatchSummaryView(setupSeedContext: setupSeedContext, matchViewStyle: matchViewStyle) |
||||||
|
} |
||||||
|
//.modifier(BroadcastViewModifier(isBroadcasted: match.isBroadcasted())) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#Preview { |
||||||
|
MatchRowView(setupSeedContext: false, matchViewStyle: .standardStyle) |
||||||
|
.environment(Match.mock()) |
||||||
|
} |
||||||
@ -0,0 +1,24 @@ |
|||||||
|
// |
||||||
|
// MatchSummaryView.swift |
||||||
|
// PadelClub |
||||||
|
// |
||||||
|
// Created by Razmig Sarkissian on 23/03/2024. |
||||||
|
// |
||||||
|
|
||||||
|
import SwiftUI |
||||||
|
|
||||||
|
struct MatchSummaryView: View { |
||||||
|
@Environment(Match.self) var match: Match |
||||||
|
let setupSeedContext: Bool |
||||||
|
let matchViewStyle: MatchViewStyle |
||||||
|
|
||||||
|
|
||||||
|
var body: some View { |
||||||
|
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#Preview { |
||||||
|
MatchSummaryView(setupSeedContext: false, matchViewStyle: .standardStyle) |
||||||
|
.environment(Match.mock()) |
||||||
|
} |
||||||
@ -0,0 +1,30 @@ |
|||||||
|
// |
||||||
|
// TournamentRunningView.swift |
||||||
|
// PadelClub |
||||||
|
// |
||||||
|
// Created by Razmig Sarkissian on 23/03/2024. |
||||||
|
// |
||||||
|
|
||||||
|
import SwiftUI |
||||||
|
|
||||||
|
struct TournamentRunningView: View { |
||||||
|
@Environment(Tournament.self) private var tournament: Tournament |
||||||
|
|
||||||
|
@ViewBuilder |
||||||
|
var body: some View { |
||||||
|
Section { |
||||||
|
NavigationLink(value: Screen.groupStage) { |
||||||
|
LabeledContent { |
||||||
|
Text(tournament.groupStageStatus()) |
||||||
|
} label: { |
||||||
|
Text("Poules") |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#Preview { |
||||||
|
TournamentRunningView() |
||||||
|
.environment(Tournament.mock()) |
||||||
|
} |
||||||
Loading…
Reference in new issue