multistore
Razmig Sarkissian 2 years ago
parent 9e2882391b
commit 9758ecfcbc
  1. 12
      PadelClub.xcodeproj/project.pbxproj
  2. 19
      PadelClub/Data/Club.swift
  3. 64
      PadelClub/Data/Court.swift
  4. 2
      PadelClub/Data/DataStore.swift
  5. 26
      PadelClub/Data/Event.swift
  6. 64
      PadelClub/Data/Match.swift
  7. 8
      PadelClub/Data/MockData.swift
  8. 14
      PadelClub/Data/Round.swift
  9. 19
      PadelClub/Data/Tournament.swift
  10. 33
      PadelClub/ViewModel/MatchScheduler.swift
  11. 11
      PadelClub/Views/Calling/CallView.swift
  12. 57
      PadelClub/Views/Club/CourtView.swift
  13. 36
      PadelClub/Views/Components/BarButtonView.swift
  14. 18
      PadelClub/Views/Components/FooterButtonView.swift
  15. 3
      PadelClub/Views/Event/EventCreationView.swift
  16. 23
      PadelClub/Views/Match/MatchDetailView.swift
  17. 4
      PadelClub/Views/Match/MatchSummaryView.swift
  18. 24
      PadelClub/Views/Planning/CourtAvailabilitySettingsView.swift
  19. 21
      PadelClub/Views/Planning/PlanningSettingsView.swift
  20. 4
      PadelClub/Views/Planning/PlanningView.swift
  21. 50
      PadelClub/Views/Tournament/Screen/Components/TournamentClubSettingsView.swift
  22. 2
      PadelClub/Views/Tournament/Screen/Components/TournamentDurationManagerView.swift
  23. 2
      PadelClub/Views/Tournament/Screen/Components/TournamentFieldsManagerView.swift
  24. 59
      PadelClub/Views/Tournament/TournamentView.swift

@ -118,6 +118,7 @@
FF1DC5572BAB3AED00FD8220 /* ClubsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC5562BAB3AED00FD8220 /* ClubsView.swift */; }; FF1DC5572BAB3AED00FD8220 /* ClubsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC5562BAB3AED00FD8220 /* ClubsView.swift */; };
FF1DC5592BAB767000FD8220 /* Tips.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC5582BAB767000FD8220 /* Tips.swift */; }; FF1DC5592BAB767000FD8220 /* Tips.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC5582BAB767000FD8220 /* Tips.swift */; };
FF1DC55B2BAB80C400FD8220 /* DisplayContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC55A2BAB80C400FD8220 /* DisplayContext.swift */; }; FF1DC55B2BAB80C400FD8220 /* DisplayContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DC55A2BAB80C400FD8220 /* DisplayContext.swift */; };
FF1DF49B2BD8D23900822FA0 /* BarButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1DF49A2BD8D23900822FA0 /* BarButtonView.swift */; };
FF2BE4872B85E27400592328 /* LeStorage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C425D4542B6D24E2002A7B48 /* LeStorage.framework */; }; FF2BE4872B85E27400592328 /* LeStorage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C425D4542B6D24E2002A7B48 /* LeStorage.framework */; };
FF2BE4882B85E27400592328 /* LeStorage.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C425D4542B6D24E2002A7B48 /* LeStorage.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; FF2BE4882B85E27400592328 /* LeStorage.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C425D4542B6D24E2002A7B48 /* LeStorage.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
FF3795622B9396D0004EA093 /* PadelClubApp.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = FF3795602B9396D0004EA093 /* PadelClubApp.xcdatamodeld */; }; FF3795622B9396D0004EA093 /* PadelClubApp.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = FF3795602B9396D0004EA093 /* PadelClubApp.xcdatamodeld */; };
@ -220,6 +221,8 @@
FFC83D4F2BB807D100750834 /* RoundsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC83D4E2BB807D100750834 /* RoundsView.swift */; }; FFC83D4F2BB807D100750834 /* RoundsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC83D4E2BB807D100750834 /* RoundsView.swift */; };
FFC83D512BB8087E00750834 /* RoundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC83D502BB8087E00750834 /* RoundView.swift */; }; FFC83D512BB8087E00750834 /* RoundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC83D502BB8087E00750834 /* RoundView.swift */; };
FFC91AF92BD6A09100B29808 /* FortuneWheelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC91AF82BD6A09100B29808 /* FortuneWheelView.swift */; }; FFC91AF92BD6A09100B29808 /* FortuneWheelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC91AF82BD6A09100B29808 /* FortuneWheelView.swift */; };
FFC91B012BD85C2F00B29808 /* Court.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC91B002BD85C2F00B29808 /* Court.swift */; };
FFC91B032BD85E2400B29808 /* CourtView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC91B022BD85E2400B29808 /* CourtView.swift */; };
FFCFBFFE2BBBE86600B82851 /* Algorithms in Frameworks */ = {isa = PBXBuildFile; productRef = FFCFBFFD2BBBE86600B82851 /* Algorithms */; }; FFCFBFFE2BBBE86600B82851 /* Algorithms in Frameworks */ = {isa = PBXBuildFile; productRef = FFCFBFFD2BBBE86600B82851 /* Algorithms */; };
FFCFC00C2BBC3D1E00B82851 /* EditScoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC0012BBC39A600B82851 /* EditScoreView.swift */; }; FFCFC00C2BBC3D1E00B82851 /* EditScoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC0012BBC39A600B82851 /* EditScoreView.swift */; };
FFCFC00E2BBC3D4600B82851 /* PointSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC00D2BBC3D4600B82851 /* PointSelectionView.swift */; }; FFCFC00E2BBC3D4600B82851 /* PointSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCFC00D2BBC3D4600B82851 /* PointSelectionView.swift */; };
@ -412,6 +415,7 @@
FF1DC5562BAB3AED00FD8220 /* ClubsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClubsView.swift; sourceTree = "<group>"; }; FF1DC5562BAB3AED00FD8220 /* ClubsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClubsView.swift; sourceTree = "<group>"; };
FF1DC5582BAB767000FD8220 /* Tips.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tips.swift; sourceTree = "<group>"; }; FF1DC5582BAB767000FD8220 /* Tips.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tips.swift; sourceTree = "<group>"; };
FF1DC55A2BAB80C400FD8220 /* DisplayContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayContext.swift; sourceTree = "<group>"; }; FF1DC55A2BAB80C400FD8220 /* DisplayContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayContext.swift; sourceTree = "<group>"; };
FF1DF49A2BD8D23900822FA0 /* BarButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarButtonView.swift; sourceTree = "<group>"; };
FF3795612B9396D0004EA093 /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = "<group>"; }; FF3795612B9396D0004EA093 /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = "<group>"; };
FF3795652B9399AA004EA093 /* Persistence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = "<group>"; }; FF3795652B9399AA004EA093 /* Persistence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = "<group>"; };
FF3B60A22BC49BBC008C2E66 /* MatchScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchScheduler.swift; sourceTree = "<group>"; }; FF3B60A22BC49BBC008C2E66 /* MatchScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchScheduler.swift; sourceTree = "<group>"; };
@ -513,6 +517,8 @@
FFC83D4E2BB807D100750834 /* RoundsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundsView.swift; sourceTree = "<group>"; }; FFC83D4E2BB807D100750834 /* RoundsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundsView.swift; sourceTree = "<group>"; };
FFC83D502BB8087E00750834 /* RoundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundView.swift; sourceTree = "<group>"; }; FFC83D502BB8087E00750834 /* RoundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundView.swift; sourceTree = "<group>"; };
FFC91AF82BD6A09100B29808 /* FortuneWheelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FortuneWheelView.swift; sourceTree = "<group>"; }; FFC91AF82BD6A09100B29808 /* FortuneWheelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FortuneWheelView.swift; sourceTree = "<group>"; };
FFC91B002BD85C2F00B29808 /* Court.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Court.swift; sourceTree = "<group>"; };
FFC91B022BD85E2400B29808 /* CourtView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourtView.swift; sourceTree = "<group>"; };
FFCFC0012BBC39A600B82851 /* EditScoreView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditScoreView.swift; sourceTree = "<group>"; }; FFCFC0012BBC39A600B82851 /* EditScoreView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditScoreView.swift; sourceTree = "<group>"; };
FFCFC00D2BBC3D4600B82851 /* PointSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointSelectionView.swift; sourceTree = "<group>"; }; FFCFC00D2BBC3D4600B82851 /* PointSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointSelectionView.swift; sourceTree = "<group>"; };
FFCFC0112BBC3E1A00B82851 /* PointView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointView.swift; sourceTree = "<group>"; }; FFCFC0112BBC3E1A00B82851 /* PointView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointView.swift; sourceTree = "<group>"; };
@ -671,6 +677,7 @@
FF025AE82BD1307E00A86CF8 /* MonthData.swift */, FF025AE82BD1307E00A86CF8 /* MonthData.swift */,
FF1DC5522BAB354A00FD8220 /* MockData.swift */, FF1DC5522BAB354A00FD8220 /* MockData.swift */,
FFDB1C6C2BB2A02000F1E467 /* AppSettings.swift */, FFDB1C6C2BB2A02000F1E467 /* AppSettings.swift */,
FFC91B002BD85C2F00B29808 /* Court.swift */,
FF6EC9012B94799200EA7F5A /* Coredata */, FF6EC9012B94799200EA7F5A /* Coredata */,
FF6EC9022B9479B900EA7F5A /* Federal */, FF6EC9022B9479B900EA7F5A /* Federal */,
); );
@ -748,6 +755,7 @@
FFBF065D2BBD8040009D6715 /* MatchListView.swift */, FFBF065D2BBD8040009D6715 /* MatchListView.swift */,
FF967CF72BAEDF0000A9A3BD /* Labels.swift */, FF967CF72BAEDF0000A9A3BD /* Labels.swift */,
FFC91AF82BD6A09100B29808 /* FortuneWheelView.swift */, FFC91AF82BD6A09100B29808 /* FortuneWheelView.swift */,
FF1DF49A2BD8D23900822FA0 /* BarButtonView.swift */,
); );
path = Components; path = Components;
sourceTree = "<group>"; sourceTree = "<group>";
@ -869,6 +877,7 @@
FF1DC5542BAB36DD00FD8220 /* CreateClubView.swift */, FF1DC5542BAB36DD00FD8220 /* CreateClubView.swift */,
FFC1E10B2BAC7FB0008D6F59 /* ClubImportView.swift */, FFC1E10B2BAC7FB0008D6F59 /* ClubImportView.swift */,
FF5D0D882BB4935C005CB568 /* ClubRowView.swift */, FF5D0D882BB4935C005CB568 /* ClubRowView.swift */,
FFC91B022BD85E2400B29808 /* CourtView.swift */,
); );
path = Club; path = Club;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1443,6 +1452,7 @@
FFC1E10A2BAC2A77008D6F59 /* NetworkFederalService.swift in Sources */, FFC1E10A2BAC2A77008D6F59 /* NetworkFederalService.swift in Sources */,
FF025AEF2BD1AE9400A86CF8 /* DurationSettingsView.swift in Sources */, FF025AEF2BD1AE9400A86CF8 /* DurationSettingsView.swift in Sources */,
FF025AED2BD1513700A86CF8 /* AppScreen.swift in Sources */, FF025AED2BD1513700A86CF8 /* AppScreen.swift in Sources */,
FFC91B032BD85E2400B29808 /* CourtView.swift in Sources */,
FFCFC00E2BBC3D4600B82851 /* PointSelectionView.swift in Sources */, FFCFC00E2BBC3D4600B82851 /* PointSelectionView.swift in Sources */,
FF089EB62BB00A3800F0AEC7 /* TeamRowView.swift in Sources */, FF089EB62BB00A3800F0AEC7 /* TeamRowView.swift in Sources */,
FF92680B2BCEE3E10080F940 /* ContactManager.swift in Sources */, FF92680B2BCEE3E10080F940 /* ContactManager.swift in Sources */,
@ -1467,6 +1477,7 @@
C4A47D5A2B6D383C00ADC637 /* Tournament.swift in Sources */, C4A47D5A2B6D383C00ADC637 /* Tournament.swift in Sources */,
C4A47D7B2B73C0F900ADC637 /* TournamentV2.swift in Sources */, C4A47D7B2B73C0F900ADC637 /* TournamentV2.swift in Sources */,
FF3795662B9399AA004EA093 /* Persistence.swift in Sources */, FF3795662B9399AA004EA093 /* Persistence.swift in Sources */,
FF1DF49B2BD8D23900822FA0 /* BarButtonView.swift in Sources */,
FFF964502BC25E3700EEF017 /* PlanningView.swift in Sources */, FFF964502BC25E3700EEF017 /* PlanningView.swift in Sources */,
FF967CEC2BAECB9900A9A3BD /* Match.swift in Sources */, FF967CEC2BAECB9900A9A3BD /* Match.swift in Sources */,
FF8F264B2BAE0B4100650388 /* TournamentLevelPickerView.swift in Sources */, FF8F264B2BAE0B4100650388 /* TournamentLevelPickerView.swift in Sources */,
@ -1573,6 +1584,7 @@
FFCFC0182BBC5A6800B82851 /* SetLabelView.swift in Sources */, FFCFC0182BBC5A6800B82851 /* SetLabelView.swift in Sources */,
FFF9645B2BC2D53B00EEF017 /* GroupStageScheduleEditorView.swift in Sources */, FFF9645B2BC2D53B00EEF017 /* GroupStageScheduleEditorView.swift in Sources */,
C4A47DA62B83948E00ADC637 /* LoginView.swift in Sources */, C4A47DA62B83948E00ADC637 /* LoginView.swift in Sources */,
FFC91B012BD85C2F00B29808 /* Court.swift in Sources */,
FF967CF82BAEDF0000A9A3BD /* Labels.swift in Sources */, FF967CF82BAEDF0000A9A3BD /* Labels.swift in Sources */,
FF089EB42BB0020000F0AEC7 /* PlayerSexPickerView.swift in Sources */, FF089EB42BB0020000F0AEC7 /* PlayerSexPickerView.swift in Sources */,
FF9267FF2BCE94830080F940 /* CallSettingsView.swift in Sources */, FF9267FF2BCE94830080F940 /* CallSettingsView.swift in Sources */,

@ -32,8 +32,7 @@ class Club : ModelObject, Storable, Hashable {
var zipCode: String? var zipCode: String?
var latitude: Double? var latitude: Double?
var longitude: Double? var longitude: Double?
var courtCount: Int? //var courtCount: Int?
var courtNames: [String]? = nil
internal init(name: String, acronym: String? = nil, phone: String? = nil, code: String? = nil, address: String? = nil, city: String? = nil, zipCode: String? = nil, latitude: Double? = nil, longitude: Double? = nil) { internal init(name: String, acronym: String? = nil, phone: String? = nil, code: String? = nil, address: String? = nil, city: String? = nil, zipCode: String? = nil, latitude: Double? = nil, longitude: Double? = nil) {
self.name = name self.name = name
@ -47,7 +46,21 @@ class Club : ModelObject, Storable, Hashable {
self.longitude = longitude self.longitude = longitude
} }
func clubTitle(_ displayStyle: DisplayStyle = .wide) -> String {
switch displayStyle {
case .wide:
return name
case .short:
return acronym
}
}
var courts: [Court] {
Store.main.filter { $0.club == self.id }.sorted(by: \.index)
}
override func deleteDependencies() throws { override func deleteDependencies() throws {
try Store.main.deleteDependencies(items: self.courts)
} }
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
@ -61,8 +74,6 @@ class Club : ModelObject, Storable, Hashable {
case _zipCode = "zipCode" case _zipCode = "zipCode"
case _latitude = "latitude" case _latitude = "latitude"
case _longitude = "longitude" case _longitude = "longitude"
case _courtCount = "courtCount"
case _courtNames = "courtNames"
} }
} }

@ -0,0 +1,64 @@
//
// Court.swift
// PadelClub
//
// Created by Razmig Sarkissian on 23/04/2024.
//
import Foundation
import SwiftUI
import LeStorage
@Observable
class Court : ModelObject, Storable, Hashable {
static func resourceName() -> String { return "courts" }
static func == (lhs: Court, rhs: Court) -> Bool {
lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
return hasher.combine(id)
}
var id: String = Store.randomId()
var index: Int
var club: String
var name: String?
var exitAllowed: Bool = false
var indoor: Bool = false
internal init(club: String, name: String? = nil, index: Int) {
self.club = club
self.name = name
self.index = index
}
func courtTitle() -> String {
self.name ?? courtIndexTitle()
}
func courtIndexTitle() -> String {
Self.courtIndexedTitle(atIndex: index)
}
static func courtIndexedTitle(atIndex index: Int) -> String {
("Terrain #" + (index + 1).formatted())
}
func clubObject() -> Club? {
Store.main.findById(club)
}
override func deleteDependencies() throws {
}
enum CodingKeys: String, CodingKey {
case _id = "id"
case _index = "index"
case _club = "club"
case _name = "name"
case _exitAllowed = "exitAllowed"
case _indoor = "indoor"
}
}

@ -17,6 +17,7 @@ class DataStore: ObservableObject {
fileprivate(set) var tournaments: StoredCollection<Tournament> fileprivate(set) var tournaments: StoredCollection<Tournament>
fileprivate(set) var clubs: StoredCollection<Club> fileprivate(set) var clubs: StoredCollection<Club>
fileprivate(set) var courts: StoredCollection<Court>
fileprivate(set) var events: StoredCollection<Event> fileprivate(set) var events: StoredCollection<Event>
fileprivate(set) var groupStages: StoredCollection<GroupStage> fileprivate(set) var groupStages: StoredCollection<GroupStage>
fileprivate(set) var matches: StoredCollection<Match> fileprivate(set) var matches: StoredCollection<Match>
@ -67,6 +68,7 @@ class DataStore: ObservableObject {
let indexed : Bool = true let indexed : Bool = true
self.clubs = store.registerCollection(synchronized: false, indexed: indexed) self.clubs = store.registerCollection(synchronized: false, indexed: indexed)
self.courts = store.registerCollection(synchronized: false, indexed: indexed)
self.tournaments = store.registerCollection(synchronized: false, indexed: indexed) self.tournaments = store.registerCollection(synchronized: false, indexed: indexed)
self.events = store.registerCollection(synchronized: false, indexed: indexed) self.events = store.registerCollection(synchronized: false, indexed: indexed)
self.groupStages = store.registerCollection(synchronized: false, indexed: indexed) self.groupStages = store.registerCollection(synchronized: false, indexed: indexed)

@ -17,21 +17,21 @@ class Event: ModelObject, Storable {
var club: String? var club: String?
var creationDate: Date = Date() var creationDate: Date = Date()
var name: String? var name: String?
var courtCount: Int? //var courtCount: Int?
var tenupId: String? var tenupId: String?
var groupStageFormat: Int? // var groupStageFormat: Int?
var roundFormat: Int? // var roundFormat: Int?
var loserRoundFormat: Int? // var loserRoundFormat: Int?
//var timeslots ? //var timeslots ?
internal init(club: String? = nil, name: String? = nil, courtCount: Int? = nil, tenupId: String? = nil, groupStageFormat: Int? = nil, roundFormat: Int? = nil, loserRoundFormat: Int? = nil) { internal init(club: String? = nil, name: String? = nil, tenupId: String? = nil) {
self.club = club self.club = club
self.name = name self.name = name
self.courtCount = courtCount // self.courtCount = courtCount
self.tenupId = tenupId self.tenupId = tenupId
self.groupStageFormat = groupStageFormat // self.groupStageFormat = groupStageFormat
self.roundFormat = roundFormat // self.roundFormat = roundFormat
self.loserRoundFormat = loserRoundFormat // self.loserRoundFormat = loserRoundFormat
} }
var clubObject: Club? { var clubObject: Club? {
@ -58,10 +58,10 @@ extension Event {
case _club = "club" case _club = "club"
case _creationDate = "creationDate" case _creationDate = "creationDate"
case _name = "name" case _name = "name"
case _courtCount = "courtCount" //case _courtCount = "courtCount"
case _tenupId = "tenupId" case _tenupId = "tenupId"
case _groupStageFormat = "groupStageFormat" // case _groupStageFormat = "groupStageFormat"
case _roundFormat = "roundFormat" // case _roundFormat = "roundFormat"
case _loserRoundFormat = "loserRoundFormat" // case _loserRoundFormat = "loserRoundFormat"
} }
} }

@ -20,30 +20,30 @@ class Match: ModelObject, Storable {
var endDate: Date? var endDate: Date?
var index: Int var index: Int
var format: Int? var format: Int?
var court: String? //var court: String?
var servingTeamId: String? var servingTeamId: String?
var winningTeamId: String? var winningTeamId: String?
var losingTeamId: String? var losingTeamId: String?
var broadcasted: Bool //var broadcasted: Bool
var name: String? //var name: String?
var order: Int //var order: Int
var disabled: Bool = false var disabled: Bool = false
var courtIndex: Int? private(set) var courtIndex: 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) { internal init(round: String? = nil, groupStage: String? = nil, startDate: Date? = nil, endDate: Date? = nil, index: Int, matchFormat: MatchFormat? = nil, servingTeamId: String? = nil, winningTeamId: String? = nil, losingTeamId: String? = nil) {
self.round = round self.round = round
self.groupStage = groupStage self.groupStage = groupStage
self.startDate = startDate self.startDate = startDate
self.endDate = endDate self.endDate = endDate
self.index = index self.index = index
self.format = matchFormat?.rawValue self.format = matchFormat?.rawValue
self.court = court //self.court = court
self.servingTeamId = servingTeamId self.servingTeamId = servingTeamId
self.winningTeamId = winningTeamId self.winningTeamId = winningTeamId
self.losingTeamId = losingTeamId self.losingTeamId = losingTeamId
self.broadcasted = broadcasted // self.broadcasted = broadcasted
self.name = name // self.name = name
self.order = order // self.order = order
} }
func indexInRound() -> Int { func indexInRound() -> Int {
@ -111,7 +111,7 @@ class Match: ModelObject, Storable {
losingTeamId = nil losingTeamId = nil
winningTeamId = nil winningTeamId = nil
endDate = nil endDate = nil
court = nil removeCourt()
servingTeamId = nil servingTeamId = nil
} }
@ -373,10 +373,11 @@ class Match: ModelObject, Storable {
switch fieldSetup { switch fieldSetup {
case .random: case .random:
let courtName = availableCourts().randomElement() if let _courtIndex = availableCourts().randomElement() {
court = courtName setCourt(_courtIndex)
case .field(let courtName): }
court = courtName case .field(let _courtIndex):
setCourt(_courtIndex)
} }
} else { } else {
@ -385,10 +386,13 @@ class Match: ModelObject, Storable {
} }
} }
func getCourtIndex() -> Int? { func courtName() -> String? {
guard let court else { return nil } guard let courtIndex else { return nil }
if let courtIndex = Int(court) { return courtIndex - 1 } if let courtName = currentTournament()?.courtName(atIndex: courtIndex) {
return nil return courtName
} else {
return Court.courtIndexedTitle(atIndex: courtIndex)
}
} }
func courtCount() -> Int { func courtCount() -> Int {
@ -397,7 +401,7 @@ class Match: ModelObject, Storable {
func courtIsAvailable(_ courtIndex: Int) -> Bool { func courtIsAvailable(_ courtIndex: Int) -> Bool {
let courtUsed = currentTournament()?.courtUsed() ?? [] let courtUsed = currentTournament()?.courtUsed() ?? []
return courtUsed.contains(String(courtIndex)) == false return courtUsed.contains(courtIndex) == false
// return Set(availableCourts().map { String($0) }).subtracting(Set(courtUsed)) // return Set(availableCourts().map { String($0) }).subtracting(Set(courtUsed))
} }
@ -405,18 +409,18 @@ class Match: ModelObject, Storable {
false false
} }
func availableCourts() -> [String] { func availableCourts() -> [Int] {
let courtUsed = currentTournament()?.courtUsed() ?? [] let courtUsed = currentTournament()?.courtUsed() ?? []
let availableCourts = Array(1...courtCount()) let availableCourts = Array(0..<courtCount())
return Array(Set(availableCourts.map { String($0) }).subtracting(Set(courtUsed))) return Array(Set(availableCourts.map { $0 }).subtracting(Set(courtUsed)))
} }
func removeCourt() { func removeCourt() {
court = nil courtIndex = nil
} }
func setCourt(_ courtIndex: Int) { func setCourt(_ courtIndex: Int) {
court = String(courtIndex) self.courtIndex = courtIndex
} }
func canBeStarted(inMatches matches: [Match]) -> Bool { func canBeStarted(inMatches matches: [Match]) -> Bool {
@ -605,14 +609,14 @@ class Match: ModelObject, Storable {
case _endDate = "endDate" case _endDate = "endDate"
case _index = "index" case _index = "index"
case _format = "format" case _format = "format"
case _court = "court" // case _court = "court"
case _courtIndex = "courtIndex" case _courtIndex = "courtIndex"
case _servingTeamId = "servingTeamId" case _servingTeamId = "servingTeamId"
case _winningTeamId = "winningTeamId" case _winningTeamId = "winningTeamId"
case _losingTeamId = "losingTeamId" case _losingTeamId = "losingTeamId"
case _broadcasted = "broadcasted" // case _broadcasted = "broadcasted"
case _name = "name" // case _name = "name"
case _order = "order" // case _order = "order"
case _disabled = "disabled" case _disabled = "disabled"
} }
} }
@ -629,7 +633,7 @@ enum MatchDateSetup: Hashable, Identifiable {
enum MatchFieldSetup: Hashable, Identifiable { enum MatchFieldSetup: Hashable, Identifiable {
case random case random
// case firstAvailable // case firstAvailable
case field(String) case field(Int)
var id: Int { hashValue } var id: Int { hashValue }
} }

@ -7,6 +7,12 @@
import Foundation import Foundation
extension Court {
static func mock() -> Court {
Court(club: "", name: "Test", index: 0)
}
}
extension Club { extension Club {
static func mock() -> Club { static func mock() -> Club {
Club(name: "AUC", acronym: "AUC") Club(name: "AUC", acronym: "AUC")
@ -53,7 +59,7 @@ extension Tournament {
extension Match { extension Match {
static func mock() -> Match { static func mock() -> Match {
Match(index: 0, broadcasted: false, order: 0) Match(index: 0)
} }
} }

@ -273,8 +273,8 @@ class Round: ModelObject, Storable {
var cumulativeMatchCount: Int { var cumulativeMatchCount: Int {
var totalMatches = playedMatches().count var totalMatches = playedMatches().count
if let parent = parentRound { if let parentRound {
totalMatches += parent.cumulativeMatchCount totalMatches += parentRound.cumulativeMatchCount
} }
return totalMatches return totalMatches
} }
@ -294,8 +294,8 @@ class Round: ModelObject, Storable {
var theoryCumulativeMatchCount: Int { var theoryCumulativeMatchCount: Int {
var totalMatches = RoundRule.numberOfMatches(forRoundIndex: index) var totalMatches = RoundRule.numberOfMatches(forRoundIndex: index)
if let parent = parentRound { if let parentRound {
totalMatches += parent.theoryCumulativeMatchCount totalMatches += parentRound.theoryCumulativeMatchCount
} }
return totalMatches return totalMatches
} }
@ -329,7 +329,7 @@ class Round: ModelObject, Storable {
if let previousRound = previousRound() { if let previousRound = previousRound() {
return previousRound.seedInterval()?.chunks()?.first return previousRound.seedInterval()?.chunks()?.first
} else if let parentRound = parentRound { } else if let parentRound {
return parentRound.seedInterval()?.chunks()?.last return parentRound.seedInterval()?.chunks()?.last
} }
@ -398,8 +398,8 @@ class Round: ModelObject, Storable {
} }
var parentRound: Round? { var parentRound: Round? {
guard let parentRound = loser else { return nil } guard let parent = loser else { return nil }
return Store.main.findById(parentRound) return Store.main.findById(parent)
} }
func updateMatchFormat(_ matchFormat: MatchFormat) { func updateMatchFormat(_ matchFormat: MatchFormat) {

@ -100,15 +100,9 @@ class Tournament : ModelObject, Storable {
case build case build
} }
func getCourtIndex(_ court: String?) -> Int? { func courtUsed() -> [Int] {
guard let court else { return nil }
if let courtIndex = Int(court) { return courtIndex - 1 }
return nil
}
func courtUsed() -> [String] {
let runningMatches : [Match] = Store.main.filter(isIncluded: { $0.isRunning() }).filter({ $0.tournamentId() == self.id }) let runningMatches : [Match] = Store.main.filter(isIncluded: { $0.isRunning() }).filter({ $0.tournamentId() == self.id })
return Set(runningMatches.compactMap { $0.court }).sorted() return Set(runningMatches.compactMap { $0.courtIndex }).sorted()
} }
func hasStarted() -> Bool { func hasStarted() -> Bool {
@ -1083,6 +1077,15 @@ class Tournament : ModelObject, Storable {
currentMonthData()?.femaleUnrankedValue currentMonthData()?.femaleUnrankedValue
} }
func courtName(atIndex courtIndex: Int) -> String {
let courts = club()?.courts
if let courts, let court = courts.first(where: { $0.index == courtIndex }) {
return court.courtTitle()
} else {
return Court.courtIndexedTitle(atIndex: courtIndex)
}
}
} }
extension Tournament { extension Tournament {

@ -260,13 +260,13 @@ class MatchScheduler {
) )
} }
func getAvailableCourts(from matches: [Match]) -> [(String, Date)] { func getAvailableCourts(from matches: [Match]) -> [(Int, Date)] {
let validMatches = matches.filter({ $0.court != nil && $0.startDate != nil }) let validMatches = matches.filter({ $0.courtIndex != nil && $0.startDate != nil })
let byCourt = Dictionary(grouping: validMatches, by: { $0.court! }) let byCourt = Dictionary(grouping: validMatches, by: { $0.courtIndex! })
return (byCourt.keys.flatMap { court in return (byCourt.keys.flatMap { court in
let matchesByCourt = byCourt[court]?.sorted(by: \.startDate!) let matchesByCourt = byCourt[court]?.sorted(by: \.startDate!)
let lastMatch = matchesByCourt?.last let lastMatch = matchesByCourt?.last
var results = [(String, Date)]() var results = [(Int, Date)]()
if let courtFreeDate = lastMatch?.estimatedEndDate(additionalEstimationDuration) { if let courtFreeDate = lastMatch?.estimatedEndDate(additionalEstimationDuration) {
results.append((court, courtFreeDate)) results.append((court, courtFreeDate))
} }
@ -290,7 +290,7 @@ class MatchScheduler {
rotationIndex += 1 rotationIndex += 1
} }
let timeMatch = TimeMatch(matchID: match.id, rotationIndex: rotationIndex, courtIndex: match.getCourtIndex() ?? 0, startDate: match.startDate!, durationLeft: match.matchFormat.getEstimatedDuration(additionalEstimationDuration), minimumBreakTime: match.matchFormat.breakTime.breakTime) let timeMatch = TimeMatch(matchID: match.id, rotationIndex: rotationIndex, courtIndex: match.courtIndex ?? 0, startDate: match.startDate!, durationLeft: match.matchFormat.getEstimatedDuration(additionalEstimationDuration), minimumBreakTime: match.matchFormat.breakTime.breakTime)
slots.append(timeMatch) slots.append(timeMatch)
} }
@ -464,27 +464,6 @@ class MatchScheduler {
let upperRounds = tournament.rounds() let upperRounds = tournament.rounds()
let allMatches = tournament.allMatches() let allMatches = tournament.allMatches()
// if dayOne < tournament.courtCount {
// let startOfDay = startDate.startOfDay
// let endOfday = Calendar.current.dateInterval(of: .day, for: startOfDay)!.end
// let dateInterval = DateInterval(startDate: startOfDay, endDate: endOfday)
// let _courtsUnavailability = courtsUnavailability ?? [:]()
// let data = _courtsUnavailability[courtCount - 1] ?? [DateInterval]()
// data.append(dateInterval)
// courtsUnavailability = _courtsUnavailability
// }
//
// if dayTwo < tournament.courtCount {
// let startOfDay = startDate.startOfDay
// let endOfday = Calendar.current.dateInterval(of: .day, for: startOfDay)!.end
// let dateInterval = DateInterval(startDate: startOfDay, endDate: endOfday)
// let _courtsUnavailability = courtsUnavailability ?? [:]()
// let data = _courtsUnavailability[courtCount - 1] ?? [DateInterval]()
// data.append(dateInterval)
// courtsUnavailability = _courtsUnavailability
// }
let rounds = upperRounds.map { let rounds = upperRounds.map {
$0 $0
} + upperRounds.flatMap { } + upperRounds.flatMap {
@ -520,7 +499,7 @@ class MatchScheduler {
let usedCourts = getAvailableCourts(from: allMatches.filter({ $0.startDate?.isEarlierThan(startDate) == true && $0.startDate?.dayInt == startDate.dayInt })) let usedCourts = getAvailableCourts(from: allMatches.filter({ $0.startDate?.isEarlierThan(startDate) == true && $0.startDate?.dayInt == startDate.dayInt }))
let initialCourts = usedCourts.filter { (court, availableDate) in let initialCourts = usedCourts.filter { (court, availableDate) in
availableDate <= startDate availableDate <= startDate
}.sorted(by: \.1).compactMap { tournament.getCourtIndex($0.0) } }.sorted(by: \.1).compactMap { $0.0 }
let courts : [Int]? = initialCourts.isEmpty ? nil : initialCourts let courts : [Int]? = initialCourts.isEmpty ? nil : initialCourts

@ -118,9 +118,9 @@ struct CallView: View {
Text(message) Text(message)
} }
.sheet(item: $contactType) { contactType in .sheet(item: $contactType) { contactType in
Group {
switch contactType { switch contactType {
case .message(_, let recipients, let body, _): case .message(_, let recipients, let body, _):
if Guard.main.paymentForNewTournament() != nil { if Guard.main.paymentForNewTournament() != nil {
MessageComposeView(recipients: recipients, body: body) { result in MessageComposeView(recipients: recipients, body: body) { result in
switch result { switch result {
@ -142,14 +142,8 @@ struct CallView: View {
} else { } else {
SubscriptionView(showLackOfPlanMessage: true) SubscriptionView(showLackOfPlanMessage: true)
} }
<<<<<<< HEAD
=======
.tint(.master)
>>>>>>> 6547a8de016666a19407c6cf8b30e91087f201e2
case .mail(_, let recipients, let bccRecipients, let body, let subject, _): case .mail(_, let recipients, let bccRecipients, let body, let subject, _):
if Guard.main.paymentForNewTournament() != nil { if Guard.main.paymentForNewTournament() != nil {
MailComposeView(recipients: recipients, bccRecipients: bccRecipients, body: body, subject: subject) { result in MailComposeView(recipients: recipients, bccRecipients: bccRecipients, body: body, subject: subject) { result in
switch result { switch result {
case .cancelled, .saved: case .cancelled, .saved:
@ -172,8 +166,9 @@ struct CallView: View {
} else { } else {
SubscriptionView(showLackOfPlanMessage: true) SubscriptionView(showLackOfPlanMessage: true)
} }
.tint(.master)
} }
} }
.tint(.master)
}
} }
} }

@ -0,0 +1,57 @@
//
// CourtView.swift
// PadelClub
//
// Created by Razmig Sarkissian on 23/04/2024.
//
import SwiftUI
struct CourtView: View {
@EnvironmentObject var dataStore: DataStore
@Bindable var court: Court
@State private var name: String = ""
init(court: Court) {
self.court = court
_name = State(wrappedValue: court.name ?? "")
}
var body: some View {
Form {
Section {
LabeledContent {
TextField("Nom", text: $name)
.keyboardType(.alphabet)
.multilineTextAlignment(.trailing)
.frame(maxWidth: .infinity)
} label: {
Text("Nom du terrain")
}
}
Section {
Toggle(isOn: $court.exitAllowed) {
Text("Sortie authorisée")
}
Toggle(isOn: $court.indoor) {
Text("Terrain intérieur")
}
}
}
.onChange(of: name) {
court.name = name
try? dataStore.courts.addOrUpdate(instance: court)
}
.onChange(of: [court.indoor, court.exitAllowed]) {
try? dataStore.courts.addOrUpdate(instance: court)
}
.navigationTitle(court.courtTitle())
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar)
}
}
#Preview {
CourtView(court: Court.mock())
}

@ -0,0 +1,36 @@
//
// BarButtonView.swift
// PadelClub
//
// Created by Razmig Sarkissian on 24/04/2024.
//
import SwiftUI
struct BarButtonView: View {
let accessibilityLabel: String
let icon: String
let action: () -> ()
init(_ accessibilityLabel: String, icon: String, action: @escaping () -> Void) {
self.accessibilityLabel = accessibilityLabel
self.icon = icon
self.action = action
}
var body: some View {
Button(action: {
action()
}) {
Label {
Text(accessibilityLabel)
} icon: {
Image(systemName: icon)
.resizable()
.scaledToFit()
.frame(minHeight: 28)
}
.labelStyle(.iconOnly)
}
}
}

@ -8,11 +8,21 @@
import SwiftUI import SwiftUI
struct FooterButtonView: View { struct FooterButtonView: View {
let title: String
let action: () -> ()
init(_ title: String, action: @escaping () -> Void) {
self.title = title
self.action = action
}
var body: some View { var body: some View {
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) Button {
action()
} label: {
Text(title)
.underline()
} }
.buttonStyle(.borderless)
} }
#Preview {
FooterButtonView()
} }

@ -42,7 +42,7 @@ struct EventCreationView: View {
if eventType == .approvedTournament { if eventType == .approvedTournament {
LabeledContent { LabeledContent {
StepperView(count: $duration, minimum: 1, maximum: 3) StepperView(count: $duration, minimum: 1)
} label: { } label: {
Text("Durée") Text("Durée")
Text("\(duration) jour" + duration.pluralSuffix) Text("\(duration) jour" + duration.pluralSuffix)
@ -99,6 +99,7 @@ struct EventCreationView: View {
} }
tournaments.forEach { tournament in tournaments.forEach { tournament in
tournament.courtCount = selectedClub?.courts.count ?? 2
tournament.startDate = startingDate tournament.startDate = startingDate
tournament.dayDuration = duration tournament.dayDuration = duration
tournament.setupFederalSettings() tournament.setupFederalSettings()

@ -29,7 +29,7 @@ struct MatchDetailView: View {
self.match = match self.match = match
self.matchViewStyle = matchViewStyle self.matchViewStyle = matchViewStyle
if match.hasStarted() == false && (match.startDate == nil || match.court == nil) { if match.hasStarted() == false && (match.startDate == nil || match.courtIndex == nil) {
_isEditing = State(wrappedValue: true) _isEditing = State(wrappedValue: true)
} }
@ -44,8 +44,8 @@ struct MatchDetailView: View {
_endDate = State(wrappedValue: endDate) _endDate = State(wrappedValue: endDate)
} }
if let court = match.court { if let courtIndex = match.courtIndex {
_fieldSetup = State(wrappedValue: .field(court)) _fieldSetup = State(wrappedValue: .field(courtIndex))
} }
} }
@ -57,17 +57,19 @@ struct MatchDetailView: View {
match.removeCourt() match.removeCourt()
save() save()
} }
ForEach(1...match.courtCount(), id: \.self) { courtIndex in if let tournament = match.currentTournament() {
Button("Terrain #\(courtIndex.formatted())") { ForEach(0..<tournament.courtCount, id: \.self) { courtIndex in
Button(tournament.courtName(atIndex: courtIndex)) {
match.setCourt(courtIndex) match.setCourt(courtIndex)
save() save()
} }
} }
}
} label: { } label: {
VStack(alignment: .leading) { VStack(alignment: .leading) {
Text("terrain").font(.footnote).foregroundStyle(.secondary) Text("terrain").font(.footnote).foregroundStyle(.secondary)
if let court = match.court { if let courtName = match.courtName() {
Text("#" + court) Text(courtName)
.foregroundStyle(Color.master) .foregroundStyle(Color.master)
.underline() .underline()
} else { } else {
@ -364,9 +366,10 @@ struct MatchDetailView: View {
Picker(selection: $fieldSetup) { Picker(selection: $fieldSetup) {
Text("Au hasard").tag(MatchFieldSetup.random) Text("Au hasard").tag(MatchFieldSetup.random)
//Text("Premier disponible").tag(MatchFieldSetup.firstAvailable) //Text("Premier disponible").tag(MatchFieldSetup.firstAvailable)
ForEach(1...match.courtCount(), id: \.self) { courtIndex in if let tournament = match.currentTournament() {
Text("Terrain #\(courtIndex)") ForEach(0..<tournament.courtCount, id: \.self) { courtIndex in
.tag(MatchFieldSetup.field(String(courtIndex))) Text(tournament.courtName(atIndex: courtIndex)) .tag(MatchFieldSetup.field(courtIndex))
}
} }
} label: { } label: {
Text("Choix du terrain") Text("Choix du terrain")

@ -74,9 +74,9 @@ struct MatchSummaryView: View {
if matchViewStyle == .standardStyle || matchViewStyle == .sectionedStandardStyle if matchViewStyle == .standardStyle || matchViewStyle == .sectionedStandardStyle
{ {
Spacer() Spacer()
if let court = match.court, match.hasEnded() == false { if let court = match.courtName(), match.hasEnded() == false {
Spacer() Spacer()
Text("Terrain #\(court)") Text(court)
} }
} }
} }

@ -56,7 +56,7 @@ struct CourtAvailabilitySettingsView: View {
} }
} }
} header: { } header: {
Text("Terrain #\(key + 1)") Text(tournament.courtName(atIndex: key))
} }
.headerProminence(.increased) .headerProminence(.increased)
} }
@ -84,7 +84,7 @@ struct CourtAvailabilitySettingsView: View {
NavigationStack { NavigationStack {
Form { Form {
Section { Section {
CourtPicker(title: "Terrain", selection: $courtIndex, maxCourt: 3) CourtPicker(title: "Terrain", selection: $courtIndex, maxCourt: tournament.courtCount)
} }
Section { Section {
@ -123,6 +123,8 @@ struct CourtAvailabilitySettingsView: View {
} }
struct CourtPicker: View { struct CourtPicker: View {
@Environment(Tournament.self) var tournament: Tournament
let title: String let title: String
@Binding var selection: Int @Binding var selection: Int
let maxCourt: Int let maxCourt: Int
@ -130,7 +132,7 @@ struct CourtPicker: View {
var body: some View { var body: some View {
Picker(title, selection: $selection) { Picker(title, selection: $selection) {
ForEach(0..<maxCourt, id: \.self) { ForEach(0..<maxCourt, id: \.self) {
Text("Terrain #\($0 + 1)") Text(tournament.courtName(atIndex: $0))
} }
} }
} }
@ -139,19 +141,3 @@ struct CourtPicker: View {
#Preview { #Preview {
CourtAvailabilitySettingsView() CourtAvailabilitySettingsView()
} }
/*
LabeledContent {
// switch dayIndex {
// case 1:
// StepperView(count: $dayTwo, maximum: tournament.courtCount)
// case 2:
// StepperView(count: $dayThree, maximum: tournament.courtCount)
// default:
// StepperView(count: $dayOne, maximum: tournament.courtCount)
// }
// } label: {
// Text("Terrains maximum")
// Text(tournament.startDate.formatted(.dateTime.weekday(.wide)) + " + \(dayIndex)")
// }
*/

@ -44,7 +44,7 @@ struct PlanningSettingsView: View {
Section { Section {
DatePicker(tournament.startDate.formatted(.dateTime.weekday()), selection: $tournament.startDate) DatePicker(tournament.startDate.formatted(.dateTime.weekday()), selection: $tournament.startDate)
LabeledContent { LabeledContent {
StepperView(count: $tournament.dayDuration, minimum: 1, maximum: 1_000) StepperView(count: $tournament.dayDuration, minimum: 1)
} label: { } label: {
Text("Durée") Text("Durée")
Text("\(tournament.dayDuration) jour" + tournament.dayDuration.pluralSuffix) Text("\(tournament.dayDuration) jour" + tournament.dayDuration.pluralSuffix)
@ -56,7 +56,7 @@ struct PlanningSettingsView: View {
} }
Section { Section {
TournamentFieldsManagerView(localizedStringKey: "Terrains maximum", count: $tournament.courtCount, max: 100) TournamentFieldsManagerView(localizedStringKey: "Terrains maximum", count: $tournament.courtCount)
if tournament.groupStages().isEmpty == false { if tournament.groupStages().isEmpty == false {
TournamentFieldsManagerView(localizedStringKey: "Terrains par poule", count: $groupStageCourtCount, max: tournament.maximumCourtsPerGroupSage()) TournamentFieldsManagerView(localizedStringKey: "Terrains par poule", count: $groupStageCourtCount, max: tournament.maximumCourtsPerGroupSage())
@ -68,23 +68,6 @@ struct PlanningSettingsView: View {
} label: { } label: {
Text("Préciser la disponibilité des terrains") Text("Préciser la disponibilité des terrains")
} }
// if tournament.dayDuration > 1 {
// ForEach(0..<tournament.dayDuration, id: \.self) { dayIndex in
// LabeledContent {
// switch dayIndex {
// case 1:
// StepperView(count: $dayTwo, maximum: tournament.courtCount)
// case 2:
// StepperView(count: $dayThree, maximum: tournament.courtCount)
// default:
// StepperView(count: $dayOne, maximum: tournament.courtCount)
// }
// } label: {
// Text("Terrains maximum")
// Text(tournament.startDate.formatted(.dateTime.weekday(.wide)) + " + \(dayIndex)")
// }
// }
// }
} }
Section { Section {

@ -36,8 +36,8 @@ struct PlanningView: View {
MatchDetailView(match: match, matchViewStyle: .sectionedStandardStyle) MatchDetailView(match: match, matchViewStyle: .sectionedStandardStyle)
} label: { } label: {
LabeledContent { LabeledContent {
if let court = match.court { if let courtName = match.courtName() {
Text(court) Text(courtName)
} }
} label: { } label: {
if let groupStage = match.groupStageObject { if let groupStage = match.groupStageObject {

@ -10,6 +10,7 @@ import SwiftUI
struct TournamentClubSettingsView: View { struct TournamentClubSettingsView: View {
@Environment(Tournament.self) private var tournament: Tournament @Environment(Tournament.self) private var tournament: Tournament
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@State var selectedCourt: Court?
var body: some View { var body: some View {
@Bindable var tournament = tournament @Bindable var tournament = tournament
@ -54,13 +55,60 @@ struct TournamentClubSettingsView: View {
} }
Section { Section {
TournamentFieldsManagerView(localizedStringKey: "Terrains maximum", count: $tournament.courtCount, max: 100) TournamentFieldsManagerView(localizedStringKey: "Terrains maximum", count: $tournament.courtCount)
}
if let selectedClub {
Section {
ForEach((0..<tournament.courtCount), id: \.self) { courtIndex in
_courtView(atIndex: courtIndex, tournamentClub: selectedClub)
}
}
} }
} }
.onChange(of: tournament.courtCount) { .onChange(of: tournament.courtCount) {
try? dataStore.tournaments.addOrUpdate(instance: tournament) try? dataStore.tournaments.addOrUpdate(instance: tournament)
} }
.navigationDestination(item: $selectedCourt) { court in
CourtView(court: court)
}
}
@ViewBuilder
private func _courtView(atIndex index: Int, tournamentClub: Club) -> some View {
if let court = tournamentClub.courts.first(where: { $0.index == index }) {
LabeledContent {
if let name = court.name {
Text(name)
}
} label: {
Text(court.courtIndexTitle())
HStack {
if court.indoor {
Text("Couvert")
}
if court.exitAllowed {
Text("Sortie autorisée")
}
}
}
} else {
LabeledContent {
FooterButtonView("personnaliser") {
let court = Court(club: tournamentClub.id, index: index)
try? dataStore.courts.addOrUpdate(instance: court)
selectedCourt = court
}
} label: {
Text(_courtName(atIndex: index))
}
}
} }
private func _courtName(atIndex index: Int) -> String {
Court.courtIndexedTitle(atIndex: index)
}
} }
#Preview { #Preview {

@ -13,7 +13,7 @@ struct TournamentDurationManagerView: View {
var body: some View { var body: some View {
@Bindable var tournament = tournament @Bindable var tournament = tournament
LabeledContent { LabeledContent {
StepperView(count: $tournament.dayDuration, minimum: 1, maximum: 3) StepperView(count: $tournament.dayDuration, minimum: 1)
} label: { } label: {
Text("Durée") Text("Durée")
Text("\(tournament.dayDuration) jour" + tournament.dayDuration.pluralSuffix) Text("\(tournament.dayDuration) jour" + tournament.dayDuration.pluralSuffix)

@ -10,7 +10,7 @@ import SwiftUI
struct TournamentFieldsManagerView: View { struct TournamentFieldsManagerView: View {
let localizedStringKey: String let localizedStringKey: String
@Binding var count: Int @Binding var count: Int
let max: Int var max: Int? = nil
var body: some View { var body: some View {
LabeledContent { LabeledContent {

@ -22,25 +22,14 @@ struct TournamentView: View {
} }
var body: some View { var body: some View {
VStack(spacing: 0.0) { VStack(spacing: 0.0) {
<<<<<<< HEAD
OffersHeaderView() OffersHeaderView()
======= List {
// if tournament.missingUnrankedValue() {
// Button("update NC") {
// tournament.femaleUnrankedValue = SourceFileManager.shared.getUnrankValue(forMale: false, rankSourceDate: tournament.rankSourceDate)
// tournament.maleUnrankedValue = SourceFileManager.shared.getUnrankValue(forMale: true, rankSourceDate: tournament.rankSourceDate)
// try? dataStore.tournaments.addOrUpdate(instance: tournament)
// }
// }
//
//
Section { Section {
NavigationLink(value: Screen.inscription) { NavigationLink(value: Screen.inscription) {
LabeledContent { LabeledContent {
Text(tournament.unsortedTeams().count.formatted() + "/" + tournament.teamCount.formatted()) Text(tournament.unsortedTeams().count.formatted() + "/" + tournament.teamCount.formatted())
.foregroundStyle(.master)
} label: { } label: {
Text("Gestion des inscriptions") Text("Gestion des inscriptions")
if let closedRegistrationDate = tournament.closedRegistrationDate { if let closedRegistrationDate = tournament.closedRegistrationDate {
@ -51,12 +40,12 @@ struct TournamentView: View {
if let endOfInscriptionDate = tournament.mandatoryRegistrationCloseDate(), tournament.inscriptionClosed() == false && tournament.hasStarted() == false { if let endOfInscriptionDate = tournament.mandatoryRegistrationCloseDate(), tournament.inscriptionClosed() == false && tournament.hasStarted() == false {
LabeledContent { LabeledContent {
Text(endOfInscriptionDate.formatted(date: .abbreviated, time: .shortened)) Text(endOfInscriptionDate.formatted(date: .abbreviated, time: .shortened))
.foregroundStyle(.master)
} label: { } label: {
Text("Date limite") Text("Date limite")
} }
} }
} footer: { } footer: {
if tournament.inscriptionClosed() { if tournament.inscriptionClosed() {
Button { Button {
tournament.lockRegistration() tournament.lockRegistration()
@ -68,48 +57,6 @@ struct TournamentView: View {
.buttonStyle(.borderless) .buttonStyle(.borderless)
} }
} }
>>>>>>> 6547a8de016666a19407c6cf8b30e91087f201e2
List {
// if tournament.missingUnrankedValue() {
// Button("update NC") {
// tournament.femaleUnrankedValue = SourceFileManager.shared.getUnrankValue(forMale: false, rankSourceDate: tournament.rankSourceDate)
// tournament.maleUnrankedValue = SourceFileManager.shared.getUnrankValue(forMale: true, rankSourceDate: tournament.rankSourceDate)
// try? dataStore.tournaments.addOrUpdate(instance: tournament)
// }
// }
//
//
Section {
NavigationLink(value: Screen.inscription) {
LabeledContent {
Text(tournament.unsortedTeams().count.formatted() + "/" + tournament.teamCount.formatted())
.foregroundStyle(.master)
} label: {
Text("Gestion des inscriptions")
if let closedRegistrationDate = tournament.closedRegistrationDate {
Text("clôturé le " + closedRegistrationDate.formatted(date: .abbreviated, time: .shortened))
}
}
}
if let endOfInscriptionDate = tournament.mandatoryRegistrationCloseDate(), tournament.inscriptionClosed() == false && tournament.hasStarted() == false {
LabeledContent {
Text(endOfInscriptionDate.formatted(date: .abbreviated, time: .shortened))
.foregroundStyle(.master)
} label: {
Text("Date limite")
}
if endOfInscriptionDate < Date() {
RowButtonView("Clôturer les inscriptions") {
tournament.lockRegistration()
_save()
}
}
}
}
switch tournament.state() { switch tournament.state() {
case .initial: case .initial:

Loading…
Cancel
Save