Implements separate store for tournaments

multistore
Laurent 1 year ago
parent 87c4b10d97
commit 6f02c3396e
  1. 6
      PadelClub.xcodeproj/project.pbxproj
  2. 3
      PadelClub/Data/Club.swift
  3. 1
      PadelClub/Data/Court.swift
  4. 91
      PadelClub/Data/DataStore.swift
  5. 1
      PadelClub/Data/DateInterval.swift
  6. 1
      PadelClub/Data/Event.swift
  7. 2
      PadelClub/Data/Federal/FederalTournament.swift
  8. 49
      PadelClub/Data/GroupStage.swift
  9. 77
      PadelClub/Data/Match.swift
  10. 11
      PadelClub/Data/MatchScheduler.swift
  11. 1
      PadelClub/Data/MonthData.swift
  12. 14
      PadelClub/Data/PlayerRegistration.swift
  13. 118
      PadelClub/Data/Round.swift
  14. 47
      PadelClub/Data/TeamRegistration.swift
  15. 16
      PadelClub/Data/TeamScore.swift
  16. 94
      PadelClub/Data/Tournament.swift
  17. 56
      PadelClub/Data/TournamentStore.swift
  18. 1
      PadelClub/Data/User.swift
  19. 52
      PadelClub/Utils/Patcher.swift
  20. 2
      PadelClub/Views/Calling/CallMessageCustomizationView.swift
  21. 9
      PadelClub/Views/Calling/CallSettingsView.swift
  22. 9
      PadelClub/Views/Calling/CallView.swift
  23. 2
      PadelClub/Views/Calling/Components/MenuWarningView.swift
  24. 16
      PadelClub/Views/Calling/SendToAllView.swift
  25. 44
      PadelClub/Views/Cashier/CashierSettingsView.swift
  26. 2
      PadelClub/Views/Cashier/Event/EventCreationView.swift
  27. 4
      PadelClub/Views/Club/ClubSearchView.swift
  28. 4
      PadelClub/Views/Club/ClubsView.swift
  29. 2
      PadelClub/Views/Club/CreateClubView.swift
  30. 5
      PadelClub/Views/Components/MatchListView.swift
  31. 9
      PadelClub/Views/GroupStage/Components/GroupStageTeamView.swift
  32. 9
      PadelClub/Views/GroupStage/GroupStageSettingsView.swift
  33. 31
      PadelClub/Views/GroupStage/GroupStageView.swift
  34. 9
      PadelClub/Views/Match/Components/MatchDateView.swift
  35. 11
      PadelClub/Views/Match/MatchDetailView.swift
  36. 4
      PadelClub/Views/Match/MatchRowView.swift
  37. 29
      PadelClub/Views/Match/MatchSetupView.swift
  38. 14
      PadelClub/Views/Navigation/MainView.swift
  39. 53
      PadelClub/Views/Navigation/Ongoing/OngoingView.swift
  40. 2
      PadelClub/Views/Navigation/Organizer/TournamentOrganizerView.swift
  41. 2
      PadelClub/Views/Navigation/Toolbox/APICallsListView.swift
  42. 8
      PadelClub/Views/Navigation/Toolbox/DebugSettingsView.swift
  43. 62
      PadelClub/Views/Navigation/Toolbox/ToolboxView.swift
  44. 10
      PadelClub/Views/Navigation/Umpire/UmpireView.swift
  45. 8
      PadelClub/Views/Planning/GroupStageScheduleEditorView.swift
  46. 7
      PadelClub/Views/Planning/LoserRoundScheduleEditorView.swift
  47. 7
      PadelClub/Views/Planning/LoserRoundStepScheduleEditorView.swift
  48. 20
      PadelClub/Views/Planning/PlanningSettingsView.swift
  49. 1
      PadelClub/Views/Planning/PlanningView.swift
  50. 6
      PadelClub/Views/Planning/RoundScheduleEditorView.swift
  51. 14
      PadelClub/Views/Planning/SchedulerView.swift
  52. 14
      PadelClub/Views/Player/Components/EditablePlayerView.swift
  53. 9
      PadelClub/Views/Player/Components/PlayerPayView.swift
  54. 10
      PadelClub/Views/Player/Components/PlayerSexPickerView.swift
  55. 10
      PadelClub/Views/Player/PlayerDetailView.swift
  56. 9
      PadelClub/Views/Player/PlayerView.swift
  57. 2
      PadelClub/Views/Round/LoserRoundView.swift
  58. 15
      PadelClub/Views/Round/RoundSettingsView.swift
  59. 11
      PadelClub/Views/Round/RoundView.swift
  60. 9
      PadelClub/Views/Score/EditScoreView.swift
  61. 2
      PadelClub/Views/Shared/SupportButtonView.swift
  62. 11
      PadelClub/Views/Team/EditingTeamView.swift
  63. 10
      PadelClub/Views/Tournament/FileImportView.swift
  64. 2
      PadelClub/Views/Tournament/Screen/BroadcastView.swift
  65. 6
      PadelClub/Views/Tournament/Screen/Components/TournamentClubSettingsView.swift
  66. 11
      PadelClub/Views/Tournament/Screen/Components/TournamentMatchFormatsSettingsView.swift
  67. 9
      PadelClub/Views/Tournament/Screen/Components/UpdateSourceRankDateView.swift
  68. 24
      PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift
  69. 11
      PadelClub/Views/Tournament/Screen/TournamentRankView.swift
  70. 4
      PadelClub/Views/Tournament/Shared/TournamentBroadcastRowView.swift
  71. 4
      PadelClub/Views/Tournament/Subscription/Guard.swift
  72. 2
      PadelClub/Views/Tournament/Subscription/Purchase.swift
  73. 0
      PadelClub/Views/Tournament/Subscription/PurchaseListView.swift
  74. 0
      PadelClub/Views/Tournament/Subscription/StoreItem.swift
  75. 2
      PadelClub/Views/Tournament/Subscription/StoreManager.swift
  76. 0
      PadelClub/Views/Tournament/Subscription/SubscriptionInfoView.swift
  77. 2
      PadelClub/Views/Tournament/Subscription/SubscriptionView.swift
  78. 8
      PadelClub/Views/Tournament/TournamentView.swift
  79. 2
      PadelClub/Views/User/ChangePasswordView.swift
  80. 4
      PadelClub/Views/User/LoginView.swift
  81. 2
      PadelClub/Views/User/UserCreationView.swift
  82. 4
      PadelClubTests/ServerDataTests.swift

@ -47,6 +47,7 @@
C4EC6F572BE92CAC000CEAB4 /* local.plist in Resources */ = {isa = PBXBuildFile; fileRef = C4EC6F562BE92CAC000CEAB4 /* local.plist */; }; C4EC6F572BE92CAC000CEAB4 /* local.plist in Resources */ = {isa = PBXBuildFile; fileRef = C4EC6F562BE92CAC000CEAB4 /* local.plist */; };
C4EC6F592BE92D88000CEAB4 /* PListReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC6F582BE92D88000CEAB4 /* PListReader.swift */; }; C4EC6F592BE92D88000CEAB4 /* PListReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC6F582BE92D88000CEAB4 /* PListReader.swift */; };
C4FC2E272C2AABC90021F3BF /* PasswordField.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4FC2E262C2AABC90021F3BF /* PasswordField.swift */; }; C4FC2E272C2AABC90021F3BF /* PasswordField.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4FC2E262C2AABC90021F3BF /* PasswordField.swift */; };
C4FC2E2B2C2C0E4D0021F3BF /* TournamentStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4FC2E2A2C2C0E4D0021F3BF /* TournamentStore.swift */; };
FF025AD82BD0C10F00A86CF8 /* TeamHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AD72BD0C10F00A86CF8 /* TeamHeaderView.swift */; }; FF025AD82BD0C10F00A86CF8 /* TeamHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025AD72BD0C10F00A86CF8 /* TeamHeaderView.swift */; };
FF025ADB2BD0C2D000A86CF8 /* MatchTeamDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025ADA2BD0C2D000A86CF8 /* MatchTeamDetailView.swift */; }; FF025ADB2BD0C2D000A86CF8 /* MatchTeamDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025ADA2BD0C2D000A86CF8 /* MatchTeamDetailView.swift */; };
FF025ADD2BD0C94300A86CF8 /* FooterButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025ADC2BD0C94300A86CF8 /* FooterButtonView.swift */; }; FF025ADD2BD0C94300A86CF8 /* FooterButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF025ADC2BD0C94300A86CF8 /* FooterButtonView.swift */; };
@ -335,6 +336,7 @@
C4EC6F562BE92CAC000CEAB4 /* local.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = local.plist; sourceTree = "<group>"; }; C4EC6F562BE92CAC000CEAB4 /* local.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = local.plist; sourceTree = "<group>"; };
C4EC6F582BE92D88000CEAB4 /* PListReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PListReader.swift; sourceTree = "<group>"; }; C4EC6F582BE92D88000CEAB4 /* PListReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PListReader.swift; sourceTree = "<group>"; };
C4FC2E262C2AABC90021F3BF /* PasswordField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordField.swift; sourceTree = "<group>"; }; C4FC2E262C2AABC90021F3BF /* PasswordField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordField.swift; sourceTree = "<group>"; };
C4FC2E2A2C2C0E4D0021F3BF /* TournamentStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TournamentStore.swift; sourceTree = "<group>"; };
FF025AD72BD0C10F00A86CF8 /* TeamHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeamHeaderView.swift; sourceTree = "<group>"; }; FF025AD72BD0C10F00A86CF8 /* TeamHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeamHeaderView.swift; sourceTree = "<group>"; };
FF025ADA2BD0C2D000A86CF8 /* MatchTeamDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchTeamDetailView.swift; sourceTree = "<group>"; }; FF025ADA2BD0C2D000A86CF8 /* MatchTeamDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchTeamDetailView.swift; sourceTree = "<group>"; };
FF025ADC2BD0C94300A86CF8 /* FooterButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FooterButtonView.swift; sourceTree = "<group>"; }; FF025ADC2BD0C94300A86CF8 /* FooterButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FooterButtonView.swift; sourceTree = "<group>"; };
@ -707,6 +709,7 @@
children = ( children = (
C411C9CC2BF21DAF003017AD /* README.md */, C411C9CC2BF21DAF003017AD /* README.md */,
C4A47D5D2B6D38EC00ADC637 /* DataStore.swift */, C4A47D5D2B6D38EC00ADC637 /* DataStore.swift */,
C4FC2E2A2C2C0E4D0021F3BF /* TournamentStore.swift */,
C4A47DAC2B85FCCD00ADC637 /* User.swift */, C4A47DAC2B85FCCD00ADC637 /* User.swift */,
C4A47D592B6D383C00ADC637 /* Tournament.swift */, C4A47D592B6D383C00ADC637 /* Tournament.swift */,
FF967CE72BAEC70100A9A3BD /* GroupStage.swift */, FF967CE72BAEC70100A9A3BD /* GroupStage.swift */,
@ -745,7 +748,6 @@
FF11627B2BCF937F000C4809 /* Cashier */, FF11627B2BCF937F000C4809 /* Cashier */,
FFBF41802BF73EA2001B24CB /* Event */, FFBF41802BF73EA2001B24CB /* Event */,
FF3F74F72B919F96004CFE0E /* Tournament */, FF3F74F72B919F96004CFE0E /* Tournament */,
C4A47D882B7BBB5000ADC637 /* Subscription */,
C4A47D852B7BA33F00ADC637 /* User */, C4A47D852B7BA33F00ADC637 /* User */,
FF6EC8FC2B9478C800EA7F5A /* Shared */, FF6EC8FC2B9478C800EA7F5A /* Shared */,
C4A47DA02B7D0BD800ADC637 /* Components */, C4A47DA02B7D0BD800ADC637 /* Components */,
@ -956,6 +958,7 @@
FF1F4B702BF9EFE9000B4573 /* TournamentInscriptionView.swift */, FF1F4B702BF9EFE9000B4573 /* TournamentInscriptionView.swift */,
FF1F4B6C2BF9E60B000B4573 /* TournamentBuildView.swift */, FF1F4B6C2BF9E60B000B4573 /* TournamentBuildView.swift */,
FF967CF52BAED51600A9A3BD /* TournamentRunningView.swift */, FF967CF52BAED51600A9A3BD /* TournamentRunningView.swift */,
C4A47D882B7BBB5000ADC637 /* Subscription */,
FF089EBE2BB0B14600F0AEC7 /* FileImportView.swift */, FF089EBE2BB0B14600F0AEC7 /* FileImportView.swift */,
FF3F74F92B91A018004CFE0E /* Screen */, FF3F74F92B91A018004CFE0E /* Screen */,
FF3F74F82B919FB2004CFE0E /* Shared */, FF3F74F82B919FB2004CFE0E /* Shared */,
@ -1595,6 +1598,7 @@
FF1162872BD004AD000C4809 /* EditingTeamView.swift in Sources */, FF1162872BD004AD000C4809 /* EditingTeamView.swift in Sources */,
FF6EC9062B947A1000EA7F5A /* NetworkManagerError.swift in Sources */, FF6EC9062B947A1000EA7F5A /* NetworkManagerError.swift in Sources */,
C4A47D5A2B6D383C00ADC637 /* Tournament.swift in Sources */, C4A47D5A2B6D383C00ADC637 /* Tournament.swift in Sources */,
C4FC2E2B2C2C0E4D0021F3BF /* TournamentStore.swift in Sources */,
FF5647132C0B6F390081F995 /* LoserRoundSettingsView.swift in Sources */, FF5647132C0B6F390081F995 /* LoserRoundSettingsView.swift in Sources */,
FF3795662B9399AA004EA093 /* Persistence.swift in Sources */, FF3795662B9399AA004EA093 /* Persistence.swift in Sources */,
FF1DF49B2BD8D23900822FA0 /* BarButtonView.swift in Sources */, FF1DF49B2BD8D23900822FA0 /* BarButtonView.swift in Sources */,

@ -14,6 +14,7 @@ class Club : ModelObject, Storable, Hashable {
static func resourceName() -> String { return "clubs" } static func resourceName() -> String { return "clubs" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [.get] } static func tokenExemptedMethods() -> [HTTPMethod] { return [.get] }
static func filterByStoreIdentifier() -> Bool { return false }
static func == (lhs: Club, rhs: Club) -> Bool { static func == (lhs: Club, rhs: Club) -> Bool {
lhs.id == rhs.id lhs.id == rhs.id
@ -235,7 +236,7 @@ extension Club {
if clubs.isEmpty == false { if clubs.isEmpty == false {
return clubs.first! return clubs.first!
} else { } else {
return Club(creator: Store.main.userId, name: name, code: code, city: city, zipCode: zipCode) return Club(creator: StoreCenter.main.userId, name: name, code: code, city: city, zipCode: zipCode)
} }
} }

@ -13,6 +13,7 @@ import LeStorage
class Court : ModelObject, Storable, Hashable { class Court : ModelObject, Storable, Hashable {
static func resourceName() -> String { return "courts" } static func resourceName() -> String { return "courts" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func filterByStoreIdentifier() -> Bool { return false }
static func == (lhs: Court, rhs: Court) -> Bool { static func == (lhs: Court, rhs: Court) -> Bool {
lhs.id == rhs.id lhs.id == rhs.id

@ -16,12 +16,12 @@ class DataStore: ObservableObject {
@Published var user: User = User.placeHolder() { @Published var user: User = User.placeHolder() {
didSet { didSet {
let loggedUser = (user.username.count > 0) let loggedUser = (user.username.count > 0)
Store.main.collectionsCanSynchronize = loggedUser StoreCenter.main.collectionsCanSynchronize = loggedUser
if loggedUser { if loggedUser {
if self.user.id != self.userStorage.item()?.id { if self.user.id != self.userStorage.item()?.id {
self.userStorage.setItemNoSync(self.user) self.userStorage.setItemNoSync(self.user)
if Store.main.collectionsCanSynchronize { if StoreCenter.main.collectionsCanSynchronize {
Store.main.loadCollectionFromServer() Store.main.loadCollectionFromServer()
self._fixMissingClubCreatorIfNecessary(self.clubs) self._fixMissingClubCreatorIfNecessary(self.clubs)
self._fixMissingEventCreatorIfNecessary(self.events) self._fixMissingEventCreatorIfNecessary(self.events)
@ -37,15 +37,15 @@ class DataStore: ObservableObject {
fileprivate(set) var clubs: StoredCollection<Club> fileprivate(set) var clubs: StoredCollection<Club>
fileprivate(set) var courts: StoredCollection<Court> 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>
fileprivate(set) var teamRegistrations: StoredCollection<TeamRegistration> // fileprivate(set) var teamRegistrations: StoredCollection<TeamRegistration>
fileprivate(set) var playerRegistrations: StoredCollection<PlayerRegistration> // fileprivate(set) var playerRegistrations: StoredCollection<PlayerRegistration>
fileprivate(set) var rounds: StoredCollection<Round> // fileprivate(set) var rounds: StoredCollection<Round>
fileprivate(set) var teamScores: StoredCollection<TeamScore> // fileprivate(set) var teamScores: StoredCollection<TeamScore>
fileprivate(set) var monthData: StoredCollection<MonthData> fileprivate(set) var monthData: StoredCollection<MonthData>
fileprivate(set) var dateIntervals: StoredCollection<DateInterval> fileprivate(set) var dateIntervals: StoredCollection<DateInterval>
fileprivate(set) var matchSchedulers: StoredCollection<MatchScheduler> // fileprivate(set) var matchSchedulers: StoredCollection<MatchScheduler>
fileprivate var userStorage: StoredSingleton<User> fileprivate var userStorage: StoredSingleton<User>
@ -59,21 +59,21 @@ class DataStore: ObservableObject {
init() { init() {
let store = Store.main let store = Store.main
let serverURL: String = URLs.api.rawValue let serverURL: String = URLs.api.rawValue
store.blackListUserName("apple-test") StoreCenter.main.blackListUserName("apple-test")
#if DEBUG #if DEBUG
if let server = PListReader.readString(plist: "local", key: "server") { if let server = PListReader.readString(plist: "local", key: "server") {
store.synchronizationApiURL = server StoreCenter.main.synchronizationApiURL = server
} else { } else {
store.synchronizationApiURL = serverURL StoreCenter.main.synchronizationApiURL = serverURL
} }
#else #else
store.synchronizationApiURL = serverURL store.synchronizationApiURL = serverURL
#endif #endif
store.logsFailedAPICalls() StoreCenter.main.logsFailedAPICalls()
var synchronized : Bool = true var synchronized: Bool = true
_ = Guard.main // init _ = Guard.main // init
@ -83,22 +83,22 @@ class DataStore: ObservableObject {
} }
#endif #endif
Logger.log("Sync URL: \(store.synchronizationApiURL ?? "none"), sync: \(synchronized) ") Logger.log("Sync URL: \(StoreCenter.main.synchronizationApiURL ?? "none"), sync: \(synchronized) ")
let indexed : Bool = true let indexed: Bool = true
self.clubs = store.registerCollection(synchronized: synchronized, indexed: indexed) self.clubs = store.registerCollection(synchronized: synchronized, indexed: indexed)
self.courts = store.registerCollection(synchronized: synchronized, indexed: indexed) self.courts = store.registerCollection(synchronized: synchronized, indexed: indexed)
self.tournaments = store.registerCollection(synchronized: synchronized, indexed: indexed) self.tournaments = store.registerCollection(synchronized: synchronized, indexed: indexed)
self.events = store.registerCollection(synchronized: synchronized, indexed: indexed) self.events = store.registerCollection(synchronized: synchronized, indexed: indexed)
self.groupStages = store.registerCollection(synchronized: synchronized, indexed: indexed) // self.groupStages = store.registerCollection(synchronized: synchronized, indexed: indexed)
self.teamScores = store.registerCollection(synchronized: synchronized, indexed: indexed) // self.teamScores = store.registerCollection(synchronized: synchronized, indexed: indexed)
self.teamRegistrations = store.registerCollection(synchronized: synchronized, indexed: indexed) // self.teamRegistrations = store.registerCollection(synchronized: synchronized, indexed: indexed)
self.playerRegistrations = store.registerCollection(synchronized: synchronized, indexed: indexed) // self.playerRegistrations = store.registerCollection(synchronized: synchronized, indexed: indexed)
self.rounds = store.registerCollection(synchronized: synchronized, indexed: indexed) // self.rounds = store.registerCollection(synchronized: synchronized, indexed: indexed)
self.matches = store.registerCollection(synchronized: synchronized, indexed: indexed) // self.matches = store.registerCollection(synchronized: synchronized, indexed: indexed)
self.monthData = store.registerCollection(synchronized: false, indexed: indexed) self.monthData = store.registerCollection(synchronized: false, indexed: indexed)
self.dateIntervals = store.registerCollection(synchronized: synchronized, indexed: indexed) self.dateIntervals = store.registerCollection(synchronized: synchronized, indexed: indexed)
self.matchSchedulers = store.registerCollection(synchronized: false, indexed: indexed) // self.matchSchedulers = store.registerCollection(synchronized: false, indexed: indexed)
self.userStorage = store.registerObject(synchronized: synchronized) self.userStorage = store.registerObject(synchronized: synchronized)
@ -139,7 +139,7 @@ class DataStore: ObservableObject {
fileprivate func _fixMissingClubCreatorIfNecessary(_ clubsCollection: StoredCollection<Club>) { fileprivate func _fixMissingClubCreatorIfNecessary(_ clubsCollection: StoredCollection<Club>) {
for club in clubsCollection { for club in clubsCollection {
if let userId = Store.main.userId, club.creator == nil { if let userId = StoreCenter.main.userId, club.creator == nil {
club.creator = userId club.creator = userId
self.userStorage.item()?.addClub(club) self.userStorage.item()?.addClub(club)
clubsCollection.writeChangeAndInsertOnServer(instance: club) clubsCollection.writeChangeAndInsertOnServer(instance: club)
@ -149,7 +149,7 @@ class DataStore: ObservableObject {
fileprivate func _fixMissingEventCreatorIfNecessary(_ eventsCollection: StoredCollection<Event>) { fileprivate func _fixMissingEventCreatorIfNecessary(_ eventsCollection: StoredCollection<Event>) {
for event in eventsCollection { for event in eventsCollection {
if let userId = Store.main.userId, event.creator == nil { if let userId = StoreCenter.main.userId, event.creator == nil {
event.creator = userId event.creator = userId
do { do {
try event.insertOnServer() try event.insertOnServer()
@ -167,7 +167,7 @@ class DataStore: ObservableObject {
func disconnect() { func disconnect() {
Task { Task {
if await Store.main.hasPendingAPICalls() { if await StoreCenter.main.hasPendingAPICalls() {
// todo qu'est ce qu'on fait des API Call ? // todo qu'est ce qu'on fait des API Call ?
} }
} }
@ -175,21 +175,26 @@ class DataStore: ObservableObject {
self.user = self._temporaryLocalUser.item ?? User.placeHolder() self.user = self._temporaryLocalUser.item ?? User.placeHolder()
self.user.clubs.removeAll() self.user.clubs.removeAll()
Store.main.disconnect() StoreCenter.main.disconnect()
Store.main.collectionsCanSynchronize = false StoreCenter.main.collectionsCanSynchronize = false
for tournament in self.tournaments {
StoreCenter.main.destroyStore(identifier: tournament.id)
}
self.tournaments.reset() self.tournaments.reset()
self.clubs.reset() self.clubs.reset()
self.courts.reset() self.courts.reset()
self.events.reset() self.events.reset()
self.groupStages.reset()
self.matches.reset() // self.groupStages.reset()
self.teamRegistrations.reset() // self.matches.reset()
self.playerRegistrations.reset() // self.teamRegistrations.reset()
self.rounds.reset() // self.playerRegistrations.reset()
self.teamScores.reset() // self.rounds.reset()
// self.teamScores.reset()
self.dateIntervals.reset() self.dateIntervals.reset()
self.matchSchedulers.reset() // self.matchSchedulers.reset()
self.userStorage.reset() self.userStorage.reset()
Guard.main.disconnect() Guard.main.disconnect()
@ -256,4 +261,20 @@ class DataStore: ObservableObject {
} }
// MARK: - Convenience
func runningMatches() -> [Match] {
// let tournaments: [Tournament] = self.tournaments // foutu
let lastTournaments = self.tournaments.sorted(by: \Tournament.startDate).prefix(10)
var runningMatches: [Match] = []
for tournament in lastTournaments {
let matches = tournament.tournamentStore.matches.filter { match in
match.confirmed && match.startDate != nil && match.endDate == nil && match.courtIndex != nil }
runningMatches.append(contentsOf: matches)
}
return runningMatches
}
} }

@ -13,6 +13,7 @@ import LeStorage
class DateInterval: ModelObject, Storable { class DateInterval: ModelObject, Storable {
static func resourceName() -> String { return "date-intervals" } static func resourceName() -> String { return "date-intervals" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func filterByStoreIdentifier() -> Bool { return false }
var id: String = Store.randomId() var id: String = Store.randomId()
var event: String var event: String

@ -14,6 +14,7 @@ class Event: ModelObject, Storable {
static func resourceName() -> String { return "events" } static func resourceName() -> String { return "events" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func filterByStoreIdentifier() -> Bool { return false }
var id: String = Store.randomId() var id: String = Store.randomId()
var creator: String? var creator: String?

@ -20,7 +20,7 @@ struct FederalTournament: Identifiable, Codable {
let club = DataStore.shared.user.clubsObjects().first(where: { $0.code == codeClub }) let club = DataStore.shared.user.clubsObjects().first(where: { $0.code == codeClub })
var event = DataStore.shared.events.first(where: { $0.tenupId == id.string }) var event = DataStore.shared.events.first(where: { $0.tenupId == id.string })
if event == nil { if event == nil {
event = Event(creator: Store.main.userId, club: club?.id, name: libelle, tenupId: id.string) event = Event(creator: StoreCenter.main.userId, club: club?.id, name: libelle, tenupId: id.string)
do { do {
try DataStore.shared.events.addOrUpdate(instance: event!) try DataStore.shared.events.addOrUpdate(instance: event!)
} catch { } catch {

@ -14,6 +14,7 @@ import SwiftUI
class GroupStage: ModelObject, Storable { class GroupStage: ModelObject, Storable {
static func resourceName() -> String { "group-stages" } static func resourceName() -> String { "group-stages" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func filterByStoreIdentifier() -> Bool { return true }
var id: String = Store.randomId() var id: String = Store.randomId()
var tournament: String var tournament: String
@ -41,10 +42,15 @@ class GroupStage: ModelObject, Storable {
self.name = name self.name = name
} }
var tournamentStore: TournamentStore {
return TournamentStore.instance(tournamentId: self.tournament)
}
// MARK: - Computed dependencies // MARK: - Computed dependencies
func _matches() -> [Match] { func _matches() -> [Match] {
Store.main.filter { $0.groupStage == self.id } return self.tournamentStore.matches.filter { $0.groupStage == self.id }
// Store.main.filter { $0.groupStage == self.id }
} }
func tournamentObject() -> Tournament? { func tournamentObject() -> Tournament? {
@ -82,21 +88,31 @@ class GroupStage: ModelObject, Storable {
return _matches.anySatisfy { $0.hasEnded() == false } == false return _matches.anySatisfy { $0.hasEnded() == false } == false
} }
fileprivate func _createMatch(index: Int) -> Match {
let match: Match = Match(groupStage: self.id,
index: index,
matchFormat: self.matchFormat,
name: self.localizedMatchUpLabel(for: index))
match.store = self.store
return match
}
func buildMatches() { func buildMatches() {
_removeMatches() _removeMatches()
var _matches = [Match]() var matches = [Match]()
var _teamScores = [TeamScore]() var teamScores = [TeamScore]()
for i in 0..<_numberOfMatchesToBuild() { for i in 0..<_numberOfMatchesToBuild() {
let newMatch = Match(groupStage: id, index: i, matchFormat: matchFormat, name: localizedMatchUpLabel(for: i)) let newMatch = self._createMatch(index: i)
_teamScores.append(contentsOf: newMatch.createTeamScores()) // let newMatch = Match(groupStage: self.id, index: i, matchFormat: self.matchFormat, name: localizedMatchUpLabel(for: i))
_matches.append(newMatch) teamScores.append(contentsOf: newMatch.createTeamScores())
matches.append(newMatch)
} }
do { do {
try DataStore.shared.matches.addOrUpdate(contentOfs: _matches) try self.tournamentStore.matches.addOrUpdate(contentOfs: matches)
try DataStore.shared.teamScores.addOrUpdate(contentOfs: _teamScores) try self.tournamentStore.teamScores.addOrUpdate(contentOfs: teamScores)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -124,7 +140,7 @@ class GroupStage: ModelObject, Storable {
team.bracketPosition = nil team.bracketPosition = nil
} }
} }
try DataStore.shared.teamRegistrations.addOrUpdate(contentOfs: teams) try self.tournamentStore.teamRegistrations.addOrUpdate(contentOfs: teams)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -286,7 +302,7 @@ class GroupStage: ModelObject, Storable {
private func _removeMatches() { private func _removeMatches() {
do { do {
try DataStore.shared.matches.delete(contentOfs: _matches()) try self.tournamentStore.matches.delete(contentOfs: _matches())
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -315,7 +331,8 @@ class GroupStage: ModelObject, Storable {
} }
func unsortedTeams() -> [TeamRegistration] { func unsortedTeams() -> [TeamRegistration] {
Store.main.filter { $0.groupStage == self.id && $0.groupStagePosition != nil } return self.tournamentStore.teamRegistrations.filter { $0.groupStage == self.id && $0.groupStagePosition != nil }
// Store.main.filter { $0.groupStage == self.id && $0.groupStagePosition != nil }
} }
func teams(_ sortedByScore: Bool = false, scores: [TeamGroupStageScore]? = nil) -> [TeamRegistration] { func teams(_ sortedByScore: Bool = false, scores: [TeamGroupStageScore]? = nil) -> [TeamRegistration] {
@ -357,14 +374,14 @@ class GroupStage: ModelObject, Storable {
match.matchFormat = matchFormat match.matchFormat = matchFormat
} }
do { do {
try DataStore.shared.matches.addOrUpdate(contentOfs: playedMatches) try self.tournamentStore.matches.addOrUpdate(contentOfs: playedMatches)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
} }
override func deleteDependencies() throws { override func deleteDependencies() throws {
DataStore.shared.matches.deleteDependencies(self._matches()) self.tournamentStore.matches.deleteDependencies(self._matches())
} }
func encode(to encoder: Encoder) throws { func encode(to encoder: Encoder) throws {
@ -394,10 +411,10 @@ class GroupStage: ModelObject, Storable {
} }
} }
func insertOnServer() throws { func insertOnServer() {
try DataStore.shared.groupStages.writeChangeAndInsertOnServer(instance: self) self.tournamentStore.groupStages.writeChangeAndInsertOnServer(instance: self)
for match in self._matches() { for match in self._matches() {
try match.insertOnServer() match.insertOnServer()
} }
} }

@ -12,6 +12,7 @@ import LeStorage
class Match: ModelObject, Storable { class Match: ModelObject, Storable {
static func resourceName() -> String { "matches" } static func resourceName() -> String { "matches" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func filterByStoreIdentifier() -> Bool { return true }
static func setServerTitle(upperRound: Round, matchIndex: Int) -> String { static func setServerTitle(upperRound: Round, matchIndex: Int) -> String {
if upperRound.index == 0 { return upperRound.roundTitle() } if upperRound.index == 0 { return upperRound.roundTitle() }
@ -38,7 +39,7 @@ class Match: ModelObject, Storable {
private(set) var courtIndex: Int? private(set) var courtIndex: Int?
var confirmed: Bool = false var confirmed: Bool = false
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, name: String? = nil, disabled: Bool = false, courtIndex: Int? = nil, confirmed: Bool = false) { 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, name: String? = nil, disabled: Bool = false, courtIndex: Int? = nil, confirmed: Bool = false) {
self.round = round self.round = round
self.groupStage = groupStage self.groupStage = groupStage
self.startDate = startDate self.startDate = startDate
@ -57,16 +58,27 @@ class Match: ModelObject, Storable {
// self.order = order // self.order = order
} }
var tournamentStore: TournamentStore {
if let store = self.store as? TournamentStore {
return store
}
fatalError("missing store for \(String(describing: type(of: self)))")
}
// MARK: - Computed dependencies // MARK: - Computed dependencies
var teamScores: [TeamScore] { var teamScores: [TeamScore] {
return Store.main.filter { $0.match == self.id } return self.tournamentStore.teamScores.filter { $0.match == self.id }
// return Store.main.filter { $0.match == self.id }
} }
// MARK: - // MARK: -
override func deleteDependencies() throws { override func deleteDependencies() throws {
DataStore.shared.teamScores.deleteDependencies(self.teamScores) guard let tournament = self.currentTournament() else {
return
}
tournament.tournamentStore.teamScores.deleteDependencies(self.teamScores)
} }
func indexInRound(in matches: [Match]? = nil) -> Int { func indexInRound(in matches: [Match]? = nil) -> Int {
@ -140,7 +152,7 @@ class Match: ModelObject, Storable {
func winner() -> TeamRegistration? { func winner() -> TeamRegistration? {
guard let winningTeamId else { return nil } guard let winningTeamId else { return nil }
return Store.main.findById(winningTeamId) return self.tournamentStore.teamRegistrations.findById(winningTeamId)
} }
func localizedStartDate() -> String { func localizedStartDate() -> String {
@ -169,7 +181,7 @@ class Match: ModelObject, Storable {
followingMatch()?.cleanScheduleAndSave(nil) followingMatch()?.cleanScheduleAndSave(nil)
_loserMatch()?.cleanScheduleAndSave(nil) _loserMatch()?.cleanScheduleAndSave(nil)
do { do {
try DataStore.shared.matches.addOrUpdate(instance: self) try self.tournamentStore.matches.addOrUpdate(instance: self)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -186,7 +198,7 @@ class Match: ModelObject, Storable {
func resetScores() { func resetScores() {
teamScores.forEach({ $0.score = nil }) teamScores.forEach({ $0.score = nil })
do { do {
try DataStore.shared.teamScores.addOrUpdate(contentOfs: teamScores) try self.tournamentStore.teamScores.addOrUpdate(contentOfs: teamScores)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -196,14 +208,14 @@ class Match: ModelObject, Storable {
resetMatch() resetMatch()
let previousScores = teamScores.filter({ $0.luckyLoser != nil }) let previousScores = teamScores.filter({ $0.luckyLoser != nil })
do { do {
try DataStore.shared.teamScores.delete(contentOfs: previousScores) try self.tournamentStore.teamScores.delete(contentOfs: previousScores)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
if let existingTeamScore = teamScore(ofTeam: team) { if let existingTeamScore = teamScore(ofTeam: team) {
do { do {
try DataStore.shared.teamScores.delete(instance: existingTeamScore) try self.tournamentStore.teamScores.delete(instance: existingTeamScore)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -212,7 +224,7 @@ class Match: ModelObject, Storable {
let teamScoreWalkout = TeamScore(match: id, team: team) let teamScoreWalkout = TeamScore(match: id, team: team)
teamScoreWalkout.walkOut = 1 teamScoreWalkout.walkOut = 1
do { do {
try DataStore.shared.teamScores.addOrUpdate(instance: teamScoreWalkout) try self.tournamentStore.teamScores.addOrUpdate(instance: teamScoreWalkout)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -230,14 +242,14 @@ class Match: ModelObject, Storable {
resetMatch() resetMatch()
let previousScores = teamScores.filter({ $0.luckyLoser != nil }) let previousScores = teamScores.filter({ $0.luckyLoser != nil })
do { do {
try DataStore.shared.teamScores.delete(contentOfs: previousScores) try self.tournamentStore.teamScores.delete(contentOfs: previousScores)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
if let existingTeamScore = teamScore(ofTeam: team) { if let existingTeamScore = teamScore(ofTeam: team) {
do { do {
try DataStore.shared.teamScores.delete(instance: existingTeamScore) try self.tournamentStore.teamScores.delete(instance: existingTeamScore)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -248,7 +260,7 @@ class Match: ModelObject, Storable {
let teamScoreLuckyLoser = TeamScore(match: id, team: team) let teamScoreLuckyLoser = TeamScore(match: id, team: team)
teamScoreLuckyLoser.luckyLoser = position teamScoreLuckyLoser.luckyLoser = position
do { do {
try DataStore.shared.teamScores.addOrUpdate(instance: teamScoreLuckyLoser) try self.tournamentStore.teamScores.addOrUpdate(instance: teamScoreLuckyLoser)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -285,13 +297,18 @@ class Match: ModelObject, Storable {
let bottomMatchIndex = (nextIndex + 1) * 2 let bottomMatchIndex = (nextIndex + 1) * 2
let isTopMatch = topMatchIndex + 1 == index let isTopMatch = topMatchIndex + 1 == index
let lookingForIndex = isTopMatch ? topMatchIndex : bottomMatchIndex let lookingForIndex = isTopMatch ? topMatchIndex : bottomMatchIndex
return Store.main.filter(isIncluded: { $0.round == round && $0.index == lookingForIndex }).first
return self.tournamentStore.matches.first(where: { $0.round == round && $0.index == lookingForIndex })
// return Store.main.filter(isIncluded: { $0.round == round && $0.index == lookingForIndex }).first
} }
private func _forwardMatch(inRound round: Round) -> Match? { private func _forwardMatch(inRound round: Round) -> Match? {
guard let roundObjectNextRound = round.nextRound() else { return nil } guard let roundObjectNextRound = round.nextRound() else { return nil }
let nextIndex = (index - 1) / 2 let nextIndex = (index - 1) / 2
return Store.main.filter(isIncluded: { $0.round == roundObjectNextRound.id && $0.index == nextIndex }).first
return self.tournamentStore.matches.first(where: { $0.round == roundObjectNextRound.id && $0.index == nextIndex })
// return Store.main.filter(isIncluded: { $0.round == roundObjectNextRound.id && $0.index == nextIndex }).first
} }
func _toggleForwardMatchDisableState(_ state: Bool) { func _toggleForwardMatchDisableState(_ state: Bool) {
@ -335,7 +352,7 @@ class Match: ModelObject, Storable {
disabled = state disabled = state
//byeState = false //byeState = false
do { do {
try DataStore.shared.matches.addOrUpdate(instance: self) try self.tournamentStore.matches.addOrUpdate(instance: self)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -350,7 +367,8 @@ class Match: ModelObject, Storable {
} }
func next() -> Match? { func next() -> Match? {
return Store.main.filter(isIncluded: { $0.round == round && $0.index > index }).sorted(by: \.index).first let matches: [Match] = self.tournamentStore.matches.filter { $0.round == round && $0.index > index }
return matches.sorted(by: \.index).first
} }
func followingMatch() -> Match? { func followingMatch() -> Match? {
@ -359,7 +377,8 @@ class Match: ModelObject, Storable {
} }
func getFollowingMatch(fromNextRoundId nextRoundId: String) -> Match? { func getFollowingMatch(fromNextRoundId nextRoundId: String) -> Match? {
return Store.main.filter(isIncluded: { $0.round == nextRoundId && $0.index == (index - 1) / 2 }).first return self.tournamentStore.matches.first(where: { $0.round == nextRoundId && $0.index == (index - 1) / 2 })
// return Store.main.filter(isIncluded: { $0.round == nextRoundId && $0.index == (index - 1) / 2 }).first
} }
func getDuration() -> Int { func getDuration() -> Int {
@ -386,7 +405,7 @@ class Match: ModelObject, Storable {
func topPreviousRoundMatch() -> Match? { func topPreviousRoundMatch() -> Match? {
guard let roundObject else { return nil } guard let roundObject else { return nil }
let matches: [Match] = Store.main.filter { match in let matches: [Match] = self.tournamentStore.matches.filter { match in
match.index == topPreviousRoundMatchIndex() && match.round != nil && match.round == roundObject.previousRound()?.id match.index == topPreviousRoundMatchIndex() && match.round != nil && match.round == roundObject.previousRound()?.id
} }
return matches.sorted(by: \.index).first return matches.sorted(by: \.index).first
@ -394,7 +413,7 @@ class Match: ModelObject, Storable {
func bottomPreviousRoundMatch() -> Match? { func bottomPreviousRoundMatch() -> Match? {
guard let roundObject else { return nil } guard let roundObject else { return nil }
let matches: [Match] = Store.main.filter { match in let matches: [Match] = self.tournamentStore.matches.filter { match in
match.index == bottomPreviousRoundMatchIndex() && match.round != nil && match.round == roundObject.previousRound()?.id match.index == bottomPreviousRoundMatchIndex() && match.round != nil && match.round == roundObject.previousRound()?.id
} }
return matches.sorted(by: \.index).first return matches.sorted(by: \.index).first
@ -428,7 +447,7 @@ class Match: ModelObject, Storable {
func previousMatches() -> [Match] { func previousMatches() -> [Match] {
guard let roundObject else { return [] } guard let roundObject else { return [] }
return Store.main.filter { match in return self.tournamentStore.matches.filter { match in
(match.index == topPreviousRoundMatchIndex() || match.index == bottomPreviousRoundMatchIndex()) (match.index == topPreviousRoundMatchIndex() || match.index == bottomPreviousRoundMatchIndex())
&& match.round == roundObject.previousRound()?.id && match.round == roundObject.previousRound()?.id
}.sorted(by: \.index) }.sorted(by: \.index)
@ -449,7 +468,7 @@ class Match: ModelObject, Storable {
let teamScoreWinning = teamScore(teamPosition.otherTeam) ?? TeamScore(match: id, team: team(teamPosition.otherTeam)) let teamScoreWinning = teamScore(teamPosition.otherTeam) ?? TeamScore(match: id, team: team(teamPosition.otherTeam))
teamScoreWinning.walkOut = nil teamScoreWinning.walkOut = nil
do { do {
try DataStore.shared.teamScores.addOrUpdate(contentOfs: [teamScoreWalkout, teamScoreWinning]) try self.tournamentStore.teamScores.addOrUpdate(contentOfs: [teamScoreWalkout, teamScoreWinning])
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -486,7 +505,7 @@ class Match: ModelObject, Storable {
let teamScoreTwo = teamScore(.two) ?? TeamScore(match: id, team: team(.two)) let teamScoreTwo = teamScore(.two) ?? TeamScore(match: id, team: team(.two))
teamScoreTwo.score = matchDescriptor.teamTwoScores.joined(separator: ",") teamScoreTwo.score = matchDescriptor.teamTwoScores.joined(separator: ",")
do { do {
try DataStore.shared.teamScores.addOrUpdate(contentOfs: [teamScoreOne, teamScoreTwo]) try self.tournamentStore.teamScores.addOrUpdate(contentOfs: [teamScoreOne, teamScoreTwo])
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -503,7 +522,7 @@ class Match: ModelObject, Storable {
let teamScores = teamScores.filter({ ids.contains($0.id) == false }) let teamScores = teamScores.filter({ ids.contains($0.id) == false })
if teamScores.isEmpty == false { if teamScores.isEmpty == false {
do { do {
try DataStore.shared.teamScores.delete(contentOfs: teamScores) try self.tournamentStore.teamScores.delete(contentOfs: teamScores)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -529,7 +548,7 @@ class Match: ModelObject, Storable {
func updateTeamScores() { func updateTeamScores() {
let teams = getOrCreateTeamScores() let teams = getOrCreateTeamScores()
do { do {
try DataStore.shared.teamScores.addOrUpdate(contentOfs: teams) try self.tournamentStore.teamScores.addOrUpdate(contentOfs: teams)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -660,7 +679,7 @@ class Match: ModelObject, Storable {
} }
func scores() -> [TeamScore] { func scores() -> [TeamScore] {
return Store.main.filter(isIncluded: { $0.match == id }) return self.tournamentStore.teamScores.filter { $0.match == id }
} }
func teams() -> [TeamRegistration] { func teams() -> [TeamRegistration] {
@ -773,12 +792,12 @@ class Match: ModelObject, Storable {
var roundObject: Round? { var roundObject: Round? {
guard let round else { return nil } guard let round else { return nil }
return Store.main.findById(round) return self.tournamentStore.rounds.findById(round)
} }
var groupStageObject: GroupStage? { var groupStageObject: GroupStage? {
guard let groupStage else { return nil } guard let groupStage else { return nil }
return Store.main.findById(groupStage) return self.tournamentStore.groupStages.findById(groupStage)
} }
var isLoserBracket: Bool { var isLoserBracket: Bool {
@ -877,8 +896,8 @@ class Match: ModelObject, Storable {
try container.encode(confirmed, forKey: ._confirmed) try container.encode(confirmed, forKey: ._confirmed)
} }
func insertOnServer() throws { func insertOnServer() {
try DataStore.shared.matches.writeChangeAndInsertOnServer(instance: self) self.tournamentStore.matches.writeChangeAndInsertOnServer(instance: self)
for teamScore in self.teamScores { for teamScore in self.teamScores {
try teamScore.insertOnServer() try teamScore.insertOnServer()
} }

@ -14,6 +14,7 @@ class MatchScheduler : ModelObject, Storable {
static func resourceName() -> String { return "match-scheduler" } static func resourceName() -> String { return "match-scheduler" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func filterByStoreIdentifier() -> Bool { return false }
private(set) var id: String = Store.randomId() private(set) var id: String = Store.randomId()
var tournament: String var tournament: String
@ -79,6 +80,10 @@ class MatchScheduler : ModelObject, Storable {
return tournamentObject()?.additionalEstimationDuration ?? 0 return tournamentObject()?.additionalEstimationDuration ?? 0
} }
var tournamentStore: TournamentStore {
return TournamentStore.instance(tournamentId: self.tournament)
}
func tournamentObject() -> Tournament? { func tournamentObject() -> Tournament? {
return Store.main.findById(tournament) return Store.main.findById(tournament)
} }
@ -132,7 +137,7 @@ class MatchScheduler : ModelObject, Storable {
groupStages.filter({ $0.startDate == nil || times.contains($0.startDate!) == false }).chunked(into: computedGroupStageChunkCount).forEach { groups in groupStages.filter({ $0.startDate == nil || times.contains($0.startDate!) == false }).chunked(into: computedGroupStageChunkCount).forEach { groups in
groups.forEach({ $0.startDate = lastDate }) groups.forEach({ $0.startDate = lastDate })
do { do {
try DataStore.shared.groupStages.addOrUpdate(contentOfs: groups) try self.tournamentStore.groupStages.addOrUpdate(contentOfs: groups)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -153,7 +158,7 @@ class MatchScheduler : ModelObject, Storable {
} }
} }
do { do {
try DataStore.shared.matches.addOrUpdate(contentOfs: matches) try self.tournamentStore.matches.addOrUpdate(contentOfs: matches)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -649,7 +654,7 @@ class MatchScheduler : ModelObject, Storable {
} }
do { do {
try DataStore.shared.matches.addOrUpdate(contentOfs: allMatches) try self.tournamentStore.matches.addOrUpdate(contentOfs: allMatches)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -14,6 +14,7 @@ class MonthData : ModelObject, Storable {
static func resourceName() -> String { return "month-data" } static func resourceName() -> String { return "month-data" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func filterByStoreIdentifier() -> Bool { return false }
private(set) var id: String = Store.randomId() private(set) var id: String = Store.randomId()
private(set) var monthKey: String private(set) var monthKey: String

@ -12,6 +12,7 @@ import LeStorage
class PlayerRegistration: ModelObject, Storable { class PlayerRegistration: ModelObject, Storable {
static func resourceName() -> String { "player-registrations" } static func resourceName() -> String { "player-registrations" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func filterByStoreIdentifier() -> Bool { return true }
var id: String = Store.randomId() var id: String = Store.randomId()
var teamRegistration: String? var teamRegistration: String?
@ -96,6 +97,13 @@ class PlayerRegistration: ModelObject, Storable {
} }
} }
var tournamentStore: TournamentStore {
if let store = self.store as? TournamentStore {
return store
}
fatalError("missing store for \(String(describing: type(of: self)))")
}
var computedAge: Int? { var computedAge: Int? {
if let birthdate { if let birthdate {
let components = birthdate.components(separatedBy: "/") let components = birthdate.components(separatedBy: "/")
@ -140,7 +148,7 @@ class PlayerRegistration: ModelObject, Storable {
func team() -> TeamRegistration? { func team() -> TeamRegistration? {
guard let teamRegistration else { return nil } guard let teamRegistration else { return nil }
return Store.main.findById(teamRegistration) return self.tournamentStore.teamRegistrations.findById(teamRegistration)
} }
func hasPaid() -> Bool { func hasPaid() -> Bool {
@ -472,8 +480,8 @@ class PlayerRegistration: ModelObject, Storable {
} }
} }
func insertOnServer() throws { func insertOnServer() {
try DataStore.shared.playerRegistrations.writeChangeAndInsertOnServer(instance: self) self.tournamentStore.playerRegistrations.writeChangeAndInsertOnServer(instance: self)
} }
} }

@ -13,6 +13,7 @@ import SwiftUI
class Round: ModelObject, Storable { class Round: ModelObject, Storable {
static func resourceName() -> String { "rounds" } static func resourceName() -> String { "rounds" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func filterByStoreIdentifier() -> Bool { return true }
var id: String = Store.randomId() var id: String = Store.randomId()
var tournament: String var tournament: String
@ -31,16 +32,22 @@ class Round: ModelObject, Storable {
// MARK: - Computed dependencies // MARK: - Computed dependencies
var tournamentStore: TournamentStore {
return TournamentStore.instance(tournamentId: self.tournament)
}
func tournamentObject() -> Tournament? { func tournamentObject() -> Tournament? {
return Store.main.findById(tournament) return Store.main.findById(tournament)
} }
func _matches() -> [Match] { func _matches() -> [Match] {
return Store.main.filter { $0.round == self.id } return self.tournamentStore.matches.filter { $0.round == self.id }
// return Store.main.filter { $0.round == self.id }
} }
func getDisabledMatches() -> [Match] { func getDisabledMatches() -> [Match] {
return Store.main.filter { $0.round == self.id && $0.disabled == true } return self.tournamentStore.matches.filter { $0.round == self.id && $0.disabled == true }
// return Store.main.filter { $0.round == self.id && $0.disabled == true }
} }
// MARK: - // MARK: -
@ -54,7 +61,6 @@ class Round: ModelObject, Storable {
} }
} }
func hasStarted() -> Bool { func hasStarted() -> Bool {
return playedMatches().anySatisfy({ $0.hasStarted() }) return playedMatches().anySatisfy({ $0.hasStarted() })
} }
@ -74,9 +80,14 @@ class Round: ModelObject, Storable {
func previousMatches(ofMatch match: Match) -> [Match] { func previousMatches(ofMatch match: Match) -> [Match] {
guard let previousRound = previousRound() else { return [] } guard let previousRound = previousRound() else { return [] }
return Store.main.filter {
return self.tournamentStore.filter {
($0.index == match.topPreviousRoundMatchIndex() || $0.index == match.bottomPreviousRoundMatchIndex()) && $0.round == previousRound.id ($0.index == match.topPreviousRoundMatchIndex() || $0.index == match.bottomPreviousRoundMatchIndex()) && $0.round == previousRound.id
} }
// return Store.main.filter {
// ($0.index == match.topPreviousRoundMatchIndex() || $0.index == match.bottomPreviousRoundMatchIndex()) && $0.round == previousRound.id
// }
} }
func precedentMatches(ofMatch match: Match) -> [Match] { func precedentMatches(ofMatch match: Match) -> [Match] {
@ -102,35 +113,49 @@ class Round: ModelObject, Storable {
} }
func seed(_ team: TeamPosition, inMatchIndex matchIndex: Int) -> TeamRegistration? { func seed(_ team: TeamPosition, inMatchIndex matchIndex: Int) -> TeamRegistration? {
return Store.main.filter(isIncluded: { return self.tournamentStore.teamRegistrations.first(where: {
$0.tournament == tournament $0.tournament == tournament
&& $0.bracketPosition != nil && $0.bracketPosition != nil
&& ($0.bracketPosition! / 2) == matchIndex && ($0.bracketPosition! / 2) == matchIndex
&& ($0.bracketPosition! % 2) == team.rawValue && ($0.bracketPosition! % 2) == team.rawValue
}).first })
// return Store.main.filter(isIncluded: {
// $0.tournament == tournament
// && $0.bracketPosition != nil
// && ($0.bracketPosition! / 2) == matchIndex
// && ($0.bracketPosition! % 2) == team.rawValue
// }).first
} }
func seeds(inMatchIndex matchIndex: Int) -> [TeamRegistration] { func seeds(inMatchIndex matchIndex: Int) -> [TeamRegistration] {
return Store.main.filter(isIncluded: { return self.tournamentStore.teamRegistrations.filter {
$0.tournament == tournament $0.tournament == tournament
&& $0.bracketPosition != nil && $0.bracketPosition != nil
&& ($0.bracketPosition! / 2) == matchIndex && ($0.bracketPosition! / 2) == matchIndex
}) }
// return Store.main.filter(isIncluded: {
// $0.tournament == tournament
// && $0.bracketPosition != nil
// && ($0.bracketPosition! / 2) == matchIndex
// })
} }
func seeds() -> [TeamRegistration] { func seeds() -> [TeamRegistration] {
let initialMatchIndex = RoundRule.matchIndex(fromRoundIndex: index) let initialMatchIndex = RoundRule.matchIndex(fromRoundIndex: index)
let numberOfMatches = RoundRule.numberOfMatches(forRoundIndex: index) let numberOfMatches = RoundRule.numberOfMatches(forRoundIndex: index)
return Store.main.filter(isIncluded: { return self.tournamentStore.teamRegistrations.filter {
$0.tournament == tournament $0.tournament == tournament
&& $0.bracketPosition != nil && $0.bracketPosition != nil
&& ($0.bracketPosition! / 2) >= initialMatchIndex && ($0.bracketPosition! / 2) >= initialMatchIndex
&& ($0.bracketPosition! / 2) < initialMatchIndex + numberOfMatches && ($0.bracketPosition! / 2) < initialMatchIndex + numberOfMatches
}) }
} }
func losers() -> [TeamRegistration] { func losers() -> [TeamRegistration] {
return _matches().compactMap { $0.losingTeamId }.compactMap { Store.main.findById($0) } let teamIds: [String] = self._matches().compactMap { $0.losingTeamId }
return teamIds.compactMap { self.tournamentStore.teamRegistrations.findById($0) }
} }
func teams() -> [TeamRegistration] { func teams() -> [TeamRegistration] {
@ -147,10 +172,10 @@ class Round: ModelObject, Storable {
if let luckyLoser = match.teamScores.first(where: { $0.luckyLoser == match.index * 2 }) { if let luckyLoser = match.teamScores.first(where: { $0.luckyLoser == match.index * 2 }) {
return luckyLoser.team return luckyLoser.team
} else if let parent = upperBracketTopMatch(ofMatchIndex: match.index)?.losingTeamId { } else if let parent = upperBracketTopMatch(ofMatchIndex: match.index)?.losingTeamId {
return Store.main.findById(parent) return self.tournamentStore.teamRegistrations.findById(parent)
} else if let previousMatch = topPreviousRoundMatch(ofMatch: match) { } else if let previousMatch = topPreviousRoundMatch(ofMatch: match) {
if let teamId = previousMatch.winningTeamId { if let teamId = previousMatch.winningTeamId {
return Store.main.findById(teamId) return self.tournamentStore.teamRegistrations.findById(teamId)
} else if previousMatch.disabled { } else if previousMatch.disabled {
return previousMatch.teams().first return previousMatch.teams().first
} }
@ -159,10 +184,10 @@ class Round: ModelObject, Storable {
if let luckyLoser = match.teamScores.first(where: { $0.luckyLoser == match.index * 2 + 1 }) { if let luckyLoser = match.teamScores.first(where: { $0.luckyLoser == match.index * 2 + 1 }) {
return luckyLoser.team return luckyLoser.team
} else if let parent = upperBracketBottomMatch(ofMatchIndex: match.index)?.losingTeamId { } else if let parent = upperBracketBottomMatch(ofMatchIndex: match.index)?.losingTeamId {
return Store.main.findById(parent) return self.tournamentStore.teamRegistrations.findById(parent)
} else if let previousMatch = bottomPreviousRoundMatch(ofMatch: match) { } else if let previousMatch = bottomPreviousRoundMatch(ofMatch: match) {
if let teamId = previousMatch.winningTeamId { if let teamId = previousMatch.winningTeamId {
return Store.main.findById(teamId) return self.tournamentStore.teamRegistrations.findById(teamId)
} else if previousMatch.disabled { } else if previousMatch.disabled {
return previousMatch.teams().first return previousMatch.teams().first
} }
@ -190,29 +215,39 @@ class Round: ModelObject, Storable {
func topPreviousRoundMatch(ofMatch match: Match) -> Match? { func topPreviousRoundMatch(ofMatch match: Match) -> Match? {
guard let previousRound = previousRound() else { return nil } guard let previousRound = previousRound() else { return nil }
let matches: [Match] = Store.main.filter {
let matches: [Match] = self.tournamentStore.matches.filter {
$0.index == match.topPreviousRoundMatchIndex() && $0.round == previousRound.id $0.index == match.topPreviousRoundMatchIndex() && $0.round == previousRound.id
} }
// let matches: [Match] = Store.main.filter {
// $0.index == match.topPreviousRoundMatchIndex() && $0.round == previousRound.id
// }
return matches.sorted(by: \.index).first return matches.sorted(by: \.index).first
} }
func bottomPreviousRoundMatch(ofMatch match: Match) -> Match? { func bottomPreviousRoundMatch(ofMatch match: Match) -> Match? {
guard let previousRound = previousRound() else { return nil } guard let previousRound = previousRound() else { return nil }
let matches: [Match] = Store.main.filter { let matches: [Match] = self.tournamentStore.matches.filter {
$0.index == match.bottomPreviousRoundMatchIndex() && $0.round == previousRound.id $0.index == match.bottomPreviousRoundMatchIndex() && $0.round == previousRound.id
} }
return matches.sorted(by: \.index).first return matches.sorted(by: \.index).first
} }
func getMatch(atMatchIndexInRound matchIndexInRound: Int) -> Match? { func getMatch(atMatchIndexInRound matchIndexInRound: Int) -> Match? {
Store.main.filter(isIncluded: { return self.tournamentStore.matches.first(where: {
let index = RoundRule.matchIndexWithinRound(fromMatchIndex: $0.index) let index = RoundRule.matchIndexWithinRound(fromMatchIndex: $0.index)
return $0.round == id && index == matchIndexInRound return $0.round == id && index == matchIndexInRound
}).first })
// Store.main.filter(isIncluded: {
// let index = RoundRule.matchIndexWithinRound(fromMatchIndex: $0.index)
// return $0.round == id && index == matchIndexInRound
// }).first
} }
func enabledMatches() -> [Match] { func enabledMatches() -> [Match] {
return Store.main.filter { $0.round == self.id && $0.disabled == false } return self.tournamentStore.matches.filter { $0.round == self.id && $0.disabled == false }
// return Store.main.filter { $0.round == self.id && $0.disabled == false }
} }
func displayableMatches() -> [Match] { func displayableMatches() -> [Match] {
@ -234,11 +269,12 @@ class Round: ModelObject, Storable {
} }
func previousRound() -> Round? { func previousRound() -> Round? {
return Store.main.filter(isIncluded: { $0.tournament == tournament && $0.parent == parent && $0.index == index + 1 }).first return self.tournamentStore.rounds.first(where: { $0.tournament == tournament && $0.parent == parent && $0.index == index + 1 })
// return Store.main.filter(isIncluded: { $0.tournament == tournament && $0.parent == parent && $0.index == index + 1 }).first
} }
func nextRound() -> Round? { func nextRound() -> Round? {
return Store.main.filter(isIncluded: { $0.tournament == tournament && $0.parent == parent && $0.index == index - 1 }).first return self.tournamentStore.rounds.first(where: { $0.tournament == tournament && $0.parent == parent && $0.index == index - 1 })
} }
func loserRounds(forRoundIndex roundIndex: Int) -> [Round] { func loserRounds(forRoundIndex roundIndex: Int) -> [Round] {
@ -302,7 +338,7 @@ class Round: ModelObject, Storable {
// } // }
} }
do { do {
try DataStore.shared.matches.addOrUpdate(contentOfs: _matches) try self.tournamentStore.matches.addOrUpdate(contentOfs: _matches)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -352,11 +388,18 @@ class Round: ModelObject, Storable {
func correspondingLoserRoundTitle(_ displayStyle: DisplayStyle = .wide) -> String { func correspondingLoserRoundTitle(_ displayStyle: DisplayStyle = .wide) -> String {
let initialMatchIndexFromRoundIndex = RoundRule.matchIndex(fromRoundIndex: index) let initialMatchIndexFromRoundIndex = RoundRule.matchIndex(fromRoundIndex: index)
let seedsAfterThisRound : [TeamRegistration] = Store.main.filter(isIncluded: {
let seedsAfterThisRound: [TeamRegistration] = self.tournamentStore.teamRegistrations.filter {
$0.tournament == tournament $0.tournament == tournament
&& $0.bracketPosition != nil && $0.bracketPosition != nil
&& ($0.bracketPosition! / 2) < initialMatchIndexFromRoundIndex && ($0.bracketPosition! / 2) < initialMatchIndexFromRoundIndex
}) }
// let seedsAfterThisRound : [TeamRegistration] = Store.main.filter(isIncluded: {
// $0.tournament == tournament
// && $0.bracketPosition != nil
// && ($0.bracketPosition! / 2) < initialMatchIndexFromRoundIndex
// })
let playedMatches = playedMatches() let playedMatches = playedMatches()
let seedInterval = SeedInterval(first: playedMatches.count + seedsAfterThisRound.count + 1, last: playedMatches.count * 2 + seedsAfterThisRound.count) let seedInterval = SeedInterval(first: playedMatches.count + seedsAfterThisRound.count + 1, last: playedMatches.count * 2 + seedsAfterThisRound.count)
return seedInterval.localizedLabel(displayStyle) return seedInterval.localizedLabel(displayStyle)
@ -370,11 +413,11 @@ class Round: ModelObject, Storable {
if parent == nil { if parent == nil {
let numberOfMatches = RoundRule.numberOfMatches(forRoundIndex: index + 1) let numberOfMatches = RoundRule.numberOfMatches(forRoundIndex: index + 1)
let initialMatchIndexFromRoundIndex = RoundRule.matchIndex(fromRoundIndex: index) let initialMatchIndexFromRoundIndex = RoundRule.matchIndex(fromRoundIndex: index)
let seedsAfterThisRound : [TeamRegistration] = Store.main.filter(isIncluded: { let seedsAfterThisRound : [TeamRegistration] = self.tournamentStore.teamRegistrations.filter {
$0.tournament == tournament $0.tournament == tournament
&& $0.bracketPosition != nil && $0.bracketPosition != nil
&& ($0.bracketPosition! / 2) < initialMatchIndexFromRoundIndex && ($0.bracketPosition! / 2) < initialMatchIndexFromRoundIndex
}) }
let playedMatches = playedMatches() let playedMatches = playedMatches()
let reduce = numberOfMatches / 2 - (playedMatches.count + seedsAfterThisRound.count) let reduce = numberOfMatches / 2 - (playedMatches.count + seedsAfterThisRound.count)
return SeedInterval(first: 1, last: numberOfMatches, reduce: reduce) return SeedInterval(first: 1, last: numberOfMatches, reduce: reduce)
@ -419,7 +462,8 @@ class Round: ModelObject, Storable {
} }
func loserRounds() -> [Round] { func loserRounds() -> [Round] {
return Store.main.filter(isIncluded: { $0.parent == id }).sorted(by: \.index).reversed() let rounds: [Round] = self.tournamentStore.rounds.filter { $0.parent == id }
return rounds.sorted(by: \.index).reversed()
} }
func loserRoundsAndChildren() -> [Round] { func loserRoundsAndChildren() -> [Round] {
@ -449,7 +493,7 @@ class Round: ModelObject, Storable {
} }
do { do {
try DataStore.shared.rounds.addOrUpdate(contentOfs: rounds) try self.tournamentStore.rounds.addOrUpdate(contentOfs: rounds)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -462,7 +506,7 @@ class Round: ModelObject, Storable {
} }
do { do {
try DataStore.shared.matches.addOrUpdate(contentOfs: matches) try self.tournamentStore.matches.addOrUpdate(contentOfs: matches)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -474,7 +518,7 @@ class Round: ModelObject, Storable {
var parentRound: Round? { var parentRound: Round? {
guard let parent = parent else { return nil } guard let parent = parent else { return nil }
return Store.main.findById(parent) return self.tournamentStore.rounds.findById(parent)
} }
func updateMatchFormat(_ updatedMatchFormat: MatchFormat, checkIfPossible: Bool, andLoserBracket: Bool) { func updateMatchFormat(_ updatedMatchFormat: MatchFormat, checkIfPossible: Bool, andLoserBracket: Bool) {
@ -499,15 +543,15 @@ class Round: ModelObject, Storable {
match.matchFormat = updatedMatchFormat match.matchFormat = updatedMatchFormat
} }
do { do {
try DataStore.shared.matches.addOrUpdate(contentOfs: playedMatches) try self.tournamentStore.matches.addOrUpdate(contentOfs: playedMatches)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
} }
override func deleteDependencies() throws { override func deleteDependencies() throws {
DataStore.shared.matches.deleteDependencies(self._matches()) self.tournamentStore.matches.deleteDependencies(self._matches())
DataStore.shared.rounds.deleteDependencies(self.loserRoundsAndChildren()) self.tournamentStore.rounds.deleteDependencies(self.loserRoundsAndChildren())
} }
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
@ -545,10 +589,10 @@ class Round: ModelObject, Storable {
} }
} }
func insertOnServer() throws { func insertOnServer() {
try DataStore.shared.rounds.writeChangeAndInsertOnServer(instance: self) self.tournamentStore.rounds.writeChangeAndInsertOnServer(instance: self)
for match in self._matches() { for match in self._matches() {
try match.insertOnServer() match.insertOnServer()
} }
} }

@ -12,6 +12,7 @@ import LeStorage
class TeamRegistration: ModelObject, Storable { class TeamRegistration: ModelObject, Storable {
static func resourceName() -> String { "team-registrations" } static func resourceName() -> String { "team-registrations" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func filterByStoreIdentifier() -> Bool { return true }
var id: String = Store.randomId() var id: String = Store.randomId()
var tournament: String var tournament: String
@ -57,24 +58,29 @@ class TeamRegistration: ModelObject, Storable {
self.qualified = qualified self.qualified = qualified
} }
var tournamentStore: TournamentStore {
return TournamentStore.instance(tournamentId: self.tournament)
}
// MARK: - Computed dependencies // MARK: - Computed dependencies
func unsortedPlayers() -> [PlayerRegistration] { func unsortedPlayers() -> [PlayerRegistration] {
Store.main.filter { $0.teamRegistration == self.id } return self.tournamentStore.playerRegistrations.filter { $0.teamRegistration == self.id }
// Store.main.filter { $0.teamRegistration == self.id }
} }
// MARK: - // MARK: -
override func deleteDependencies() throws { override func deleteDependencies() throws {
DataStore.shared.playerRegistrations.deleteDependencies(self.unsortedPlayers()) self.tournamentStore.playerRegistrations.deleteDependencies(self.unsortedPlayers())
DataStore.shared.teamScores.deleteDependencies(self.teamScores()) self.tournamentStore.teamScores.deleteDependencies(self.teamScores())
} }
func hasArrived() { func hasArrived() {
let unsortedPlayers = unsortedPlayers() let unsortedPlayers = unsortedPlayers()
unsortedPlayers.forEach({ $0.hasArrived = true }) unsortedPlayers.forEach({ $0.hasArrived = true })
do { do {
try DataStore.shared.playerRegistrations.addOrUpdate(contentOfs: unsortedPlayers) try self.tournamentStore.playerRegistrations.addOrUpdate(contentOfs: unsortedPlayers)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -138,19 +144,23 @@ class TeamRegistration: ModelObject, Storable {
} }
func teamScores() -> [TeamScore] { func teamScores() -> [TeamScore] {
return Store.main.filter(isIncluded: { $0.teamRegistration == id }) return self.tournamentStore.teamScores.filter { $0.teamRegistration == id }
// return Store.main.filter(isIncluded: { $0.teamRegistration == id })
} }
func wins() -> [Match] { func wins() -> [Match] {
return Store.main.filter(isIncluded: { $0.winningTeamId == id }) return self.tournamentStore.matches.filter { $0.winningTeamId == id }
// return Store.main.filter(isIncluded: { $0.winningTeamId == id })
} }
func loses() -> [Match] { func loses() -> [Match] {
return Store.main.filter(isIncluded: { $0.losingTeamId == id }) return self.tournamentStore.matches.filter { $0.losingTeamId == id }
// return Store.main.filter(isIncluded: { $0.losingTeamId == id })
} }
func matches() -> [Match] { func matches() -> [Match] {
return Store.main.filter(isIncluded: { $0.losingTeamId == id || $0.winningTeamId == id }) return self.tournamentStore.matches.filter { $0.losingTeamId == id || $0.winningTeamId == id }
// return Store.main.filter(isIncluded: { $0.losingTeamId == id || $0.winningTeamId == id })
} }
var tournamentCategory: TournamentCategory { var tournamentCategory: TournamentCategory {
@ -273,7 +283,7 @@ class TeamRegistration: ModelObject, Storable {
let previousPlayers = Set(unsortedPlayers()) let previousPlayers = Set(unsortedPlayers())
let playersToRemove = previousPlayers.subtracting(players) let playersToRemove = previousPlayers.subtracting(players)
do { do {
try DataStore.shared.playerRegistrations.delete(contentOfs: playersToRemove) try self.tournamentStore.playerRegistrations.delete(contentOfs: playersToRemove)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -323,7 +333,10 @@ class TeamRegistration: ModelObject, Storable {
typealias AreInIncreasingOrder = (PlayerRegistration, PlayerRegistration) -> Bool typealias AreInIncreasingOrder = (PlayerRegistration, PlayerRegistration) -> Bool
func players() -> [PlayerRegistration] { func players() -> [PlayerRegistration] {
Store.main.filter { $0.teamRegistration == self.id }.sorted { (lhs, rhs) in
let playerRegistration = self.tournamentStore.playerRegistrations.filter { $0.teamRegistration == self.id }
return playerRegistration.sorted { (lhs, rhs) in
let predicates: [AreInIncreasingOrder] = [ let predicates: [AreInIncreasingOrder] = [
{ $0.sex?.rawValue ?? 0 < $1.sex?.rawValue ?? 0 }, { $0.sex?.rawValue ?? 0 < $1.sex?.rawValue ?? 0 },
{ $0.rank ?? 0 < $1.rank ?? 0 }, { $0.rank ?? 0 < $1.rank ?? 0 },
@ -371,19 +384,21 @@ class TeamRegistration: ModelObject, Storable {
func groupStageObject() -> GroupStage? { func groupStageObject() -> GroupStage? {
guard let groupStage else { return nil } guard let groupStage else { return nil }
return Store.main.findById(groupStage) return self.tournamentStore.groupStages.findById(groupStage)
} }
func initialRound() -> Round? { func initialRound() -> Round? {
guard let bracketPosition else { return nil } guard let bracketPosition else { return nil }
let roundIndex = RoundRule.roundIndex(fromMatchIndex: bracketPosition / 2) let roundIndex = RoundRule.roundIndex(fromMatchIndex: bracketPosition / 2)
return Store.main.filter(isIncluded: { $0.tournament == tournament && $0.index == roundIndex }).first return self.tournamentStore.rounds.first(where: { $0.index == roundIndex })
// return Store.main.filter(isIncluded: { $0.tournament == tournament && $0.index == roundIndex }).first
} }
func initialMatch() -> Match? { func initialMatch() -> Match? {
guard let bracketPosition else { return nil } guard let bracketPosition else { return nil }
guard let initialRoundObject = initialRound() else { return nil } guard let initialRoundObject = initialRound() else { return nil }
return Store.main.filter(isIncluded: { $0.round == initialRoundObject.id && $0.index == bracketPosition / 2 }).first return self.tournamentStore.matches.first(where: { $0.round == initialRoundObject.id && $0.index == bracketPosition / 2 })
// return Store.main.filter(isIncluded: { $0.round == initialRoundObject.id && $0.index == bracketPosition / 2 }).first
} }
@ -513,10 +528,10 @@ class TeamRegistration: ModelObject, Storable {
} }
} }
func insertOnServer() throws { func insertOnServer() {
try DataStore.shared.teamRegistrations.writeChangeAndInsertOnServer(instance: self) self.tournamentStore.teamRegistrations.writeChangeAndInsertOnServer(instance: self)
for playerRegistration in self.unsortedPlayers() { for playerRegistration in self.unsortedPlayers() {
try playerRegistration.insertOnServer() playerRegistration.insertOnServer()
} }
} }

@ -13,6 +13,7 @@ class TeamScore: ModelObject, Storable {
static func resourceName() -> String { "team-scores" } static func resourceName() -> String { "team-scores" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func filterByStoreIdentifier() -> Bool { return true }
var id: String = Store.randomId() var id: String = Store.randomId()
var match: String var match: String
@ -42,17 +43,24 @@ class TeamScore: ModelObject, Storable {
self.luckyLoser = nil self.luckyLoser = nil
} }
var tournamentStore: TournamentStore {
if let store = self.store as? TournamentStore {
return store
}
fatalError("missing store for \(String(describing: type(of: self)))")
}
// MARK: - Computed dependencies // MARK: - Computed dependencies
func matchObject() -> Match? { func matchObject() -> Match? {
return DataStore.shared.matches.findById(self.match) return self.tournamentStore.matches.findById(self.match)
} }
var team: TeamRegistration? { var team: TeamRegistration? {
guard let teamRegistration else { guard let teamRegistration else {
return nil return nil
} }
return DataStore.shared.teamRegistrations.findById(teamRegistration) return self.tournamentStore.teamRegistrations.findById(teamRegistration)
} }
// MARK: - // MARK: -
@ -104,8 +112,8 @@ class TeamScore: ModelObject, Storable {
} }
} }
func insertOnServer() throws { func insertOnServer() {
try DataStore.shared.teamScores.writeChangeAndInsertOnServer(instance: self) self.tournamentStore.teamScores.writeChangeAndInsertOnServer(instance: self)
} }
} }

@ -12,6 +12,7 @@ import LeStorage
class Tournament : ModelObject, Storable { class Tournament : ModelObject, Storable {
static func resourceName() -> String { "tournaments" } static func resourceName() -> String { "tournaments" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func filterByStoreIdentifier() -> Bool { return false }
var id: String = Store.randomId() var id: String = Store.randomId()
var event: String? var event: String?
@ -334,26 +335,35 @@ class Tournament : ModelObject, Storable {
} }
} }
var tournamentStore: TournamentStore {
return TournamentStore.instance(tournamentId: self.id)
}
override func deleteDependencies() throws { override func deleteDependencies() throws {
DataStore.shared.teamRegistrations.deleteDependencies(self.unsortedTeams()) let store = self.tournamentStore
DataStore.shared.groupStages.deleteDependencies(self.groupStages()) store.teamRegistrations.deleteDependencies(self.unsortedTeams())
DataStore.shared.rounds.deleteDependencies(self.rounds()) store.groupStages.deleteDependencies(self.groupStages())
DataStore.shared.matchSchedulers.deleteDependencies(self._matchSchedulers()) store.rounds.deleteDependencies(self.rounds())
store.matchSchedulers.deleteDependencies(self._matchSchedulers())
} }
// MARK: - Computed Dependencies // MARK: - Computed Dependencies
func unsortedTeams() -> [TeamRegistration] { func unsortedTeams() -> [TeamRegistration] {
return Store.main.filter { $0.tournament == self.id } return Array(self.tournamentStore.teamRegistrations)
} }
func groupStages() -> [GroupStage] { func groupStages() -> [GroupStage] {
let groupStages: [GroupStage] = DataStore.shared.groupStages.filter { $0.tournament == self.id } let groupStages: [GroupStage] = self.tournamentStore.groupStages.filter { $0.tournament == self.id }
return groupStages.sorted(by: \.index) return groupStages.sorted(by: \.index)
} }
func allGroupStages() -> [GroupStage] {
return Array(self.tournamentStore.groupStages)
}
func allRounds() -> [Round] { func allRounds() -> [Round] {
return Store.main.filter { $0.tournament == self.id } return Array(self.tournamentStore.rounds)
} }
// MARK: - // MARK: -
@ -476,7 +486,8 @@ class Tournament : ModelObject, Storable {
} }
func courtUsed() -> [Int] { func courtUsed() -> [Int] {
let runningMatches : [Match] = Store.main.filter(isIncluded: { $0.isRunning() }).filter({ $0.tournamentId() == self.id }) let runningMatches: [Match] = self.tournamentStore.matches.filter { $0.isRunning() }
// let runningMatches : [Match] = Store.main.filter(isIncluded: { $0.isRunning() }).filter({ $0.tournamentId() == self.id })
return Set(runningMatches.compactMap { $0.courtIndex }).sorted() return Set(runningMatches.compactMap { $0.courtIndex }).sorted()
} }
@ -569,7 +580,8 @@ class Tournament : ModelObject, Storable {
} }
func getRound(atRoundIndex roundIndex: Int) -> Round? { func getRound(atRoundIndex roundIndex: Int) -> Round? {
return Store.main.filter(isIncluded: { $0.tournament == id && $0.index == roundIndex }).first return self.tournamentStore.rounds.first(where: { $0.index == roundIndex })
// return Store.main.filter(isIncluded: { $0.tournament == id && $0.index == roundIndex }).first
} }
func availableSeedSpot(inRoundIndex roundIndex: Int) -> [Match] { func availableSeedSpot(inRoundIndex roundIndex: Int) -> [Match] {
@ -746,18 +758,19 @@ class Tournament : ModelObject, Storable {
} }
func allMatches() -> [Match] { func allMatches() -> [Match] {
let unsortedGroupStages : [GroupStage] = Store.main.filter { $0.tournament == self.id } let unsortedGroupStages: [GroupStage] = Store.main.filter { $0.tournament == self.id }
let matches: [Match] = unsortedGroupStages.flatMap { $0._matches() } + allRoundMatches() let matches: [Match] = self.allGroupStages().flatMap { $0._matches() } + allRoundMatches()
return matches.filter({ $0.disabled == false }) return matches.filter({ $0.disabled == false })
} }
func _allMatchesIncludingDisabled() -> [Match] { func _allMatchesIncludingDisabled() -> [Match] {
let unsortedGroupStages : [GroupStage] = Store.main.filter { $0.tournament == self.id } return self.allGroupStages().flatMap { $0._matches() } + allRounds().flatMap { $0._matches() }
return unsortedGroupStages.flatMap { $0._matches() } + allRounds().flatMap { $0._matches() }
} }
func rounds() -> [Round] { func rounds() -> [Round] {
Store.main.filter { $0.tournament == self.id && $0.parent == nil }.sorted(by: \.index).reversed() let rounds: [Round] = self.tournamentStore.rounds.filter { $0.parent == nil }
return rounds.sorted(by: \.index).reversed()
// Store.main.filter { $0.tournament == self.id && $0.parent == nil }.sorted(by: \.index).reversed()
} }
func sortedTeams() -> [TeamRegistration] { func sortedTeams() -> [TeamRegistration] {
@ -842,11 +855,13 @@ class Tournament : ModelObject, Storable {
} }
func unsortedTeamsWithoutWO() -> [TeamRegistration] { func unsortedTeamsWithoutWO() -> [TeamRegistration] {
return Store.main.filter { $0.tournament == self.id && $0.walkOut == false } return self.tournamentStore.teamRegistrations.filter { $0.walkOut == false }
// return Store.main.filter { $0.tournament == self.id && $0.walkOut == false }
} }
func walkoutTeams() -> [TeamRegistration] { func walkoutTeams() -> [TeamRegistration] {
return Store.main.filter { $0.tournament == self.id && $0.walkOut == true } return self.tournamentStore.teamRegistrations.filter { $0.walkOut == true }
// return Store.main.filter { $0.tournament == self.id && $0.walkOut == true }
} }
func duplicates(in players: [PlayerRegistration]) -> [PlayerRegistration] { func duplicates(in players: [PlayerRegistration]) -> [PlayerRegistration] {
@ -971,12 +986,12 @@ class Tournament : ModelObject, Storable {
} }
do { do {
try DataStore.shared.teamRegistrations.addOrUpdate(contentOfs: teamsToImport) try self.tournamentStore.teamRegistrations.addOrUpdate(contentOfs: teamsToImport)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
do { do {
try DataStore.shared.playerRegistrations.addOrUpdate(contentOfs: teams.flatMap { $0.players }) try self.tournamentStore.playerRegistrations.addOrUpdate(contentOfs: teams.flatMap { $0.players })
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -1015,7 +1030,8 @@ class Tournament : ModelObject, Storable {
func groupStagesMatches() -> [Match] { func groupStagesMatches() -> [Match] {
let groupStageIds = groupStages().map { $0.id } let groupStageIds = groupStages().map { $0.id }
return Store.main.filter(isIncluded: { $0.groupStage != nil && groupStageIds.contains($0.groupStage!) }) return self.tournamentStore.matches.filter { $0.groupStage != nil && groupStageIds.contains($0.groupStage!) }
// return Store.main.filter(isIncluded: { $0.groupStage != nil && groupStageIds.contains($0.groupStage!) })
} }
func availableToStart(_ allMatches: [Match], in runningMatches: [Match]) async -> [Match] { func availableToStart(_ allMatches: [Match], in runningMatches: [Match]) async -> [Match] {
@ -1148,7 +1164,7 @@ class Tournament : ModelObject, Storable {
team.lockedWeight = team.weight team.lockedWeight = team.weight
} }
do { do {
try DataStore.shared.teamRegistrations.addOrUpdate(contentOfs: teams) try self.tournamentStore.teamRegistrations.addOrUpdate(contentOfs: teams)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -1161,13 +1177,13 @@ class Tournament : ModelObject, Storable {
players.forEach { $0.setComputedRank(in: self) } players.forEach { $0.setComputedRank(in: self) }
team.setWeight(from: players, inTournamentCategory: tournamentCategory) team.setWeight(from: players, inTournamentCategory: tournamentCategory)
do { do {
try DataStore.shared.playerRegistrations.addOrUpdate(contentOfs: players) try self.tournamentStore.playerRegistrations.addOrUpdate(contentOfs: players)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
} }
do { do {
try DataStore.shared.teamRegistrations.addOrUpdate(contentOfs: teams) try self.tournamentStore.teamRegistrations.addOrUpdate(contentOfs: teams)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -1418,7 +1434,7 @@ class Tournament : ModelObject, Storable {
} }
do { do {
try DataStore.shared.groupStages.addOrUpdate(contentOfs: _groupStages) try self.tournamentStore.groupStages.addOrUpdate(contentOfs: _groupStages)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -1440,7 +1456,7 @@ class Tournament : ModelObject, Storable {
} }
do { do {
try DataStore.shared.rounds.addOrUpdate(contentOfs: rounds) try self.tournamentStore.rounds.addOrUpdate(contentOfs: rounds)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -1457,7 +1473,7 @@ class Tournament : ModelObject, Storable {
}) })
do { do {
try DataStore.shared.matches.addOrUpdate(contentOfs: matches) try self.tournamentStore.matches.addOrUpdate(contentOfs: matches)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -1471,8 +1487,9 @@ class Tournament : ModelObject, Storable {
guard let bracketPosition else { return nil } guard let bracketPosition else { return nil }
let matchIndex = bracketPosition / 2 let matchIndex = bracketPosition / 2
let roundIndex = RoundRule.roundIndex(fromMatchIndex: matchIndex) let roundIndex = RoundRule.roundIndex(fromMatchIndex: matchIndex)
if let round : Round = Store.main.filter(isIncluded: { $0.tournament == id && $0.index == roundIndex }).first { if let round: Round = self.getRound(atRoundIndex: roundIndex) {
return Store.main.filter(isIncluded: { $0.round == round.id && $0.index == matchIndex }).first return self.tournamentStore.matches.first(where: { $0.round == round.id && $0.index == matchIndex })
// return Store.main.filter(isIncluded: { $0.round == round.id && $0.index == matchIndex }).first
} }
return nil return nil
} }
@ -1489,13 +1506,13 @@ class Tournament : ModelObject, Storable {
func deleteStructure() { func deleteStructure() {
do { do {
try DataStore.shared.rounds.delete(contentOfs: rounds()) try self.tournamentStore.rounds.delete(contentOfs: rounds())
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
unsortedTeams().forEach({ $0.bracketPosition = nil }) unsortedTeams().forEach({ $0.bracketPosition = nil })
do { do {
try DataStore.shared.teamRegistrations.addOrUpdate(contentOfs: unsortedTeams()) try self.tournamentStore.teamRegistrations.addOrUpdate(contentOfs: unsortedTeams())
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -1503,7 +1520,7 @@ class Tournament : ModelObject, Storable {
func deleteGroupStages() { func deleteGroupStages() {
do { do {
try DataStore.shared.groupStages.delete(contentOfs: groupStages()) try self.tournamentStore.groupStages.delete(contentOfs: groupStages())
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -1513,7 +1530,7 @@ class Tournament : ModelObject, Storable {
$0.groupStage = nil $0.groupStage = nil
$0.groupStagePosition = nil $0.groupStagePosition = nil
}) })
try DataStore.shared.teamRegistrations.addOrUpdate(contentOfs: unsortedTeams()) try self.tournamentStore.teamRegistrations.addOrUpdate(contentOfs: unsortedTeams())
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -1564,7 +1581,7 @@ class Tournament : ModelObject, Storable {
} }
do { do {
try DataStore.shared.teamRegistrations.addOrUpdate(contentOfs: unsortedTeams()) try self.tournamentStore.teamRegistrations.addOrUpdate(contentOfs: unsortedTeams())
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -1725,7 +1742,7 @@ class Tournament : ModelObject, Storable {
private let _currentSelectionSorting : [MySortDescriptor<TeamRegistration>] = [.keyPath(\.weight), .keyPath(\.registrationDate!)] private let _currentSelectionSorting : [MySortDescriptor<TeamRegistration>] = [.keyPath(\.weight), .keyPath(\.registrationDate!)]
private func _matchSchedulers() -> [MatchScheduler] { private func _matchSchedulers() -> [MatchScheduler] {
return DataStore.shared.matchSchedulers.filter { $0.tournament == self.id } return self.tournamentStore.matchSchedulers.filter { $0.tournament == self.id }
// DataStore.shared.matchSchedulers.filter(isIncluded: { $0.tournament == self.id }) // DataStore.shared.matchSchedulers.filter(isIncluded: { $0.tournament == self.id })
} }
@ -1736,7 +1753,8 @@ class Tournament : ModelObject, Storable {
func currentMonthData() -> MonthData? { func currentMonthData() -> MonthData? {
guard let rankSourceDate else { return nil } guard let rankSourceDate else { return nil }
let dateString = URL.importDateFormatter.string(from: rankSourceDate) let dateString = URL.importDateFormatter.string(from: rankSourceDate)
return Store.main.filter(isIncluded: { $0.monthKey == dateString }).first return DataStore.shared.monthData.first(where: { $0.monthKey == dateString })
// return Store.main.filter(isIncluded: { $0.monthKey == dateString }).first
} }
var maleUnrankedValue: Int? { var maleUnrankedValue: Int? {
@ -1756,9 +1774,11 @@ class Tournament : ModelObject, Storable {
} }
func tournamentWinner() -> TeamRegistration? { func tournamentWinner() -> TeamRegistration? {
let rounds: [Round] = Store.main.filter(isIncluded: { $0.index == 0 && $0.tournament == id && $0.parent == nil }) let finals: Round? = self.tournamentStore.rounds.first(where: { $0.index == 0 && $0.parent == nil })
// let rounds: [Round] = Store.main.filter(isIncluded: { $0.index == 0 && $0.tournament == id && $0.parent == nil })
// let final: Round? = .first // let final: Round? = .first
return rounds.first?.playedMatches().first?.winner() return finals?.playedMatches().first?.winner()
} }
func getGroupStageChunkValue() -> Int { func getGroupStageChunkValue() -> Int {
@ -1796,7 +1816,7 @@ class Tournament : ModelObject, Storable {
func insertOnServer() throws { func insertOnServer() throws {
try DataStore.shared.tournaments.writeChangeAndInsertOnServer(instance: self) DataStore.shared.tournaments.writeChangeAndInsertOnServer(instance: self)
for teamRegistration in self.unsortedTeams() { for teamRegistration in self.unsortedTeams() {
try teamRegistration.insertOnServer() try teamRegistration.insertOnServer()

@ -0,0 +1,56 @@
//
// TournamentStore.swift
// PadelClub
//
// Created by Laurent Morvillier on 26/06/2024.
//
import Foundation
import LeStorage
import SwiftUI
class TournamentStore: Store, ObservableObject {
static func instance(tournamentId: String) -> TournamentStore {
return StoreCenter.main.store(identifier: tournamentId, parameter: "tournament")
}
fileprivate(set) var groupStages: StoredCollection<GroupStage> = StoredCollection.placeholder()
fileprivate(set) var matches: StoredCollection<Match> = StoredCollection.placeholder()
fileprivate(set) var teamRegistrations: StoredCollection<TeamRegistration> = StoredCollection.placeholder()
fileprivate(set) var playerRegistrations: StoredCollection<PlayerRegistration> = StoredCollection.placeholder()
fileprivate(set) var rounds: StoredCollection<Round> = StoredCollection.placeholder()
fileprivate(set) var teamScores: StoredCollection<TeamScore> = StoredCollection.placeholder()
fileprivate(set) var matchSchedulers: StoredCollection<MatchScheduler> = StoredCollection.placeholder()
// fileprivate(set) var loading: Bool = true
convenience init(tournament: Tournament) {
self.init(identifier: tournament.id, parameter: "tournament")
}
required init(identifier: String, parameter: String) {
super.init(identifier: identifier, parameter: parameter)
var synchronized: Bool = true
let indexed: Bool = true
#if DEBUG
if let sync = PListReader.readBool(plist: "local", key: "synchronized") {
synchronized = sync
}
#endif
self.groupStages = self.registerCollection(synchronized: synchronized, indexed: indexed)
self.teamRegistrations = self.registerCollection(synchronized: synchronized, indexed: indexed)
self.playerRegistrations = self.registerCollection(synchronized: synchronized, indexed: indexed)
self.rounds = self.registerCollection(synchronized: synchronized, indexed: indexed)
self.matches = self.registerCollection(synchronized: synchronized, indexed: indexed)
self.teamScores = self.registerCollection(synchronized: synchronized, indexed: indexed)
self.matchSchedulers = self.registerCollection(synchronized: false, indexed: indexed)
}
}

@ -19,6 +19,7 @@ class User: ModelObject, UserBase, Storable {
static func resourceName() -> String { "users" } static func resourceName() -> String { "users" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [.post] } static func tokenExemptedMethods() -> [HTTPMethod] { return [.post] }
static func filterByStoreIdentifier() -> Bool { return false }
// func deleteDependencies() throws { } // func deleteDependencies() throws { }

@ -40,16 +40,16 @@ class Patcher {
} }
fileprivate static func _patchAlexisLeDu() { fileprivate static func _patchAlexisLeDu() {
guard Store.main.userId == "94f45ed2-8938-4c32-a4b6-e4525073dd33" else { return } guard StoreCenter.main.userId == "94f45ed2-8938-4c32-a4b6-e4525073dd33" else { return }
Logger.log(">>> Start patch...") Logger.log(">>> Start patch...")
let clubs = DataStore.shared.clubs let clubs = DataStore.shared.clubs
StoreCenter.main.resetApiCalls(collection: clubs)
clubs.resetApiCalls() // clubs.resetApiCalls()
for club in clubs.filter({ $0.creator == "d5060b89-e979-4c19-bf78-e459a6ed5318"}) { for club in clubs.filter({ $0.creator == "d5060b89-e979-4c19-bf78-e459a6ed5318"}) {
club.creator = Store.main.userId club.creator = StoreCenter.main.userId
clubs.writeChangeAndInsertOnServer(instance: club) clubs.writeChangeAndInsertOnServer(instance: club)
} }
@ -57,25 +57,28 @@ class Patcher {
fileprivate static func _importDataFromDev() { fileprivate static func _importDataFromDev() {
guard let userId = Store.main.userId else { guard let userId = StoreCenter.main.userId else {
return return
} }
return // TODO review
let services = Services(url: "https://xlr.alwaysdata.net/roads/") let services = Services(url: "https://xlr.alwaysdata.net/roads/")
if services.hasToken() { if services.hasToken() {
Task { Task {
let clubs: [Club] = try await services.get()
let events: [Event] = try await services.get() let clubs: [Club] = try await Store.main.getItems()
let tournaments: [Tournament] = try await services.get() let events: [Event] = try await Store.main.getItems()
let rounds: [Round] = try await services.get() let tournaments: [Tournament] = try await Store.main.getItems()
let groupStages: [GroupStage] = try await services.get() // let rounds: [Round] = try await services.get()
let matches: [Match] = try await services.get() // let groupStages: [GroupStage] = try await services.get()
let teamRegistrations: [TeamRegistration] = try await services.get() // let matches: [Match] = try await services.get()
let teamScores: [TeamScore] = try await services.get() // let teamRegistrations: [TeamRegistration] = try await services.get()
let playerRegistrations: [PlayerRegistration] = try await services.get() // let teamScores: [TeamScore] = try await services.get()
let courts: [Court] = try await services.get() // let playerRegistrations: [PlayerRegistration] = try await services.get()
let dateIntervals: [DateInterval] = try await services.get() let courts: [Court] = try await Store.main.getItems()
let dateIntervals: [DateInterval] = try await Store.main.getItems()
// for club in clubs { // for club in clubs {
// club.creator = userId // club.creator = userId
@ -93,14 +96,19 @@ class Patcher {
// try DataStore.shared.clubs.addOrUpdate(contentOfs: clubs) // try DataStore.shared.clubs.addOrUpdate(contentOfs: clubs)
try DataStore.shared.events.addOrUpdate(contentOfs: events) try DataStore.shared.events.addOrUpdate(contentOfs: events)
try DataStore.shared.tournaments.addOrUpdate(contentOfs: tournaments) try DataStore.shared.tournaments.addOrUpdate(contentOfs: tournaments)
try DataStore.shared.rounds.addOrUpdate(contentOfs: rounds)
try DataStore.shared.groupStages.addOrUpdate(contentOfs: groupStages)
try DataStore.shared.matches.addOrUpdate(contentOfs: matches)
try DataStore.shared.teamRegistrations.addOrUpdate(contentOfs: teamRegistrations)
try DataStore.shared.teamScores.addOrUpdate(contentOfs: teamScores)
try DataStore.shared.playerRegistrations.addOrUpdate(contentOfs: playerRegistrations)
try DataStore.shared.courts.addOrUpdate(contentOfs: courts) try DataStore.shared.courts.addOrUpdate(contentOfs: courts)
try DataStore.shared.dateIntervals.addOrUpdate(contentOfs: dateIntervals) try DataStore.shared.dateIntervals.addOrUpdate(contentOfs: dateIntervals)
// for tournament in DataStore.shared.tournaments {
// let store = tournament.tournamentStore
// try store.rounds.addOrUpdate(contentOfs: rounds)
// try store.groupStages.addOrUpdate(contentOfs: groupStages)
// try store.matches.addOrUpdate(contentOfs: matches)
// try store.teamRegistrations.addOrUpdate(contentOfs: teamRegistrations)
// try store.teamScores.addOrUpdate(contentOfs: teamScores)
// try store.playerRegistrations.addOrUpdate(contentOfs: playerRegistrations)
// }
} }
} }

@ -206,7 +206,7 @@ struct CallMessageCustomizationView: View {
@ViewBuilder @ViewBuilder
private func _clubNameView() -> some View { private func _clubNameView() -> some View {
if let eventClub = tournament.eventObject()?.clubObject() { if let eventClub = tournament.eventObject()?.clubObject() {
let hasBeenCreated: Bool = eventClub.hasBeenCreated(by: Store.main.userId) let hasBeenCreated: Bool = eventClub.hasBeenCreated(by: StoreCenter.main.userId)
Section { Section {
TextField("Nom du club", text: $customClubName, axis: .vertical) TextField("Nom du club", text: $customClubName, axis: .vertical)
.lineLimit(2) .lineLimit(2)

@ -10,10 +10,15 @@ import LeStorage
struct CallSettingsView: View { struct CallSettingsView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) var tournament: Tournament @Environment(Tournament.self) var tournament: Tournament
@State private var showSendToAllView: Bool = false @State private var showSendToAllView: Bool = false
@State private var addLink: Bool = false @State private var addLink: Bool = false
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var body: some View { var body: some View {
List { List {
@ -59,7 +64,7 @@ struct CallSettingsView: View {
team.callDate = nil team.callDate = nil
} }
do { do {
try dataStore.teamRegistrations.addOrUpdate(contentOfs: teams) try tournamentStore.teamRegistrations.addOrUpdate(contentOfs: teams)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -73,7 +78,7 @@ struct CallSettingsView: View {
team.callDate = team.expectedSummonDate() team.callDate = team.expectedSummonDate()
} }
do { do {
try dataStore.teamRegistrations.addOrUpdate(contentOfs: teams) try tournamentStore.teamRegistrations.addOrUpdate(contentOfs: teams)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -49,6 +49,7 @@ struct CallView: View {
} }
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@EnvironmentObject var networkMonitor: NetworkMonitor @EnvironmentObject var networkMonitor: NetworkMonitor
@Environment(Tournament.self) var tournament: Tournament @Environment(Tournament.self) var tournament: Tournament
@ -66,6 +67,10 @@ struct CallView: View {
@State var summonParamByMessage: Bool = false @State var summonParamByMessage: Bool = false
@State var summonParamReSummon: Bool = false @State var summonParamReSummon: Bool = false
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var messageSentFailed: Binding<Bool> { var messageSentFailed: Binding<Bool> {
Binding { Binding {
sentError != nil sentError != nil
@ -82,7 +87,7 @@ struct CallView: View {
team.callDate = callDate team.callDate = callDate
} }
do { do {
try dataStore.teamRegistrations.addOrUpdate(contentOfs: teams) try self.tournamentStore.teamRegistrations.addOrUpdate(contentOfs: teams)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -229,7 +234,7 @@ struct CallView: View {
} }
fileprivate func _verifyUser(_ handler: () -> ()) { fileprivate func _verifyUser(_ handler: () -> ()) {
if Store.main.userId != nil { if StoreCenter.main.userId != nil {
handler() handler()
} else { } else {
self.showUserCreationView = true self.showUserCreationView = true

@ -142,7 +142,7 @@ struct MenuWarningView: View {
} }
fileprivate func _verifyUser(_ handler: () -> ()) { fileprivate func _verifyUser(_ handler: () -> ()) {
if Store.main.userId != nil { if StoreCenter.main.userId != nil {
handler() handler()
} else { } else {
self.showUserCreationView = true self.showUserCreationView = true

@ -9,8 +9,10 @@ import SwiftUI
import LeStorage import LeStorage
struct SendToAllView: View { struct SendToAllView: View {
@Environment(\.dismiss) var dismiss @Environment(\.dismiss) var dismiss
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) var tournament: Tournament @Environment(Tournament.self) var tournament: Tournament
@EnvironmentObject var networkMonitor: NetworkMonitor @EnvironmentObject var networkMonitor: NetworkMonitor
@ -28,6 +30,10 @@ struct SendToAllView: View {
@State var summonParamByMessage: Bool = false @State var summonParamByMessage: Bool = false
@State var summonParamReSummon: Bool = false @State var summonParamReSummon: Bool = false
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var messageSentFailed: Binding<Bool> { var messageSentFailed: Binding<Bool> {
Binding { Binding {
sentError != nil sentError != nil
@ -181,13 +187,13 @@ struct SendToAllView: View {
} }
func _roundTeams() -> [TeamRegistration] { func _roundTeams() -> [TeamRegistration] {
let rounds : [Round] = contactRecipients.compactMap { Store.main.findById($0) } let rounds: [Round] = contactRecipients.compactMap { self.tournamentStore.rounds.findById($0) }
return rounds.flatMap({ $0.teams() }) return rounds.flatMap { $0.teams() }
} }
func _groupStagesTeams() -> [TeamRegistration] { func _groupStagesTeams() -> [TeamRegistration] {
let groupStages : [GroupStage] = contactRecipients.compactMap { Store.main.findById($0) } let groupStages : [GroupStage] = contactRecipients.compactMap { self.tournamentStore.groupStages.findById($0) }
return groupStages.flatMap({ $0.teams() }) return groupStages.flatMap { $0.teams() }
} }
func _totalString() -> String { func _totalString() -> String {
@ -229,7 +235,7 @@ struct SendToAllView: View {
} }
fileprivate func _verifyUser(_ handler: () -> ()) { fileprivate func _verifyUser(_ handler: () -> ()) {
if Store.main.userId != nil { if StoreCenter.main.userId != nil {
handler() handler()
} else { } else {
self.showUserCreationView = true self.showUserCreationView = true

@ -9,7 +9,9 @@ import SwiftUI
import LeStorage import LeStorage
struct CashierSettingsView: View { struct CashierSettingsView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
var tournaments: [Tournament] var tournaments: [Tournament]
init(tournaments: [Tournament]) { init(tournaments: [Tournament]) {
@ -24,17 +26,21 @@ struct CashierSettingsView: View {
List { List {
Section { Section {
RowButtonView("Tout le monde a réglé", role: .destructive) { RowButtonView("Tout le monde a réglé", role: .destructive) {
let players = tournaments.flatMap({ $0.selectedPlayers() })
players.forEach { player in for tournament in self.tournaments {
if player.hasPaid() == false { let players = tournament.selectedPlayers() // tournaments.flatMap({ $0.selectedPlayers() })
player.paymentType = .gift players.forEach { player in
if player.hasPaid() == false {
player.paymentType = .gift
}
}
do {
try tournament.tournamentStore.playerRegistrations.addOrUpdate(contentOfs: players)
} catch {
Logger.error(error)
} }
} }
do {
try dataStore.playerRegistrations.addOrUpdate(contentOfs: players)
} catch {
Logger.error(error)
}
} }
} footer: { } footer: {
Text("Passe tous les joueurs qui n'ont pas réglé en offert") Text("Passe tous les joueurs qui n'ont pas réglé en offert")
@ -42,14 +48,18 @@ struct CashierSettingsView: View {
Section { Section {
RowButtonView("Personne n'a réglé", role: .destructive) { RowButtonView("Personne n'a réglé", role: .destructive) {
let players = tournaments.flatMap({ $0.selectedPlayers() }) for tournament in self.tournaments {
players.forEach { player in let store = tournament.tournamentStore
player.paymentType = nil
} let players = tournament.selectedPlayers()
do { players.forEach { player in
try dataStore.playerRegistrations.addOrUpdate(contentOfs: players) player.paymentType = nil
} catch { }
Logger.error(error) do {
try store.playerRegistrations.addOrUpdate(contentOfs: players)
} catch {
Logger.error(error)
}
} }
} }
} footer: { } footer: {

@ -129,7 +129,7 @@ struct EventCreationView: View {
} }
private func _validate() { private func _validate() {
let event = Event(creator: Store.main.userId, name: eventName) let event = Event(creator: StoreCenter.main.userId, name: eventName)
do { do {
try dataStore.events.addOrUpdate(instance: event) try dataStore.events.addOrUpdate(instance: event)

@ -303,7 +303,7 @@ struct ClubSearchView: View {
} }
private func _importClub(clubToEdit: Club, clubMarker: ClubMarker) { private func _importClub(clubToEdit: Club, clubMarker: ClubMarker) {
if clubToEdit.hasBeenCreated(by: Store.main.userId) { if clubToEdit.hasBeenCreated(by: StoreCenter.main.userId) {
if clubToEdit.name.isEmpty { if clubToEdit.name.isEmpty {
clubToEdit.name = clubMarker.nom.capitalized clubToEdit.name = clubMarker.nom.capitalized
clubToEdit.acronym = clubToEdit.automaticShortName().capitalized clubToEdit.acronym = clubToEdit.automaticShortName().capitalized
@ -314,7 +314,7 @@ struct ClubSearchView: View {
clubToEdit.city = clubMarker.ville clubToEdit.city = clubMarker.ville
} }
if displayContext == .addition && clubToEdit.hasBeenCreated(by: Store.main.userId) { if displayContext == .addition && clubToEdit.hasBeenCreated(by: StoreCenter.main.userId) {
do { do {
try dataStore.clubs.addOrUpdate(instance: clubToEdit) try dataStore.clubs.addOrUpdate(instance: clubToEdit)
} catch { } catch {

@ -62,7 +62,7 @@ struct ClubsView: View {
.buttonStyle(.plain) .buttonStyle(.plain)
} else { } else {
NavigationLink { NavigationLink {
ClubDetailView(club: club, displayContext: club.hasBeenCreated(by: Store.main.userId) ? .edition : .lockedForEditing) ClubDetailView(club: club, displayContext: club.hasBeenCreated(by: StoreCenter.main.userId) ? .edition : .lockedForEditing)
} label: { } label: {
ClubRowView(club: club) ClubRowView(club: club)
} }
@ -88,7 +88,7 @@ struct ClubsView: View {
.buttonStyle(.plain) .buttonStyle(.plain)
} else { } else {
NavigationLink { NavigationLink {
ClubDetailView(club: club, displayContext: club.hasBeenCreated(by: Store.main.userId) ? .edition : .lockedForEditing) ClubDetailView(club: club, displayContext: club.hasBeenCreated(by: StoreCenter.main.userId) ? .edition : .lockedForEditing)
} label: { } label: {
ClubRowView(club: club) ClubRowView(club: club)
} }

@ -52,7 +52,7 @@ struct CreateClubView: View {
let newClub = Club.findOrCreate(name: club.name, code: club.code, city: club.city, zipCode: club.zipCode) let newClub = Club.findOrCreate(name: club.name, code: club.code, city: club.city, zipCode: club.zipCode)
//update existing club if rights ok / freshly created club with data input from user //update existing club if rights ok / freshly created club with data input from user
if newClub.hasBeenCreated(by: Store.main.userId) { if newClub.hasBeenCreated(by: StoreCenter.main.userId) {
newClub.update(fromClub: club) newClub.update(fromClub: club)
do { do {
try dataStore.clubs.addOrUpdate(instance: newClub) try dataStore.clubs.addOrUpdate(instance: newClub)

@ -8,7 +8,10 @@
import SwiftUI import SwiftUI
struct MatchListView: View { struct MatchListView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) var tournament
let section: String let section: String
let matches: [Match]? let matches: [Match]?
var matchViewStyle: MatchViewStyle = .standardStyle var matchViewStyle: MatchViewStyle = .standardStyle
@ -31,7 +34,7 @@ struct MatchListView: View {
DisclosureGroup(isExpanded: $isExpanded) { DisclosureGroup(isExpanded: $isExpanded) {
if let matches { if let matches {
ForEach(matches) { match in ForEach(matches) { match in
MatchRowView(match: match, matchViewStyle: matchViewStyle) MatchRowView(match: match, tournament: self.tournament, matchViewStyle: matchViewStyle)
.listRowInsets(EdgeInsets(top: 0, leading: -2, bottom: 0, trailing: 8)) .listRowInsets(EdgeInsets(top: 0, leading: -2, bottom: 0, trailing: 8))
} }
} }

@ -9,11 +9,18 @@ import SwiftUI
import LeStorage import LeStorage
struct GroupStageTeamView: View { struct GroupStageTeamView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) var tournament: Tournament
@Environment(\.dismiss) private var dismiss @Environment(\.dismiss) private var dismiss
let groupStage: GroupStage let groupStage: GroupStage
var team: TeamRegistration var team: TeamRegistration
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var body: some View { var body: some View {
List { List {
Section { Section {
@ -85,7 +92,7 @@ struct GroupStageTeamView: View {
private func _save() { private func _save() {
do { do {
try dataStore.teamRegistrations.addOrUpdate(instance: team) try tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -10,9 +10,14 @@ import LeStorage
struct GroupStageSettingsView: View { struct GroupStageSettingsView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) var tournament: Tournament @Environment(Tournament.self) var tournament: Tournament
@State private var generationDone: Bool = false @State private var generationDone: Bool = false
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var body: some View { var body: some View {
List { List {
@ -68,7 +73,7 @@ struct GroupStageSettingsView: View {
} }
} }
do { do {
try dataStore.groupStages.addOrUpdate(contentOfs: groupStages) try self.tournament.tournamentStore.groupStages.addOrUpdate(contentOfs: groupStages)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -82,7 +87,7 @@ struct GroupStageSettingsView: View {
groupStage.name = nil groupStage.name = nil
} }
do { do {
try dataStore.groupStages.addOrUpdate(contentOfs: groupStages) try self.tournament.tournamentStore.groupStages.addOrUpdate(contentOfs: groupStages)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -9,7 +9,9 @@ import SwiftUI
import LeStorage import LeStorage
struct GroupStageView: View { struct GroupStageView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) private var tournament @Environment(Tournament.self) private var tournament
@Bindable var groupStage: GroupStage @Bindable var groupStage: GroupStage
@State private var confirmGroupStageStart: Bool = false @State private var confirmGroupStageStart: Bool = false
@ -27,6 +29,10 @@ struct GroupStageView: View {
self.playedMatches = groupStage.playedMatches() self.playedMatches = groupStage.playedMatches()
} }
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var body: some View { var body: some View {
List { List {
Section { Section {
@ -92,12 +98,19 @@ struct GroupStageView: View {
} }
struct GroupStageScoreView: View { struct GroupStageScoreView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) private var tournament
let groupStage: GroupStage let groupStage: GroupStage
let sortByScore: Bool let sortByScore: Bool
let scores: [GroupStage.TeamGroupStageScore]? let scores: [GroupStage.TeamGroupStageScore]?
let teams: [TeamRegistration] let teams: [TeamRegistration]
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
init(groupStage: GroupStage, sortByScore: Bool) { init(groupStage: GroupStage, sortByScore: Bool) {
self.groupStage = groupStage self.groupStage = groupStage
self.sortByScore = sortByScore self.sortByScore = sortByScore
@ -114,6 +127,7 @@ struct GroupStageView: View {
if let team = _teamAt(atIndex: index), let groupStagePosition = team.groupStagePosition { if let team = _teamAt(atIndex: index), let groupStagePosition = team.groupStagePosition {
NavigationLink { NavigationLink {
GroupStageTeamView(groupStage: groupStage, team: team) GroupStageTeamView(groupStage: groupStage, team: team)
.environment(self.tournament)
} label: { } label: {
VStack(alignment: .leading, spacing: 4.0) { VStack(alignment: .leading, spacing: 4.0) {
HStack(spacing: 6.0) { HStack(spacing: 6.0) {
@ -177,7 +191,7 @@ struct GroupStageView: View {
team.groupStagePosition = index team.groupStagePosition = index
groupStage._matches().forEach({ $0.updateTeamScores() }) groupStage._matches().forEach({ $0.updateTeamScores() })
do { do {
try dataStore.teamRegistrations.addOrUpdate(instance: team) try tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -214,7 +228,7 @@ struct GroupStageView: View {
groupStage._matches().forEach({ $0.updateTeamScores() }) groupStage._matches().forEach({ $0.updateTeamScores() })
} }
do { do {
try dataStore.teamRegistrations.addOrUpdate(contentOfs: teams) try tournamentStore.teamRegistrations.addOrUpdate(contentOfs: teams)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -230,7 +244,7 @@ struct GroupStageView: View {
private func _save() { private func _save() {
do { do {
try dataStore.groupStages.addOrUpdate(instance: groupStage) try tournamentStore.groupStages.addOrUpdate(instance: groupStage)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -238,9 +252,12 @@ struct GroupStageView: View {
} }
struct GroupStageNameEditionView: View { struct GroupStageNameEditionView: View {
@Environment(\.dismiss) private var dismiss @Environment(\.dismiss) private var dismiss
@Environment(Tournament.self) private var tournament @Environment(Tournament.self) private var tournament
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Bindable var groupStage: GroupStage @Bindable var groupStage: GroupStage
@State private var groupStageName: String @State private var groupStageName: String
@State private var presentConfirmationButton: Bool = false @State private var presentConfirmationButton: Bool = false
@ -252,6 +269,10 @@ struct GroupStageNameEditionView: View {
_size = .init(wrappedValue: groupStage.size) _size = .init(wrappedValue: groupStage.size)
} }
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var body: some View { var body: some View {
Form { Form {
Section { Section {
@ -295,7 +316,7 @@ struct GroupStageNameEditionView: View {
groupStage._matches().forEach({ $0.updateTeamScores() }) groupStage._matches().forEach({ $0.updateTeamScores() })
} }
do { do {
try dataStore.teamRegistrations.addOrUpdate(contentOfs: teams) try tournamentStore.teamRegistrations.addOrUpdate(contentOfs: teams)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -344,7 +365,7 @@ struct GroupStageNameEditionView: View {
private func _save() { private func _save() {
do { do {
try dataStore.groupStages.addOrUpdate(instance: groupStage) try tournamentStore.groupStages.addOrUpdate(instance: groupStage)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -9,13 +9,20 @@ import SwiftUI
import LeStorage import LeStorage
struct MatchDateView: View { struct MatchDateView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) var tournament: Tournament
var match: Match var match: Match
var showPrefix: Bool = false var showPrefix: Bool = false
private var isReady: Bool private var isReady: Bool
private var hasWalkoutTeam: Bool private var hasWalkoutTeam: Bool
private var hasEnded: Bool private var hasEnded: Bool
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
init(match: Match, showPrefix: Bool) { init(match: Match, showPrefix: Bool) {
self.match = match self.match = match
self.showPrefix = showPrefix self.showPrefix = showPrefix
@ -143,7 +150,7 @@ struct MatchDateView: View {
private func _save() { private func _save() {
do { do {
try dataStore.matches.addOrUpdate(instance: match) try self.tournamentStore.matches.addOrUpdate(instance: match)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -9,7 +9,10 @@ import SwiftUI
import LeStorage import LeStorage
struct MatchDetailView: View { struct MatchDetailView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) var tournament: Tournament
@EnvironmentObject var networkMonitor: NetworkMonitor @EnvironmentObject var networkMonitor: NetworkMonitor
@Environment(\.dismiss) var dismiss @Environment(\.dismiss) var dismiss
let matchViewStyle: MatchViewStyle let matchViewStyle: MatchViewStyle
@ -32,6 +35,10 @@ struct MatchDetailView: View {
@State var showSubscriptionView: Bool = false @State var showSubscriptionView: Bool = false
@State var showUserCreationView: Bool = false @State var showUserCreationView: Bool = false
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var messageSentFailed: Binding<Bool> { var messageSentFailed: Binding<Bool> {
Binding { Binding {
sentError != nil sentError != nil
@ -442,7 +449,7 @@ struct MatchDetailView: View {
} }
fileprivate func _verifyUser(_ handler: () -> ()) { fileprivate func _verifyUser(_ handler: () -> ()) {
if Store.main.userId != nil { if StoreCenter.main.userId != nil {
handler() handler()
} else { } else {
self.showUserCreationView = true self.showUserCreationView = true
@ -462,7 +469,7 @@ struct MatchDetailView: View {
private func save() { private func save() {
do { do {
try dataStore.matches.addOrUpdate(instance: match) try self.tournamentStore.matches.addOrUpdate(instance: match)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -8,8 +8,11 @@
import SwiftUI import SwiftUI
struct MatchRowView: View { struct MatchRowView: View {
var match: Match var match: Match
var tournament: Tournament
let matchViewStyle: MatchViewStyle let matchViewStyle: MatchViewStyle
@Environment(\.isEditingTournamentSeed) private var isEditingTournamentSeed @Environment(\.isEditingTournamentSeed) private var isEditingTournamentSeed
@ViewBuilder @ViewBuilder
@ -55,6 +58,7 @@ struct MatchRowView: View {
NavigationLink { NavigationLink {
MatchDetailView(match: match, matchViewStyle: matchViewStyle) MatchDetailView(match: match, matchViewStyle: matchViewStyle)
.environment(self.tournament)
} label: { } label: {
MatchSummaryView(match: match, matchViewStyle: matchViewStyle) MatchSummaryView(match: match, matchViewStyle: matchViewStyle)
} }

@ -9,10 +9,17 @@ import SwiftUI
import LeStorage import LeStorage
struct MatchSetupView: View { struct MatchSetupView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) var tournament: Tournament
var match: Match var match: Match
@State private var seedGroup: SeedInterval? @State private var seedGroup: SeedInterval?
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
@ViewBuilder @ViewBuilder
var body: some View { var body: some View {
ForEach(TeamPosition.allCases) { teamPosition in ForEach(TeamPosition.allCases) { teamPosition in
@ -41,19 +48,19 @@ struct MatchSetupView: View {
match.updateTeamScores() match.updateTeamScores()
match.enableMatch() match.enableMatch()
do { do {
try dataStore.matches.addOrUpdate(instance: match) try tournamentStore.matches.addOrUpdate(instance: match)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
do { do {
try dataStore.teamRegistrations.addOrUpdate(instance: team) try tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
} else { } else {
match.teamWillBeWalkOut(team) match.teamWillBeWalkOut(team)
do { do {
try dataStore.matches.addOrUpdate(instance: match) try tournamentStore.matches.addOrUpdate(instance: match)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -76,19 +83,19 @@ struct MatchSetupView: View {
if walkOutSpot { if walkOutSpot {
match.setLuckyLoser(team: team, teamPosition: teamPosition) match.setLuckyLoser(team: team, teamPosition: teamPosition)
do { do {
try dataStore.matches.addOrUpdate(instance: match) try tournamentStore.matches.addOrUpdate(instance: match)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
} else { } else {
team.setSeedPosition(inSpot: match, slot: teamPosition, opposingSeeding: false) team.setSeedPosition(inSpot: match, slot: teamPosition, opposingSeeding: false)
do { do {
try dataStore.matches.addOrUpdate(instance: match) try tournamentStore.matches.addOrUpdate(instance: match)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
do { do {
try dataStore.teamRegistrations.addOrUpdate(instance: team) try tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -103,7 +110,7 @@ struct MatchSetupView: View {
if let randomTeam = luckyLosers.randomElement() { if let randomTeam = luckyLosers.randomElement() {
match.setLuckyLoser(team: randomTeam, teamPosition: teamPosition) match.setLuckyLoser(team: randomTeam, teamPosition: teamPosition)
do { do {
try dataStore.matches.addOrUpdate(instance: match) try tournamentStore.matches.addOrUpdate(instance: match)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -117,12 +124,12 @@ struct MatchSetupView: View {
if let randomTeam = tournament.randomSeed(fromSeedGroup: seedGroup) { if let randomTeam = tournament.randomSeed(fromSeedGroup: seedGroup) {
randomTeam.setSeedPosition(inSpot: match, slot: teamPosition, opposingSeeding: false) randomTeam.setSeedPosition(inSpot: match, slot: teamPosition, opposingSeeding: false)
do { do {
try dataStore.matches.addOrUpdate(instance: match) try tournamentStore.matches.addOrUpdate(instance: match)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
do { do {
try dataStore.teamRegistrations.addOrUpdate(instance: randomTeam) try tournamentStore.teamRegistrations.addOrUpdate(instance: randomTeam)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -141,7 +148,7 @@ struct MatchSetupView: View {
Button { Button {
match.unlockSeedPosition(atTeamPosition: teamPosition) match.unlockSeedPosition(atTeamPosition: teamPosition)
do { do {
try dataStore.matches.addOrUpdate(instance: match) try tournamentStore.matches.addOrUpdate(instance: match)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -153,7 +160,7 @@ struct MatchSetupView: View {
Button { Button {
_ = match.lockAndGetSeedPosition(atTeamPosition: teamPosition) _ = match.lockAndGetSeedPosition(atTeamPosition: teamPosition)
do { do {
try dataStore.matches.addOrUpdate(instance: match) try tournamentStore.matches.addOrUpdate(instance: match)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -10,6 +10,7 @@ import LeStorage
struct MainView: View { struct MainView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@AppStorage("importingFiles") var importingFiles: Bool = false @AppStorage("importingFiles") var importingFiles: Bool = false
@Environment(NavigationViewModel.self) private var navigation: NavigationViewModel @Environment(NavigationViewModel.self) private var navigation: NavigationViewModel
@ -45,13 +46,8 @@ struct MainView: View {
} }
)} )}
var matches: [Match] {
return dataStore.matches.filter { match in
match.confirmed && match.startDate != nil && match.endDate == nil && match.courtIndex != nil }
}
private func _isConnected() -> Bool { private func _isConnected() -> Bool {
return Store.main.hasToken() && Store.main.userId != nil return StoreCenter.main.hasToken() && StoreCenter.main.userId != nil
} }
var badgeText: Text? { var badgeText: Text? {
@ -73,7 +69,7 @@ struct MainView: View {
.tabItem(for: .tournamentOrganizer) .tabItem(for: .tournamentOrganizer)
OngoingView() OngoingView()
.tabItem(for: .ongoing) .tabItem(for: .ongoing)
.badge(matches.count) .badge(self.dataStore.runningMatches().count)
ToolboxView() ToolboxView()
.tabItem(for: .toolbox) .tabItem(for: .toolbox)
UmpireView() UmpireView()
@ -84,7 +80,7 @@ struct MainView: View {
} }
.id(mainViewId) .id(mainViewId)
.onChange(of: dataStore.user.id) { .onChange(of: dataStore.user.id) {
if Store.main.userId == nil { // user disconnected if StoreCenter.main.userId == nil { // user disconnected
navigation.path.removeLast(navigation.path.count) navigation.path.removeLast(navigation.path.count)
mainViewId = UUID() mainViewId = UUID()
} }
@ -92,7 +88,7 @@ struct MainView: View {
.environmentObject(dataStore) .environmentObject(dataStore)
.task { .task {
await self._checkSourceFileAvailability() await self._checkSourceFileAvailability()
if Store.main.hasToken() { if StoreCenter.main.hasToken() {
do { do {
try await dataStore.clubs.loadDataFromServerIfAllowed() try await dataStore.clubs.loadDataFromServerIfAllowed()
} catch { } catch {

@ -9,15 +9,18 @@ import SwiftUI
import LeStorage import LeStorage
struct OngoingView: View { struct OngoingView: View {
@Environment(NavigationViewModel.self) private var navigation: NavigationViewModel @Environment(NavigationViewModel.self) private var navigation: NavigationViewModel
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@State private var sortByField: Bool = false @State private var sortByField: Bool = false
let fieldSorting : [MySortDescriptor<Match>] = [.keyPath(\Match.courtIndex!), .keyPath(\Match.startDate!)] let fieldSorting : [MySortDescriptor<Match>] = [.keyPath(\Match.courtIndex!), .keyPath(\Match.startDate!)]
let defaultSorting : [MySortDescriptor<Match>] = [.keyPath(\Match.startDate!), .keyPath(\Match.courtIndex!)] let defaultSorting : [MySortDescriptor<Match>] = [.keyPath(\Match.startDate!), .keyPath(\Match.courtIndex!)]
var matches: [Match] { var matches: [Match] {
let sorting = sortByField ? fieldSorting : defaultSorting let sorting = self.sortByField ? fieldSorting : defaultSorting
return dataStore.matches.filter({ $0.confirmed && $0.startDate != nil && $0.endDate == nil && $0.courtIndex != nil }).sorted(using: sorting, order: .ascending) return self.dataStore.runningMatches().sorted(using: sorting, order: .ascending)
} }
var body: some View { var body: some View {
@ -26,10 +29,12 @@ struct OngoingView: View {
let matches = matches.filter { $0.currentTournament()?.isDeleted == false } let matches = matches.filter { $0.currentTournament()?.isDeleted == false }
List { List {
ForEach(matches) { match in ForEach(matches) { match in
Section {
MatchRowView(match: match, matchViewStyle: .standardStyle) if let tournament = match.currentTournament() {
} header: {
if let tournament = match.currentTournament() { Section {
MatchRowView(match: match, tournament: tournament, matchViewStyle: .standardStyle)
} header: {
HStack { HStack {
Text(tournament.tournamentTitle(.short)) Text(tournament.tournamentTitle(.short))
Spacer() Spacer()
@ -37,23 +42,21 @@ struct OngoingView: View {
Text("@" + club.clubTitle(.short)) Text("@" + club.clubTitle(.short))
} }
} }
} else { } footer: {
Text("Pas de tournoi") HStack {
}
} footer: {
HStack {
if let tournament = match.currentTournament() {
Text(tournament.eventLabel()) Text(tournament.eventLabel())
}
#if DEBUG #if DEBUG
Spacer() Spacer()
FooterButtonView("copier l'id") { FooterButtonView("copier l'id") {
let pasteboard = UIPasteboard.general let pasteboard = UIPasteboard.general
pasteboard.string = match.id pasteboard.string = match.id
} }
#endif #endif
}
} }
} }
} }
} }
.headerProminence(.increased) .headerProminence(.increased)
@ -74,13 +77,13 @@ struct OngoingView: View {
} }
#if DEBUG #if DEBUG
Button("effacer les mauvais matchs") { Button("effacer les mauvais matchs (TODO)") {
let bad = matches.filter({ $0.currentTournament() == nil }) // let bad = matches.filter({ $0.currentTournament() == nil })
do { // do {
try dataStore.matches.delete(contentOfs: bad) // try self.tournamentStore.matches.delete(contentOfs: bad)
} catch { // } catch {
Logger.error(error) // Logger.error(error)
} // }
} }
#endif #endif
//todo //todo

@ -44,7 +44,7 @@ struct TournamentOrganizerView: View {
} }
} }
} }
.onChange(of: Store.main.userId) { .onChange(of: StoreCenter.main.userId) {
navigation.organizerTournament = nil navigation.organizerTournament = nil
} }
} }

@ -43,7 +43,7 @@ struct APICallsView: View {
@MainActor @MainActor
fileprivate func _load() { fileprivate func _load() {
Task { Task {
self.text = await Store.main.apiCallsFileContent(resourceName: self.name) self.text = await StoreCenter.main.apiCallsFileContent(resourceName: self.name)
} }
} }

@ -21,15 +21,15 @@ struct DebugSettingsView: View {
} }
fileprivate var _userId: String { fileprivate var _userId: String {
return Store.main.userId ?? "" return StoreCenter.main.userId ?? ""
} }
fileprivate var _userName: String { fileprivate var _userName: String {
return Store.main.userName() ?? "" return StoreCenter.main.userName() ?? ""
} }
fileprivate var _token: String { fileprivate var _token: String {
return Store.main.token() ?? "" return StoreCenter.main.token() ?? ""
} }
fileprivate var _server: String { fileprivate var _server: String {
@ -45,7 +45,7 @@ struct DebugSettingsView: View {
} }
fileprivate var _canSynchronize: String { fileprivate var _canSynchronize: String {
return "\(Store.main.collectionsCanSynchronize)" return "\(StoreCenter.main.collectionsCanSynchronize)"
} }
} }

@ -10,6 +10,7 @@ import LeStorage
struct ToolboxView: View { struct ToolboxView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(NavigationViewModel.self) private var navigation: NavigationViewModel @Environment(NavigationViewModel.self) private var navigation: NavigationViewModel
var body: some View { var body: some View {
@ -21,7 +22,7 @@ struct ToolboxView: View {
Text("Version de l'application").badge(PadelClubApp.appVersion) Text("Version de l'application").badge(PadelClubApp.appVersion)
SupportButtonView(contentIsUnavailable: false) SupportButtonView(contentIsUnavailable: false)
if Store.main.userId == "94f45ed2-8938-4c32-a4b6-e4525073dd33" { if StoreCenter.main.userId == "94f45ed2-8938-4c32-a4b6-e4525073dd33" {
Button { Button {
Patcher.applyPatch(.alexisLeDu) Patcher.applyPatch(.alexisLeDu)
} label: { } label: {
@ -52,45 +53,64 @@ struct ToolboxView: View {
Section { Section {
RowButtonView("Reset ALL API Calls") { RowButtonView("Reset ALL API Calls") {
Store.main.resetApiCalls() StoreCenter.main.resetApiCalls()
Logger.log("Api calls reset") Logger.log("Api calls reset")
} }
} }
Section { Section {
RowButtonView("Fix Names") { RowButtonView("Fix Names") {
let playerRegistrations = dataStore.playerRegistrations
playerRegistrations.forEach { player in
player.firstName = player.firstName.trimmed.capitalized
player.lastName = player.lastName.trimmed.uppercased()
}
do { for tournament in dataStore.tournaments {
try dataStore.playerRegistrations.addOrUpdate(contentOfs: playerRegistrations)
} catch { let store = tournament.tournamentStore
Logger.error(error) let playerRegistrations = store.playerRegistrations
playerRegistrations.forEach { player in
player.firstName = player.firstName.trimmed.capitalized
player.lastName = player.lastName.trimmed.uppercased()
}
do {
try store.playerRegistrations.addOrUpdate(contentOfs: playerRegistrations)
} catch {
Logger.error(error)
}
} }
} }
} }
Section { Section {
RowButtonView("Delete teams") { RowButtonView("Delete teams") {
let teamRegistrations = dataStore.teamRegistrations.filter({ $0.tournamentObject() == nil })
do { for tournament in DataStore.shared.tournaments {
try dataStore.teamRegistrations.delete(contentOfs: teamRegistrations)
} catch { let store: TournamentStore = tournament.tournamentStore
Logger.error(error)
let teamRegistrations = store.teamRegistrations.filter({ $0.tournamentObject() == nil })
do {
try store.teamRegistrations.delete(contentOfs: teamRegistrations)
} catch {
Logger.error(error)
}
} }
} }
} }
Section { Section {
// TODO
RowButtonView("Delete players") { RowButtonView("Delete players") {
let playersRegistrations = dataStore.playerRegistrations.filter({ $0.team() == nil })
do { for tournament in DataStore.shared.tournaments {
try dataStore.playerRegistrations.delete(contentOfs: playersRegistrations) let store: TournamentStore = tournament.tournamentStore
} catch {
Logger.error(error) let playersRegistrations = store.playerRegistrations.filter({ $0.team() == nil })
do {
try store.playerRegistrations.delete(contentOfs: playersRegistrations)
} catch {
Logger.error(error)
}
} }
} }
} }

@ -172,7 +172,7 @@ struct UmpireView: View {
.toolbar { .toolbar {
#if DEBUG #if DEBUG
ToolbarItem(placement: .topBarTrailing) { ToolbarItem(placement: .topBarTrailing) {
if Store.main.collectionsCanSynchronize { if StoreCenter.main.collectionsCanSynchronize {
Image(systemName: "checkmark.icloud") Image(systemName: "checkmark.icloud")
} else { } else {
Image(systemName: "icloud.slash") Image(systemName: "icloud.slash")
@ -193,7 +193,7 @@ struct UmpireView: View {
user.licenceId = player.license user.licenceId = player.license
if user.clubsObjects().contains(where: { $0.code == player.clubCode }) == false { if user.clubsObjects().contains(where: { $0.code == player.clubCode }) == false {
let userClub = Club.findOrCreate(name: player.clubName!, code: player.clubCode) let userClub = Club.findOrCreate(name: player.clubName!, code: player.clubCode)
if userClub.hasBeenCreated(by: Store.main.userId) { if userClub.hasBeenCreated(by: StoreCenter.main.userId) {
do { do {
try dataStore.clubs.addOrUpdate(instance: userClub) try dataStore.clubs.addOrUpdate(instance: userClub)
} catch { } catch {
@ -224,7 +224,7 @@ struct UmpireView: View {
} }
fileprivate func _isConnected() -> Bool { fileprivate func _isConnected() -> Bool {
return dataStore.user.username.count > 0 && Store.main.hasToken() return dataStore.user.username.count > 0 && StoreCenter.main.hasToken()
} }
} }
@ -235,11 +235,11 @@ struct AccountRowView: View {
var userName: String var userName: String
var body: some View { var body: some View {
let hasToken = Store.main.hasToken() let hasToken = StoreCenter.main.hasToken()
LabeledContent { LabeledContent {
if hasToken { if hasToken {
Text(self.userName) Text(self.userName)
} else if Store.main.userName() != nil { } else if StoreCenter.main.userName() != nil {
Image(systemName: "xmark.circle.fill") Image(systemName: "xmark.circle.fill")
.foregroundStyle(.logoRed) .foregroundStyle(.logoRed)
} }

@ -9,11 +9,17 @@ import SwiftUI
import LeStorage import LeStorage
struct GroupStageScheduleEditorView: View { struct GroupStageScheduleEditorView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Bindable var groupStage: GroupStage @Bindable var groupStage: GroupStage
var tournament: Tournament var tournament: Tournament
@State private var startDate: Date @State private var startDate: Date
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
init(groupStage: GroupStage, tournament: Tournament) { init(groupStage: GroupStage, tournament: Tournament) {
self.groupStage = groupStage self.groupStage = groupStage
self.tournament = tournament self.tournament = tournament
@ -29,7 +35,7 @@ struct GroupStageScheduleEditorView: View {
private func _save() { private func _save() {
do { do {
try dataStore.groupStages.addOrUpdate(instance: groupStage) try tournamentStore.groupStages.addOrUpdate(instance: groupStage)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -9,6 +9,7 @@ import SwiftUI
import LeStorage import LeStorage
struct LoserRoundScheduleEditorView: View { struct LoserRoundScheduleEditorView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
var upperRound: Round var upperRound: Round
@ -17,6 +18,10 @@ struct LoserRoundScheduleEditorView: View {
@State private var startDate: Date @State private var startDate: Date
@State private var matchFormat: MatchFormat @State private var matchFormat: MatchFormat
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
init(upperRound: Round, tournament: Tournament) { init(upperRound: Round, tournament: Tournament) {
self.upperRound = upperRound self.upperRound = upperRound
self.tournament = tournament self.tournament = tournament
@ -75,7 +80,7 @@ struct LoserRoundScheduleEditorView: View {
private func _save() { private func _save() {
do { do {
try dataStore.rounds.addOrUpdate(contentOfs: upperRound.loserRounds()) try self.tournamentStore.rounds.addOrUpdate(contentOfs: upperRound.loserRounds())
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -9,6 +9,7 @@ import SwiftUI
import LeStorage import LeStorage
struct LoserRoundStepScheduleEditorView: View { struct LoserRoundStepScheduleEditorView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
var stepIndex: Int var stepIndex: Int
@ -19,6 +20,10 @@ struct LoserRoundStepScheduleEditorView: View {
@State private var startDate: Date @State private var startDate: Date
//@State private var matchFormat: MatchFormat //@State private var matchFormat: MatchFormat
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
init(stepIndex: Int, round: Round, upperRound: Round, tournament: Tournament) { init(stepIndex: Int, round: Round, upperRound: Round, tournament: Tournament) {
self.upperRound = upperRound self.upperRound = upperRound
self.tournament = tournament self.tournament = tournament
@ -69,7 +74,7 @@ struct LoserRoundStepScheduleEditorView: View {
private func _save() { private func _save() {
do { do {
try dataStore.rounds.addOrUpdate(contentOfs: upperRound.loserRounds(forRoundIndex: round.index)) try tournamentStore.rounds.addOrUpdate(contentOfs: upperRound.loserRounds(forRoundIndex: round.index))
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -9,7 +9,9 @@ import SwiftUI
import LeStorage import LeStorage
struct PlanningSettingsView: View { struct PlanningSettingsView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Bindable var tournament: Tournament @Bindable var tournament: Tournament
@Bindable var matchScheduler: MatchScheduler @Bindable var matchScheduler: MatchScheduler
@ -20,6 +22,10 @@ struct PlanningSettingsView: View {
@State private var issueFound: Bool = false @State private var issueFound: Bool = false
@State private var parallelType: Bool = false @State private var parallelType: Bool = false
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
init(tournament: Tournament) { init(tournament: Tournament) {
self.tournament = tournament self.tournament = tournament
if let matchScheduler = tournament.matchScheduler() { if let matchScheduler = tournament.matchScheduler() {
@ -68,7 +74,7 @@ struct PlanningSettingsView: View {
let verb = tournament.courtCount > 1 ? "seront" : "sera" let verb = tournament.courtCount > 1 ? "seront" : "sera"
Text("En réduisant les terrains maximum, seul\(plural) le\(plural) \(tournament.courtCount) premier\(plural) terrain\(plural) \(verb) utilisé\(plural)") + Text(", par contre, si vous augmentez le nombre de terrains, vous pourrez plutôt préciser quel terrain n'est pas disponible.") Text("En réduisant les terrains maximum, seul\(plural) le\(plural) \(tournament.courtCount) premier\(plural) terrain\(plural) \(verb) utilisé\(plural)") + Text(", par contre, si vous augmentez le nombre de terrains, vous pourrez plutôt préciser quel terrain n'est pas disponible.")
} else if tournament.courtCount > club.courtCount { } else if tournament.courtCount > club.courtCount {
let isCreatedByUser = club.hasBeenCreated(by: Store.main.userId) let isCreatedByUser = club.hasBeenCreated(by: StoreCenter.main.userId)
Button { Button {
do { do {
club.courtCount = tournament.courtCount club.courtCount = tournament.courtCount
@ -117,7 +123,7 @@ struct PlanningSettingsView: View {
$0.startDate = nil $0.startDate = nil
$0.confirmed = false $0.confirmed = false
}) })
try dataStore.matches.addOrUpdate(contentOfs: allMatches) try self.tournamentStore.matches.addOrUpdate(contentOfs: allMatches)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -133,13 +139,13 @@ struct PlanningSettingsView: View {
$0.startDate = nil $0.startDate = nil
$0.confirmed = false $0.confirmed = false
}) })
try dataStore.matches.addOrUpdate(contentOfs: allMatches) try self.tournamentStore.matches.addOrUpdate(contentOfs: allMatches)
allGroupStages.forEach({ $0.startDate = nil }) allGroupStages.forEach({ $0.startDate = nil })
try dataStore.groupStages.addOrUpdate(contentOfs: allGroupStages) try self.tournamentStore.groupStages.addOrUpdate(contentOfs: allGroupStages)
allRounds.forEach({ $0.startDate = nil }) allRounds.forEach({ $0.startDate = nil })
try dataStore.rounds.addOrUpdate(contentOfs: allRounds) try self.tournamentStore.rounds.addOrUpdate(contentOfs: allRounds)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -172,7 +178,7 @@ struct PlanningSettingsView: View {
.headerProminence(.increased) .headerProminence(.increased)
.onAppear { .onAppear {
do { do {
try dataStore.matchSchedulers.addOrUpdate(instance: matchScheduler) try self.tournamentStore.matchSchedulers.addOrUpdate(instance: matchScheduler)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -306,7 +312,7 @@ struct PlanningSettingsView: View {
private func _save() { private func _save() {
do { do {
try dataStore.matchSchedulers.addOrUpdate(instance: matchScheduler) try self.tournamentStore.matchSchedulers.addOrUpdate(instance: matchScheduler)
try dataStore.tournaments.addOrUpdate(instance: tournament) try dataStore.tournaments.addOrUpdate(instance: tournament)
} catch { } catch {
Logger.error(error) Logger.error(error)

@ -37,6 +37,7 @@ struct PlanningView: View {
ForEach(_matches) { match in ForEach(_matches) { match in
NavigationLink { NavigationLink {
MatchDetailView(match: match, matchViewStyle: .sectionedStandardStyle) MatchDetailView(match: match, matchViewStyle: .sectionedStandardStyle)
.environment(self.tournament)
} label: { } label: {
LabeledContent { LabeledContent {
if let courtName = match.courtName() { if let courtName = match.courtName() {

@ -15,6 +15,10 @@ struct RoundScheduleEditorView: View {
var tournament: Tournament var tournament: Tournament
@State private var startDate: Date @State private var startDate: Date
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
init(round: Round, tournament: Tournament) { init(round: Round, tournament: Tournament) {
self.round = round self.round = round
self.tournament = tournament self.tournament = tournament
@ -62,7 +66,7 @@ struct RoundScheduleEditorView: View {
private func _save() { private func _save() {
do { do {
try dataStore.rounds.addOrUpdate(instance: round) try tournamentStore.rounds.addOrUpdate(instance: round)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -20,10 +20,16 @@ extension Round: Schedulable {
} }
struct SchedulerView: View { struct SchedulerView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
var tournament: Tournament var tournament: Tournament
var destination: ScheduleDestination var destination: ScheduleDestination
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var body: some View { var body: some View {
@Bindable var tournament = tournament @Bindable var tournament = tournament
@ -43,7 +49,7 @@ struct SchedulerView: View {
} }
do { do {
try dataStore.tournaments.addOrUpdate(instance: tournament) try dataStore.tournaments.addOrUpdate(instance: tournament)
try dataStore.groupStages.addOrUpdate(contentOfs: groupStages) try self.tournamentStore.groupStages.addOrUpdate(contentOfs: groupStages)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -82,7 +88,7 @@ struct SchedulerView: View {
do { do {
try dataStore.tournaments.addOrUpdate(instance: tournament) try dataStore.tournaments.addOrUpdate(instance: tournament)
try dataStore.groupStages.addOrUpdate(contentOfs: groupStages) try self.tournamentStore.groupStages.addOrUpdate(contentOfs: groupStages)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -122,7 +128,7 @@ struct SchedulerView: View {
Button { Button {
round.updateMatchFormatAndAllMatches(federalFormat) round.updateMatchFormatAndAllMatches(federalFormat)
do { do {
try dataStore.rounds.addOrUpdate(instance: round) try self.tournamentStore.rounds.addOrUpdate(instance: round)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -166,7 +172,7 @@ struct SchedulerView: View {
Button { Button {
round.updateMatchFormatAndAllMatches(federalFormat) round.updateMatchFormatAndAllMatches(federalFormat)
do { do {
try dataStore.rounds.addOrUpdate(instance: round) try self.tournamentStore.rounds.addOrUpdate(instance: round)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -17,6 +17,8 @@ struct EditablePlayerView: View {
} }
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) var tournament: Tournament
@Bindable var player: PlayerRegistration @Bindable var player: PlayerRegistration
var editingOptions: [PlayerEditingOption] var editingOptions: [PlayerEditingOption]
@State private var editedLicenceId = "" @State private var editedLicenceId = ""
@ -24,6 +26,10 @@ struct EditablePlayerView: View {
@State private var presentLastNameUpdate: Bool = false @State private var presentLastNameUpdate: Bool = false
@State private var presentFirstNameUpdate: Bool = false @State private var presentFirstNameUpdate: Bool = false
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var body: some View { var body: some View {
computedPlayerView(player) computedPlayerView(player)
.alert("Numéro de licence", isPresented: $shouldPresentLicenceIdEdition) { .alert("Numéro de licence", isPresented: $shouldPresentLicenceIdEdition) {
@ -32,7 +38,7 @@ struct EditablePlayerView: View {
player.licenceId = editedLicenceId player.licenceId = editedLicenceId
editedLicenceId = "" editedLicenceId = ""
do { do {
try dataStore.playerRegistrations.addOrUpdate(instance: player) try self.tournamentStore.playerRegistrations.addOrUpdate(instance: player)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -42,7 +48,7 @@ struct EditablePlayerView: View {
TextField("Prénom", text: $player.firstName) TextField("Prénom", text: $player.firstName)
.onSubmit { .onSubmit {
do { do {
try dataStore.playerRegistrations.addOrUpdate(instance: player) try self.tournamentStore.playerRegistrations.addOrUpdate(instance: player)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -52,7 +58,7 @@ struct EditablePlayerView: View {
TextField("Nom", text: $player.lastName) TextField("Nom", text: $player.lastName)
.onSubmit { .onSubmit {
do { do {
try dataStore.playerRegistrations.addOrUpdate(instance: player) try self.tournamentStore.playerRegistrations.addOrUpdate(instance: player)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -74,7 +80,7 @@ struct EditablePlayerView: View {
Button { Button {
player.hasArrived.toggle() player.hasArrived.toggle()
do { do {
try dataStore.playerRegistrations.addOrUpdate(instance: player) try self.tournamentStore.playerRegistrations.addOrUpdate(instance: player)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -9,8 +9,13 @@ import SwiftUI
import LeStorage import LeStorage
struct PlayerPayView: View { struct PlayerPayView: View {
@EnvironmentObject var dataStore: DataStore
@Bindable var player: PlayerRegistration @Bindable var player: PlayerRegistration
@Environment(Tournament.self) var tournament: Tournament
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var body: some View { var body: some View {
Picker(selection: $player.paymentType) { Picker(selection: $player.paymentType) {
@ -29,7 +34,7 @@ struct PlayerPayView: View {
private func _save() { private func _save() {
do { do {
try dataStore.playerRegistrations.addOrUpdate(instance: player) try tournamentStore.playerRegistrations.addOrUpdate(instance: player)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -8,10 +8,16 @@
import SwiftUI import SwiftUI
struct PlayerSexPickerView: View { struct PlayerSexPickerView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) var tournament: Tournament @Environment(Tournament.self) var tournament: Tournament
@Bindable var player: PlayerRegistration @Bindable var player: PlayerRegistration
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var body: some View { var body: some View {
HStack { HStack {
Text(player.playerLabel()) Text(player.playerLabel())
@ -33,10 +39,10 @@ struct PlayerSexPickerView: View {
private func _save() { private func _save() {
do { do {
player.setComputedRank(in: tournament) player.setComputedRank(in: tournament)
try dataStore.playerRegistrations.addOrUpdate(instance: player) try tournamentStore.playerRegistrations.addOrUpdate(instance: player)
if let team = player.team() { if let team = player.team() {
team.updateWeight(inTournamentCategory: tournament.tournamentCategory) team.updateWeight(inTournamentCategory: tournament.tournamentCategory)
try dataStore.teamRegistrations.addOrUpdate(instance: team) try tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} }
} catch { } catch {

@ -9,14 +9,20 @@ import SwiftUI
import LeStorage import LeStorage
struct PlayerDetailView: View { struct PlayerDetailView: View {
@Environment(Tournament.self) var tournament: Tournament @Environment(Tournament.self) var tournament: Tournament
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Bindable var player: PlayerRegistration @Bindable var player: PlayerRegistration
@State private var licenceId: String @State private var licenceId: String
@State private var phoneNumber: String @State private var phoneNumber: String
@State private var email: String @State private var email: String
@FocusState var focusedField: PlayerRegistration.CodingKeys? @FocusState var focusedField: PlayerRegistration.CodingKeys?
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
init(player: PlayerRegistration) { init(player: PlayerRegistration) {
self.player = player self.player = player
_licenceId = .init(wrappedValue: player.licenceId ?? "") _licenceId = .init(wrappedValue: player.licenceId ?? "")
@ -205,13 +211,13 @@ struct PlayerDetailView: View {
private func _save() { private func _save() {
do { do {
try dataStore.playerRegistrations.addOrUpdate(instance: player) try self.tournamentStore.playerRegistrations.addOrUpdate(instance: player)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
if let team = player.team() { if let team = player.team() {
do { do {
try dataStore.teamRegistrations.addOrUpdate(instance: team) try self.tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -9,15 +9,22 @@ import SwiftUI
import LeStorage import LeStorage
struct PlayerView: View { struct PlayerView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) var tournament: Tournament
let player: PlayerRegistration let player: PlayerRegistration
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var body: some View { var body: some View {
ImportedPlayerView(player: player) ImportedPlayerView(player: player)
.swipeActions(edge: .trailing, allowsFullSwipe: true) { .swipeActions(edge: .trailing, allowsFullSwipe: true) {
Button(role: .destructive) { Button(role: .destructive) {
do { do {
try dataStore.playerRegistrations.delete(instance: player) try self.tournamentStore.playerRegistrations.delete(instance: player)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -29,7 +29,7 @@ struct LoserRoundView: View {
Section { Section {
let matches = loserRound.playedMatches().sorted(by: \.index) let matches = loserRound.playedMatches().sorted(by: \.index)
ForEach(matches) { match in ForEach(matches) { match in
MatchRowView(match: match, matchViewStyle: .sectionedStandardStyle) MatchRowView(match: match, tournament: self.tournament, matchViewStyle: .sectionedStandardStyle)
.overlay { .overlay {
if match.disabled /*&& isEditingTournamentSeed*/ { if match.disabled /*&& isEditingTournamentSeed*/ {
Image(systemName: "xmark") Image(systemName: "xmark")

@ -10,9 +10,14 @@ import LeStorage
struct RoundSettingsView: View { struct RoundSettingsView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(\.isEditingTournamentSeed) private var isEditingTournamentSeed @Environment(\.isEditingTournamentSeed) private var isEditingTournamentSeed
@Environment(Tournament.self) var tournament: Tournament @Environment(Tournament.self) var tournament: Tournament
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var body: some View { var body: some View {
List { List {
if tournament.shouldVerifyBracket { if tournament.shouldVerifyBracket {
@ -78,12 +83,12 @@ struct RoundSettingsView: View {
return match return match
} }
do { do {
try dataStore.rounds.addOrUpdate(instance: round) try tournamentStore.rounds.addOrUpdate(instance: round)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
do { do {
try dataStore.matches.addOrUpdate(contentOfs: matches) try tournamentStore.matches.addOrUpdate(contentOfs: matches)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -97,7 +102,7 @@ struct RoundSettingsView: View {
if let lastRound = tournament.rounds().first { // first is final, last round if let lastRound = tournament.rounds().first { // first is final, last round
RowButtonView("Supprimer " + lastRound.roundTitle(), role: .destructive) { RowButtonView("Supprimer " + lastRound.roundTitle(), role: .destructive) {
do { do {
try dataStore.rounds.delete(instance: lastRound) try tournamentStore.rounds.delete(instance: lastRound)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -116,12 +121,12 @@ struct RoundSettingsView: View {
} }
do { do {
try DataStore.shared.teamScores.delete(contentOfs: ts) try tournamentStore.teamScores.delete(contentOfs: ts)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
do { do {
try dataStore.teamRegistrations.addOrUpdate(contentOfs: tournament.unsortedTeams()) try tournamentStore.teamRegistrations.addOrUpdate(contentOfs: tournament.unsortedTeams())
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -10,6 +10,7 @@ import LeStorage
import TipKit import TipKit
struct RoundView: View { struct RoundView: View {
@Environment(\.isEditingTournamentSeed) private var isEditingTournamentSeed @Environment(\.isEditingTournamentSeed) private var isEditingTournamentSeed
@Environment(Tournament.self) var tournament: Tournament @Environment(Tournament.self) var tournament: Tournament
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@ -23,6 +24,10 @@ struct RoundView: View {
var round: Round var round: Round
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
private func _getAvailableSeedGroup() async { private func _getAvailableSeedGroup() async {
availableSeedGroup = tournament.seedGroupAvailable(atRoundIndex: round.index) availableSeedGroup = tournament.seedGroupAvailable(atRoundIndex: round.index)
} }
@ -226,7 +231,7 @@ struct RoundView: View {
ForEach(displayableMatches) { match in ForEach(displayableMatches) { match in
Section { Section {
MatchRowView(match: match, matchViewStyle: .sectionedStandardStyle) MatchRowView(match: match, tournament: self.tournament, matchViewStyle: .sectionedStandardStyle)
} header: { } header: {
HStack { HStack {
Text(round.roundTitle(.wide)) Text(round.roundTitle(.wide))
@ -298,7 +303,7 @@ struct RoundView: View {
private func _save() async { private func _save() async {
do { do {
try dataStore.teamRegistrations.addOrUpdate(contentOfs: tournament.unsortedTeams()) try self.tournamentStore.teamRegistrations.addOrUpdate(contentOfs: tournament.unsortedTeams())
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -313,7 +318,7 @@ struct RoundView: View {
} }
let allRoundMatches = tournament.allRoundMatches() let allRoundMatches = tournament.allRoundMatches()
do { do {
try DataStore.shared.matches.addOrUpdate(contentOfs: allRoundMatches) try self.tournamentStore.matches.addOrUpdate(contentOfs: allRoundMatches)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -9,9 +9,16 @@ import SwiftUI
import LeStorage import LeStorage
struct EditScoreView: View { struct EditScoreView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@ObservedObject var matchDescriptor: MatchDescriptor @ObservedObject var matchDescriptor: MatchDescriptor
@Environment(\.dismiss) private var dismiss @Environment(\.dismiss) private var dismiss
@Environment(Tournament.self) var tournament: Tournament
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
func walkout(_ team: TeamPosition) { func walkout(_ team: TeamPosition) {
self.matchDescriptor.match?.setWalkOut(team) self.matchDescriptor.match?.setWalkOut(team)
@ -104,7 +111,7 @@ struct EditScoreView: View {
func save() { func save() {
if let match = matchDescriptor.match { if let match = matchDescriptor.match {
do { do {
try dataStore.matches.addOrUpdate(instance: match) try self.tournamentStore.matches.addOrUpdate(instance: match)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -80,7 +80,7 @@ struct SupportButtonView: View {
private func _getBody() -> String { private func _getBody() -> String {
let separator = "---------------------------------------------" let separator = "---------------------------------------------"
return ["Décrivez votre problème", "\n\n\n", separator, "token", Store.main.token(), separator, "userId", Store.main.userId, separator, "dataStore userId", DataStore.shared.user.id].compacted().joined(separator: "\n") return ["Décrivez votre problème", "\n\n\n", separator, "token", StoreCenter.main.token(), separator, "userId", StoreCenter.main.userId, separator, "dataStore userId", DataStore.shared.user.id].compacted().joined(separator: "\n")
} }
private func _getDeviceIdentifier() -> String { private func _getDeviceIdentifier() -> String {

@ -10,9 +10,16 @@ import LeStorage
struct EditingTeamView: View { struct EditingTeamView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
var team: TeamRegistration var team: TeamRegistration
@State private var registrationDate : Date @State private var registrationDate : Date
@State private var name: String @State private var name: String
@Environment(Tournament.self) var tournament: Tournament
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
init(team: TeamRegistration) { init(team: TeamRegistration) {
self.team = team self.team = team
@ -91,7 +98,7 @@ struct EditingTeamView: View {
$0.hasArrived = hasArrived $0.hasArrived = hasArrived
} }
do { do {
try dataStore.playerRegistrations.addOrUpdate(contentOfs: team.unsortedPlayers()) try tournamentStore.playerRegistrations.addOrUpdate(contentOfs: team.unsortedPlayers())
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -100,7 +107,7 @@ struct EditingTeamView: View {
} }
private func _save() { private func _save() {
do { do {
try dataStore.teamRegistrations.addOrUpdate(instance: team) try tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -55,7 +55,9 @@ enum FileImportCustomField: Int, Identifiable, CaseIterable {
} }
struct FileImportView: View { struct FileImportView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) var tournament: Tournament @Environment(Tournament.self) var tournament: Tournament
@Environment(\.dismiss) private var dismiss @Environment(\.dismiss) private var dismiss
@ -76,6 +78,10 @@ struct FileImportView: View {
@State private var multiImport: Bool = false @State private var multiImport: Bool = false
@State private var presentFormatHelperView: Bool = false @State private var presentFormatHelperView: Bool = false
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
private func filteredTeams(tournament: Tournament) -> [FileImportManager.TeamHolder] { private func filteredTeams(tournament: Tournament) -> [FileImportManager.TeamHolder] {
return teams.filter { $0.tournamentCategory == tournament.tournamentCategory }.sorted(by: \.weight) return teams.filter { $0.tournamentCategory == tournament.tournamentCategory }.sorted(by: \.weight)
} }
@ -83,7 +89,7 @@ struct FileImportView: View {
private func _deleteTeams() async { private func _deleteTeams() async {
await MainActor.run { await MainActor.run {
do { do {
try dataStore.teamRegistrations.delete(contentOfs: tournament.unsortedTeams()) try tournamentStore.teamRegistrations.delete(contentOfs: tournament.unsortedTeams())
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -417,7 +423,7 @@ struct FileImportView: View {
} }
do { do {
try dataStore.teamRegistrations.addOrUpdate(contentOfs: unfound) try self.tournamentStore.teamRegistrations.addOrUpdate(contentOfs: unfound)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -32,7 +32,7 @@ struct BroadcastView: View {
var body: some View { var body: some View {
@Bindable var tournament = tournament @Bindable var tournament = tournament
List { List {
if Store.main.userId == nil { if StoreCenter.main.userId == nil {
Section { Section {
TipView(createAccountTip) { action in TipView(createAccountTip) { action in
switch action.id { switch action.id {

@ -75,7 +75,7 @@ struct TournamentClubSettingsView: View {
let verb = tournament.courtCount > 1 ? "seront" : "sera" let verb = tournament.courtCount > 1 ? "seront" : "sera"
Text("En réduisant les terrains maximum, seul\(plural) le\(plural) \(tournament.courtCount) premier\(plural) terrain\(plural) \(verb) utilisé\(plural)") + Text(", par contre, si vous augmentez le nombre de terrains, vous pourrez plutôt préciser quel terrain n'est pas disponible.") Text("En réduisant les terrains maximum, seul\(plural) le\(plural) \(tournament.courtCount) premier\(plural) terrain\(plural) \(verb) utilisé\(plural)") + Text(", par contre, si vous augmentez le nombre de terrains, vous pourrez plutôt préciser quel terrain n'est pas disponible.")
} else if tournament.courtCount > club.courtCount { } else if tournament.courtCount > club.courtCount {
let isCreatedByUser = club.hasBeenCreated(by: Store.main.userId) let isCreatedByUser = club.hasBeenCreated(by: StoreCenter.main.userId)
Button { Button {
do { do {
club.courtCount = tournament.courtCount club.courtCount = tournament.courtCount
@ -100,7 +100,7 @@ struct TournamentClubSettingsView: View {
if let selectedClub { if let selectedClub {
ClubCourtSetupView(club: selectedClub, displayContext: selectedClub.hasBeenCreated(by: Store.main.userId) ? .edition : .lockedForEditing, selectedCourt: $selectedCourt) ClubCourtSetupView(club: selectedClub, displayContext: selectedClub.hasBeenCreated(by: StoreCenter.main.userId) ? .edition : .lockedForEditing, selectedCourt: $selectedCourt)
.onChange(of: selectedClub.courtCount) { .onChange(of: selectedClub.courtCount) {
tournament.courtCount = max(tournament.courtCount, selectedClub.courtCount) tournament.courtCount = max(tournament.courtCount, selectedClub.courtCount)
do { do {
@ -112,7 +112,7 @@ struct TournamentClubSettingsView: View {
} }
} }
.navigationDestination(item: $showClubDetail) { club in .navigationDestination(item: $showClubDetail) { club in
ClubDetailView(club: club, displayContext: club.hasBeenCreated(by: Store.main.userId) ? .edition : .lockedForEditing) ClubDetailView(club: club, displayContext: club.hasBeenCreated(by: StoreCenter.main.userId) ? .edition : .lockedForEditing)
} }
.navigationDestination(item: $selectedCourt) { court in .navigationDestination(item: $selectedCourt) { court in
CourtView(court: court) CourtView(court: court)

@ -9,11 +9,18 @@ import SwiftUI
import LeStorage import LeStorage
struct TournamentMatchFormatsSettingsView: View { struct TournamentMatchFormatsSettingsView: View {
@Environment(NavigationViewModel.self) var navigation: NavigationViewModel @Environment(NavigationViewModel.self) var navigation: NavigationViewModel
@Environment(Tournament.self) var tournament: Tournament @Environment(Tournament.self) var tournament: Tournament
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@State private var confirmUpdate: Bool = false @State private var confirmUpdate: Bool = false
@State private var updateCompleted: Bool = false @State private var updateCompleted: Bool = false
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var body: some View { var body: some View {
@Bindable var tournament = tournament @Bindable var tournament = tournament
List { List {
@ -92,12 +99,12 @@ struct TournamentMatchFormatsSettingsView: View {
} }
} }
do { do {
try dataStore.groupStages.addOrUpdate(contentOfs: groupStages) try tournamentStore.groupStages.addOrUpdate(contentOfs: groupStages)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
do { do {
try dataStore.rounds.addOrUpdate(contentOfs: allRounds) try tournamentStore.rounds.addOrUpdate(contentOfs: allRounds)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -10,12 +10,17 @@ import LeStorage
struct UpdateSourceRankDateView: View { struct UpdateSourceRankDateView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Binding var currentRankSourceDate: Date? @Binding var currentRankSourceDate: Date?
@Binding var confirmUpdateRank: Bool @Binding var confirmUpdateRank: Bool
@State private var forceRefreshLockWeight: Bool = false @State private var forceRefreshLockWeight: Bool = false
@State private var updatingRank = false @State private var updatingRank = false
var tournament: Tournament var tournament: Tournament
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var body: some View { var body: some View {
NavigationStack { NavigationStack {
List { List {
@ -43,7 +48,7 @@ struct UpdateSourceRankDateView: View {
player.setComputedRank(in: tournament) player.setComputedRank(in: tournament)
} }
try dataStore.playerRegistrations.addOrUpdate(contentOfs: tournament.unsortedPlayers()) try tournamentStore.playerRegistrations.addOrUpdate(contentOfs: tournament.unsortedPlayers())
tournament.unsortedTeams().forEach { team in tournament.unsortedTeams().forEach { team in
team.setWeight(from: team.players(), inTournamentCategory: tournament.tournamentCategory) team.setWeight(from: team.players(), inTournamentCategory: tournament.tournamentCategory)
@ -52,7 +57,7 @@ struct UpdateSourceRankDateView: View {
} }
} }
try dataStore.teamRegistrations.addOrUpdate(contentOfs: tournament.unsortedTeams()) try tournamentStore.teamRegistrations.addOrUpdate(contentOfs: tournament.unsortedTeams())
try dataStore.tournaments.addOrUpdate(instance: tournament) try dataStore.tournaments.addOrUpdate(instance: tournament)

@ -20,7 +20,9 @@ let padelBeachExportTip = PadelBeachExportTip()
let padelBeachImportTip = PadelBeachImportTip() let padelBeachImportTip = PadelBeachImportTip()
struct InscriptionManagerView: View { struct InscriptionManagerView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@EnvironmentObject var networkMonitor: NetworkMonitor @EnvironmentObject var networkMonitor: NetworkMonitor
@Environment(\.dismiss) var dismiss @Environment(\.dismiss) var dismiss
@ -63,6 +65,10 @@ struct InscriptionManagerView: View {
@State private var teamPaste: URL? @State private var teamPaste: URL?
@State private var confirmDuplicate: Bool = false @State private var confirmDuplicate: Bool = false
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var messageSentFailed: Binding<Bool> { var messageSentFailed: Binding<Bool> {
Binding { Binding {
sentError != nil sentError != nil
@ -167,7 +173,7 @@ struct InscriptionManagerView: View {
} }
do { do {
try dataStore.teamRegistrations.addOrUpdate(contentOfs: waitingList) try tournamentStore.teamRegistrations.addOrUpdate(contentOfs: waitingList)
try dataStore.tournaments.addOrUpdate(instance: tournament) try dataStore.tournaments.addOrUpdate(instance: tournament)
} catch { } catch {
Logger.error(error) Logger.error(error)
@ -887,12 +893,12 @@ struct InscriptionManagerView: View {
let players = _currentSelection() let players = _currentSelection()
let team = tournament.addTeam(players) let team = tournament.addTeam(players)
do { do {
try dataStore.teamRegistrations.addOrUpdate(instance: team) try self.tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
do { do {
try dataStore.playerRegistrations.addOrUpdate(contentOfs: players) try self.tournamentStore.playerRegistrations.addOrUpdate(contentOfs: players)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -915,12 +921,12 @@ struct InscriptionManagerView: View {
let players = _currentSelection() let players = _currentSelection()
editedTeam.updatePlayers(players, inTournamentCategory: tournament.tournamentCategory) editedTeam.updatePlayers(players, inTournamentCategory: tournament.tournamentCategory)
do { do {
try dataStore.teamRegistrations.addOrUpdate(instance: editedTeam) try self.tournamentStore.teamRegistrations.addOrUpdate(instance: editedTeam)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
do { do {
try dataStore.playerRegistrations.addOrUpdate(contentOfs: players) try self.tournamentStore.playerRegistrations.addOrUpdate(contentOfs: players)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -1151,7 +1157,7 @@ struct InscriptionManagerView: View {
team.walkOut = false team.walkOut = false
team.wildCardBracket = value team.wildCardBracket = value
do { do {
try dataStore.teamRegistrations.addOrUpdate(instance: team) try tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -1172,7 +1178,7 @@ struct InscriptionManagerView: View {
team.walkOut = false team.walkOut = false
team.wildCardGroupStage = value team.wildCardGroupStage = value
do { do {
try dataStore.teamRegistrations.addOrUpdate(instance: team) try tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -1193,7 +1199,7 @@ struct InscriptionManagerView: View {
team.wildCardGroupStage = false team.wildCardGroupStage = false
team.walkOut = value team.walkOut = value
do { do {
try dataStore.teamRegistrations.addOrUpdate(instance: team) try tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -1207,7 +1213,7 @@ struct InscriptionManagerView: View {
_clearScreen() _clearScreen()
Task { Task {
do { do {
try dataStore.teamRegistrations.delete(instance: team) try tournamentStore.teamRegistrations.delete(instance: team)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -16,6 +16,10 @@ struct TournamentRankView: View {
@State private var calculating = false @State private var calculating = false
@State private var selectedTeam: TeamRegistration? @State private var selectedTeam: TeamRegistration?
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
var isEditingTeam: Binding<Bool> { var isEditingTeam: Binding<Bool> {
Binding { Binding {
selectedTeam != nil selectedTeam != nil
@ -121,7 +125,7 @@ struct TournamentRankView: View {
Button("Valider") { Button("Valider") {
selectedTeam.pointsEarned = tournament.isAnimation() ? nil : tournament.tournamentLevel.points(for: selectedTeam.finalRanking! - 1, count: tournament.teamCount) selectedTeam.pointsEarned = tournament.isAnimation() ? nil : tournament.tournamentLevel.points(for: selectedTeam.finalRanking! - 1, count: tournament.teamCount)
do { do {
try dataStore.teamRegistrations.addOrUpdate(instance: selectedTeam) try self.tournamentStore.teamRegistrations.addOrUpdate(instance: selectedTeam)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -254,7 +258,8 @@ struct TournamentRankView: View {
let finalRanks = await tournament.finalRanking() let finalRanks = await tournament.finalRanking()
finalRanks.keys.sorted().forEach { rank in finalRanks.keys.sorted().forEach { rank in
if let rankedTeamIds = finalRanks[rank] { if let rankedTeamIds = finalRanks[rank] {
rankings[rank] = rankedTeamIds.compactMap { Store.main.findById($0) } let teams: [TeamRegistration] = rankedTeamIds.compactMap { self.tournamentStore.teamRegistrations.findById($0) }
self.rankings[rank] = teams
} }
} }
} }
@ -281,7 +286,7 @@ struct TournamentRankView: View {
private func _save() { private func _save() {
do { do {
try dataStore.teamRegistrations.addOrUpdate(contentOfs: tournament.unsortedTeams()) try self.tournamentStore.teamRegistrations.addOrUpdate(contentOfs: tournament.unsortedTeams())
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -14,7 +14,7 @@ struct TournamentBroadcastRowView: View {
var body: some View { var body: some View {
NavigationLink(value: Screen.broadcast) { NavigationLink(value: Screen.broadcast) {
LabeledContent { LabeledContent {
if Store.main.userId == nil { if StoreCenter.main.userId == nil {
Image(systemName: "exclamationmark.circle.fill") Image(systemName: "exclamationmark.circle.fill")
.foregroundStyle(.logoYellow) .foregroundStyle(.logoYellow)
} else { } else {
@ -26,7 +26,7 @@ struct TournamentBroadcastRowView: View {
} }
} label: { } label: {
Text("Publication") Text("Publication")
if Store.main.userId == nil { if StoreCenter.main.userId == nil {
Text("Créez un compte pour publier !") Text("Créez un compte pour publier !")
} }
} }

@ -153,7 +153,7 @@ import LeStorage
func userFilteredPurchases() -> [StoreKit.Transaction] { func userFilteredPurchases() -> [StoreKit.Transaction] {
// Logger.log("self.purchasedTransactions = \(self.purchasedTransactions.count)") // Logger.log("self.purchasedTransactions = \(self.purchasedTransactions.count)")
guard let userId = Store.main.userId, let currentUserUUID: UUID = UUID(uuidString: userId) else { guard let userId = StoreCenter.main.userId, let currentUserUUID: UUID = UUID(uuidString: userId) else {
return [] return []
} }
@ -250,7 +250,7 @@ struct PurchaseRow: Identifiable {
fileprivate extension StoreKit.Transaction { fileprivate extension StoreKit.Transaction {
func purchase() throws -> Purchase { func purchase() throws -> Purchase {
guard let userId = Store.main.userId else { guard let userId = StoreCenter.main.userId else {
throw StoreError.missingUserId throw StoreError.missingUserId
} }
return Purchase(user: userId, return Purchase(user: userId,

@ -9,9 +9,9 @@ import Foundation
import LeStorage import LeStorage
class Purchase: ModelObject, Storable { class Purchase: ModelObject, Storable {
static func resourceName() -> String { return "purchases" } static func resourceName() -> String { return "purchases" }
static func tokenExemptedMethods() -> [HTTPMethod] { return [] } static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
static func filterByStoreIdentifier() -> Bool { return false }
var id: String = Store.randomId() var id: String = Store.randomId()

@ -100,7 +100,7 @@ class StoreManager {
func purchase(_ product: Product, quantity: Int? = nil) async throws -> StoreKit.Transaction? { func purchase(_ product: Product, quantity: Int? = nil) async throws -> StoreKit.Transaction? {
Logger.log("Store purchase started...") Logger.log("Store purchase started...")
guard let userId = Store.main.userId, let uuid: UUID = UUID(uuidString: userId) else { guard let userId = StoreCenter.main.userId, let uuid: UUID = UUID(uuidString: userId) else {
throw StoreError.missingUserId throw StoreError.missingUserId
} }

@ -203,7 +203,7 @@ struct SubscriptionView: View {
} }
fileprivate func _purchaseIfPossible() { fileprivate func _purchaseIfPossible() {
if Store.main.userId != nil { if StoreCenter.main.userId != nil {
self._purchase() self._purchase()
} else { } else {
self.showLoginView = true self.showLoginView = true

@ -11,6 +11,7 @@ import TipKit
struct TournamentView: View { struct TournamentView: View {
@EnvironmentObject var dataStore: DataStore @EnvironmentObject var dataStore: DataStore
@Environment(NavigationViewModel.self) var navigation: NavigationViewModel @Environment(NavigationViewModel.self) var navigation: NavigationViewModel
@State var tournament: Tournament @State var tournament: Tournament
var presentationContext: PresentationContext = .agenda var presentationContext: PresentationContext = .agenda
@ -22,7 +23,7 @@ struct TournamentView: View {
get: { tournament.id }, get: { tournament.id },
set: { id in set: { id in
if let tournamentFound: Tournament = Store.main.findById(id) { if let tournamentFound: Tournament = Store.main.findById(id) {
tournament = tournamentFound self.tournament = tournamentFound
} }
} }
)} )}
@ -36,6 +37,11 @@ struct TournamentView: View {
return URL.importDateFormatter.date(from: lastDataSource) return URL.importDateFormatter.date(from: lastDataSource)
} }
init(tournament: Tournament, presentationContext: PresentationContext = .agenda) {
self.tournament = tournament
self.presentationContext = presentationContext
}
var body: some View { var body: some View {
VStack(spacing: 0.0) { VStack(spacing: 0.0) {
List { List {

@ -66,7 +66,7 @@ struct ChangePasswordView: View {
Task { Task {
do { do {
self.isLoading = true self.isLoading = true
let service = try Store.main.service() let service = try StoreCenter.main.service()
_ = try await service.changePassword( _ = try await service.changePassword(
oldPassword: self.oldPassword, oldPassword: self.oldPassword,
password1: self.password1, password1: self.password1,

@ -197,7 +197,7 @@ struct LoginView: View {
self.errorText = nil // reset error self.errorText = nil // reset error
self.isLoading = true self.isLoading = true
do { do {
let service = try Store.main.service() let service = try StoreCenter.main.service()
let user: User = try await service.login( let user: User = try await service.login(
username: self.username, username: self.username,
password: self.password) password: self.password)
@ -240,7 +240,7 @@ struct EmailConfirmationView: View {
Task { Task {
do { do {
let service = try Store.main.service() let service = try StoreCenter.main.service()
try await service.forgotPassword(email: self.email) try await service.forgotPassword(email: self.email)
} catch { } catch {
Logger.error(error) Logger.error(error)

@ -224,7 +224,7 @@ struct UserCreationFormView: View {
phone: self.phone, phone: self.phone,
country: country) country: country)
let service: Services = try Store.main.service() let service: Services = try StoreCenter.main.service()
let _: User = try await service.createAccount(user: userCreationForm) let _: User = try await service.createAccount(user: userCreationForm)
DispatchQueue.main.async { DispatchQueue.main.async {

@ -72,7 +72,7 @@ final class ServerDataTests: XCTestCase {
func testEvent() async throws { func testEvent() async throws {
guard let userId = Store.main.userId else { guard let userId = StoreCenter.main.userId else {
assertionFailure("missing user UUID") assertionFailure("missing user UUID")
return return
} }
@ -340,7 +340,7 @@ final class ServerDataTests: XCTestCase {
func testPurchase() async throws { func testPurchase() async throws {
guard let userId = Store.main.userId else { guard let userId = StoreCenter.main.userId else {
assertionFailure("missing user UUID") assertionFailure("missing user UUID")
return return
} }

Loading…
Cancel
Save