From 9ebdffddd7f22f270d2258deb772442b3fbbdce1 Mon Sep 17 00:00:00 2001 From: Laurent Date: Thu, 5 Dec 2024 12:21:47 +0100 Subject: [PATCH] cleanup generation and add tournament sharing --- PadelClub.xcodeproj/project.pbxproj | 16 +- PadelClub/Data/Gen/BaseClub.swift | 3 +- PadelClub/Data/Gen/BaseCourt.swift | 1 - PadelClub/Data/Gen/BaseCustomUser.swift | 10 +- PadelClub/Data/Gen/BaseDateInterval.swift | 1 - PadelClub/Data/Gen/BaseEvent.swift | 1 - PadelClub/Data/Gen/BaseGroupStage.swift | 1 - PadelClub/Data/Gen/BaseMatch.swift | 1 - PadelClub/Data/Gen/BaseMatchScheduler.swift | 1 - PadelClub/Data/Gen/BaseMonthData.swift | 1 - .../Data/Gen/BasePlayerRegistration.swift | 1 - PadelClub/Data/Gen/BasePurchase.swift | 1 - PadelClub/Data/Gen/BaseRound.swift | 1 - PadelClub/Data/Gen/BaseTeamRegistration.swift | 1 - PadelClub/Data/Gen/BaseTeamScore.swift | 1 - PadelClub/Data/Gen/BaseTournament.swift | 1 - PadelClub/Data/Gen/Court.json | 3 +- PadelClub/Data/Gen/CustomUser.json | 6 +- PadelClub/Data/Gen/DateInterval.json | 3 +- PadelClub/Data/Gen/Event.json | 3 +- PadelClub/Data/Gen/GroupStage.json | 3 +- PadelClub/Data/Gen/Match.json | 1 - PadelClub/Data/Gen/MatchScheduler.json | 1 - PadelClub/Data/Gen/MonthData.json | 1 - PadelClub/Data/Gen/PlayerRegistration.json | 1 - PadelClub/Data/Gen/Purchase.json | 1 - PadelClub/Data/Gen/Round.json | 1 - PadelClub/Data/Gen/TeamRegistration.json | 1 - PadelClub/Data/Gen/TeamScore.json | 1 - PadelClub/Data/Gen/Tournament.json | 1 - PadelClub/Data/Gen/generator.py | 6 +- .../Navigation/Agenda/EventListView.swift | 8 +- .../Views/Tournament/TournamentView.swift | 8 +- PadelClub/Views/User/ShareModelView.swift | 113 ++++++++++++ PadelClub/Views/User/UserSearchView.swift | 168 ------------------ 35 files changed, 143 insertions(+), 229 deletions(-) create mode 100644 PadelClub/Views/User/ShareModelView.swift delete mode 100644 PadelClub/Views/User/UserSearchView.swift diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index 74a898c..5cc3b3c 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -17,9 +17,9 @@ C425D4122B6D249E002A7B48 /* PadelClubTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C425D4112B6D249E002A7B48 /* PadelClubTests.swift */; }; C425D41C2B6D249E002A7B48 /* PadelClubUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C425D41B2B6D249E002A7B48 /* PadelClubUITests.swift */; }; C425D41E2B6D249E002A7B48 /* PadelClubUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C425D41D2B6D249E002A7B48 /* PadelClubUITestsLaunchTests.swift */; }; - C4339BFB2CFF7D68004E5F09 /* UserSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4339BFA2CFF7D64004E5F09 /* UserSearchView.swift */; }; - C4339BFC2CFF7D68004E5F09 /* UserSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4339BFA2CFF7D64004E5F09 /* UserSearchView.swift */; }; - C4339BFD2CFF7D68004E5F09 /* UserSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4339BFA2CFF7D64004E5F09 /* UserSearchView.swift */; }; + C4339BFB2CFF7D68004E5F09 /* ShareModelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4339BFA2CFF7D64004E5F09 /* ShareModelView.swift */; }; + C4339BFC2CFF7D68004E5F09 /* ShareModelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4339BFA2CFF7D64004E5F09 /* ShareModelView.swift */; }; + C4339BFD2CFF7D68004E5F09 /* ShareModelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4339BFA2CFF7D64004E5F09 /* ShareModelView.swift */; }; C4489BE22C05BF5000043F3D /* DebugSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4489BE12C05BF5000043F3D /* DebugSettingsView.swift */; }; C44B79112BBDA63A00906534 /* Locale+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44B79102BBDA63A00906534 /* Locale+Extensions.swift */; }; C45BAE3B2BC6DF10002EEC8A /* SyncedProducts.storekit in Resources */ = {isa = PBXBuildFile; fileRef = C45BAE3A2BC6DF10002EEC8A /* SyncedProducts.storekit */; }; @@ -975,7 +975,7 @@ C425D4172B6D249E002A7B48 /* PadelClubUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PadelClubUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C425D41B2B6D249E002A7B48 /* PadelClubUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PadelClubUITests.swift; sourceTree = ""; }; C425D41D2B6D249E002A7B48 /* PadelClubUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PadelClubUITestsLaunchTests.swift; sourceTree = ""; }; - C4339BFA2CFF7D64004E5F09 /* UserSearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSearchView.swift; sourceTree = ""; }; + C4339BFA2CFF7D64004E5F09 /* ShareModelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareModelView.swift; sourceTree = ""; }; C4489BE12C05BF5000043F3D /* DebugSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugSettingsView.swift; sourceTree = ""; }; C44B79102BBDA63A00906534 /* Locale+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Locale+Extensions.swift"; sourceTree = ""; }; C45BAE3A2BC6DF10002EEC8A /* SyncedProducts.storekit */ = {isa = PBXFileReference; lastKnownFileType = text; path = SyncedProducts.storekit; sourceTree = ""; }; @@ -1547,7 +1547,7 @@ C4A47D852B7BA33F00ADC637 /* User */ = { isa = PBXGroup; children = ( - C4339BFA2CFF7D64004E5F09 /* UserSearchView.swift */, + C4339BFA2CFF7D64004E5F09 /* ShareModelView.swift */, C4A47DB22B86387500ADC637 /* AccountView.swift */, C4A47DA82B85F82100ADC637 /* ChangePasswordView.swift */, C4A47DA52B83948E00ADC637 /* LoginView.swift */, @@ -2457,7 +2457,7 @@ C4A47D9F2B7D0BCE00ADC637 /* StepperView.swift in Sources */, FFC83D4F2BB807D100750834 /* RoundsView.swift in Sources */, FF1CBC1B2BB53D1F0036DAAB /* FederalTournament.swift in Sources */, - C4339BFB2CFF7D68004E5F09 /* UserSearchView.swift in Sources */, + C4339BFB2CFF7D68004E5F09 /* ShareModelView.swift in Sources */, FF8F26412BADFC8700650388 /* TournamentInitView.swift in Sources */, C4A47D8A2B7BBB6500ADC637 /* SubscriptionView.swift in Sources */, FFD655D82C8DE27400E5B35E /* TournamentLookUpView.swift in Sources */, @@ -2836,7 +2836,7 @@ FF4CBF992C996C0600151637 /* StoreManager.swift in Sources */, FF4CBF9A2C996C0600151637 /* SearchViewModel.swift in Sources */, FF4CBF9B2C996C0600151637 /* PlayerRegistration.swift in Sources */, - C4339BFD2CFF7D68004E5F09 /* UserSearchView.swift in Sources */, + C4339BFD2CFF7D68004E5F09 /* ShareModelView.swift in Sources */, FF4CBF9C2C996C0600151637 /* ImportedPlayerView.swift in Sources */, FF4CBF9D2C996C0600151637 /* EditingTeamView.swift in Sources */, FF4CBF9E2C996C0600151637 /* NetworkManagerError.swift in Sources */, @@ -3103,7 +3103,7 @@ FF70FB182C90584900129CC2 /* StoreManager.swift in Sources */, FF70FB192C90584900129CC2 /* SearchViewModel.swift in Sources */, FF70FB1A2C90584900129CC2 /* PlayerRegistration.swift in Sources */, - C4339BFC2CFF7D68004E5F09 /* UserSearchView.swift in Sources */, + C4339BFC2CFF7D68004E5F09 /* ShareModelView.swift in Sources */, FF70FB1B2C90584900129CC2 /* ImportedPlayerView.swift in Sources */, FF70FB1C2C90584900129CC2 /* EditingTeamView.swift in Sources */, FF70FB1D2C90584900129CC2 /* NetworkManagerError.swift in Sources */, diff --git a/PadelClub/Data/Gen/BaseClub.swift b/PadelClub/Data/Gen/BaseClub.swift index 61c8fbb..ad4ec3e 100644 --- a/PadelClub/Data/Gen/BaseClub.swift +++ b/PadelClub/Data/Gen/BaseClub.swift @@ -10,7 +10,6 @@ class BaseClub: SyncedModelObject, SyncedStorable { static func resourceName() -> String { return "clubs" } static func tokenExemptedMethods() -> [HTTPMethod] { return [] } - static func filterByStoreIdentifier() -> Bool { return false } var id: String = Store.randomId() var creator: String? = nil @@ -137,4 +136,4 @@ class BaseClub: SyncedModelObject, SyncedStorable { ] } -} +} \ No newline at end of file diff --git a/PadelClub/Data/Gen/BaseCourt.swift b/PadelClub/Data/Gen/BaseCourt.swift index bb3dbed..10099bd 100644 --- a/PadelClub/Data/Gen/BaseCourt.swift +++ b/PadelClub/Data/Gen/BaseCourt.swift @@ -10,7 +10,6 @@ class BaseCourt: SyncedModelObject, SyncedStorable { static func resourceName() -> String { return "courts" } static func tokenExemptedMethods() -> [HTTPMethod] { return [] } - static func filterByStoreIdentifier() -> Bool { return false } var id: String = Store.randomId() var index: Int = 0 diff --git a/PadelClub/Data/Gen/BaseCustomUser.swift b/PadelClub/Data/Gen/BaseCustomUser.swift index bf5e67d..1b61d70 100644 --- a/PadelClub/Data/Gen/BaseCustomUser.swift +++ b/PadelClub/Data/Gen/BaseCustomUser.swift @@ -10,7 +10,6 @@ class BaseCustomUser: SyncedModelObject, SyncedStorable { static func resourceName() -> String { return "users" } static func tokenExemptedMethods() -> [HTTPMethod] { return [.post] } - static func filterByStoreIdentifier() -> Bool { return false } var id: String = Store.randomId() var username: String = "" @@ -34,6 +33,7 @@ class BaseCustomUser: SyncedModelObject, SyncedStorable { var loserBracketMatchFormatPreference: MatchFormat? = nil var loserBracketMode: LoserBracketMode = .automatic var deviceId: String? = nil + var agents: [String] = [] init( id: String = Store.randomId(), @@ -57,7 +57,8 @@ class BaseCustomUser: SyncedModelObject, SyncedStorable { groupStageMatchFormatPreference: MatchFormat? = nil, loserBracketMatchFormatPreference: MatchFormat? = nil, loserBracketMode: LoserBracketMode = .automatic, - deviceId: String? = nil + deviceId: String? = nil, + agents: [String] = [] ) { super.init() self.id = id @@ -82,6 +83,7 @@ class BaseCustomUser: SyncedModelObject, SyncedStorable { self.loserBracketMatchFormatPreference = loserBracketMatchFormatPreference self.loserBracketMode = loserBracketMode self.deviceId = deviceId + self.agents = agents } enum CodingKeys: String, CodingKey { @@ -107,6 +109,7 @@ class BaseCustomUser: SyncedModelObject, SyncedStorable { case _loserBracketMatchFormatPreference = "loserBracketMatchFormatPreference" case _loserBracketMode = "loserBracketMode" case _deviceId = "deviceId" + case _agents = "agents" } required init(from decoder: Decoder) throws { @@ -133,6 +136,7 @@ class BaseCustomUser: SyncedModelObject, SyncedStorable { self.loserBracketMatchFormatPreference = try container.decodeIfPresent(MatchFormat.self, forKey: ._loserBracketMatchFormatPreference) ?? nil self.loserBracketMode = try container.decodeIfPresent(LoserBracketMode.self, forKey: ._loserBracketMode) ?? .automatic self.deviceId = try container.decodeIfPresent(String.self, forKey: ._deviceId) ?? nil + self.agents = try container.decodeIfPresent([String].self, forKey: ._agents) ?? [] try super.init(from: decoder) } @@ -160,6 +164,7 @@ class BaseCustomUser: SyncedModelObject, SyncedStorable { try container.encode(self.loserBracketMatchFormatPreference, forKey: ._loserBracketMatchFormatPreference) try container.encode(self.loserBracketMode, forKey: ._loserBracketMode) try container.encode(self.deviceId, forKey: ._deviceId) + try container.encode(self.agents, forKey: ._agents) try super.encode(to: encoder) } @@ -187,6 +192,7 @@ class BaseCustomUser: SyncedModelObject, SyncedStorable { self.loserBracketMatchFormatPreference = customuser.loserBracketMatchFormatPreference self.loserBracketMode = customuser.loserBracketMode self.deviceId = customuser.deviceId + self.agents = customuser.agents } static func relationships() -> [Relationship] { diff --git a/PadelClub/Data/Gen/BaseDateInterval.swift b/PadelClub/Data/Gen/BaseDateInterval.swift index 0ba359a..a429f9d 100644 --- a/PadelClub/Data/Gen/BaseDateInterval.swift +++ b/PadelClub/Data/Gen/BaseDateInterval.swift @@ -10,7 +10,6 @@ class BaseDateInterval: SyncedModelObject, SyncedStorable { static func resourceName() -> String { return "date-intervals" } static func tokenExemptedMethods() -> [HTTPMethod] { return [] } - static func filterByStoreIdentifier() -> Bool { return false } var id: String = Store.randomId() var event: String = "" diff --git a/PadelClub/Data/Gen/BaseEvent.swift b/PadelClub/Data/Gen/BaseEvent.swift index ee7e5f2..4dcb703 100644 --- a/PadelClub/Data/Gen/BaseEvent.swift +++ b/PadelClub/Data/Gen/BaseEvent.swift @@ -10,7 +10,6 @@ class BaseEvent: SyncedModelObject, SyncedStorable { static func resourceName() -> String { return "events" } static func tokenExemptedMethods() -> [HTTPMethod] { return [] } - static func filterByStoreIdentifier() -> Bool { return false } var id: String = Store.randomId() var creator: String? = nil diff --git a/PadelClub/Data/Gen/BaseGroupStage.swift b/PadelClub/Data/Gen/BaseGroupStage.swift index c237546..c5c9e1d 100644 --- a/PadelClub/Data/Gen/BaseGroupStage.swift +++ b/PadelClub/Data/Gen/BaseGroupStage.swift @@ -10,7 +10,6 @@ class BaseGroupStage: SyncedModelObject, SyncedStorable { static func resourceName() -> String { return "group-stages" } static func tokenExemptedMethods() -> [HTTPMethod] { return [] } - static func filterByStoreIdentifier() -> Bool { return true } var id: String = Store.randomId() var tournament: String = "" diff --git a/PadelClub/Data/Gen/BaseMatch.swift b/PadelClub/Data/Gen/BaseMatch.swift index 9328e70..f66ab28 100644 --- a/PadelClub/Data/Gen/BaseMatch.swift +++ b/PadelClub/Data/Gen/BaseMatch.swift @@ -10,7 +10,6 @@ class BaseMatch: SyncedModelObject, SyncedStorable { static func resourceName() -> String { return "matches" } static func tokenExemptedMethods() -> [HTTPMethod] { return [] } - static func filterByStoreIdentifier() -> Bool { return true } var id: String = Store.randomId() var round: String? = nil diff --git a/PadelClub/Data/Gen/BaseMatchScheduler.swift b/PadelClub/Data/Gen/BaseMatchScheduler.swift index 9334070..59cb283 100644 --- a/PadelClub/Data/Gen/BaseMatchScheduler.swift +++ b/PadelClub/Data/Gen/BaseMatchScheduler.swift @@ -10,7 +10,6 @@ class BaseMatchScheduler: BaseModelObject, Storable { static func resourceName() -> String { return "match-scheduler" } static func tokenExemptedMethods() -> [HTTPMethod] { return [] } - static func filterByStoreIdentifier() -> Bool { return false } var id: String = Store.randomId() var tournament: String = "" diff --git a/PadelClub/Data/Gen/BaseMonthData.swift b/PadelClub/Data/Gen/BaseMonthData.swift index 06d719e..1f1a12c 100644 --- a/PadelClub/Data/Gen/BaseMonthData.swift +++ b/PadelClub/Data/Gen/BaseMonthData.swift @@ -10,7 +10,6 @@ class BaseMonthData: BaseModelObject, Storable { static func resourceName() -> String { return "month-data" } static func tokenExemptedMethods() -> [HTTPMethod] { return [] } - static func filterByStoreIdentifier() -> Bool { return false } var id: String = Store.randomId() var monthKey: String = "" diff --git a/PadelClub/Data/Gen/BasePlayerRegistration.swift b/PadelClub/Data/Gen/BasePlayerRegistration.swift index e925e55..594aee1 100644 --- a/PadelClub/Data/Gen/BasePlayerRegistration.swift +++ b/PadelClub/Data/Gen/BasePlayerRegistration.swift @@ -10,7 +10,6 @@ class BasePlayerRegistration: SyncedModelObject, SyncedStorable { static func resourceName() -> String { return "player-registrations" } static func tokenExemptedMethods() -> [HTTPMethod] { return [] } - static func filterByStoreIdentifier() -> Bool { return true } var id: String = Store.randomId() var teamRegistration: String? = nil diff --git a/PadelClub/Data/Gen/BasePurchase.swift b/PadelClub/Data/Gen/BasePurchase.swift index 3a2b8cd..e10f087 100644 --- a/PadelClub/Data/Gen/BasePurchase.swift +++ b/PadelClub/Data/Gen/BasePurchase.swift @@ -8,7 +8,6 @@ class BasePurchase: SyncedModelObject, SyncedStorable { static func resourceName() -> String { return "purchases" } static func tokenExemptedMethods() -> [HTTPMethod] { return [] } - static func filterByStoreIdentifier() -> Bool { return false } var id: UInt64 = 0 var user: String = "" diff --git a/PadelClub/Data/Gen/BaseRound.swift b/PadelClub/Data/Gen/BaseRound.swift index 48efe3b..7ea4249 100644 --- a/PadelClub/Data/Gen/BaseRound.swift +++ b/PadelClub/Data/Gen/BaseRound.swift @@ -10,7 +10,6 @@ class BaseRound: SyncedModelObject, SyncedStorable { static func resourceName() -> String { return "rounds" } static func tokenExemptedMethods() -> [HTTPMethod] { return [] } - static func filterByStoreIdentifier() -> Bool { return true } var id: String = Store.randomId() var tournament: String = "" diff --git a/PadelClub/Data/Gen/BaseTeamRegistration.swift b/PadelClub/Data/Gen/BaseTeamRegistration.swift index 6c9e96d..237d84f 100644 --- a/PadelClub/Data/Gen/BaseTeamRegistration.swift +++ b/PadelClub/Data/Gen/BaseTeamRegistration.swift @@ -10,7 +10,6 @@ class BaseTeamRegistration: SyncedModelObject, SyncedStorable { static func resourceName() -> String { return "team-registrations" } static func tokenExemptedMethods() -> [HTTPMethod] { return [] } - static func filterByStoreIdentifier() -> Bool { return true } var id: String = Store.randomId() var tournament: String = "" diff --git a/PadelClub/Data/Gen/BaseTeamScore.swift b/PadelClub/Data/Gen/BaseTeamScore.swift index dfcf662..2407f39 100644 --- a/PadelClub/Data/Gen/BaseTeamScore.swift +++ b/PadelClub/Data/Gen/BaseTeamScore.swift @@ -10,7 +10,6 @@ class BaseTeamScore: SyncedModelObject, SyncedStorable { static func resourceName() -> String { return "team-scores" } static func tokenExemptedMethods() -> [HTTPMethod] { return [] } - static func filterByStoreIdentifier() -> Bool { return true } var id: String = Store.randomId() var match: String = "" diff --git a/PadelClub/Data/Gen/BaseTournament.swift b/PadelClub/Data/Gen/BaseTournament.swift index ff2e836..3f29de8 100644 --- a/PadelClub/Data/Gen/BaseTournament.swift +++ b/PadelClub/Data/Gen/BaseTournament.swift @@ -10,7 +10,6 @@ class BaseTournament: SyncedModelObject, SyncedStorable { static func resourceName() -> String { return "tournaments" } static func tokenExemptedMethods() -> [HTTPMethod] { return [] } - static func filterByStoreIdentifier() -> Bool { return false } var id: String = Store.randomId() var event: String? = nil diff --git a/PadelClub/Data/Gen/Court.json b/PadelClub/Data/Gen/Court.json index bac920c..ec2bbe4 100644 --- a/PadelClub/Data/Gen/Court.json +++ b/PadelClub/Data/Gen/Court.json @@ -36,8 +36,7 @@ "defaultValue": "false" } ], - "tokenExemptedMethods": [], - "filterByStoreIdentifier": false + "tokenExemptedMethods": [] } ] } diff --git a/PadelClub/Data/Gen/CustomUser.json b/PadelClub/Data/Gen/CustomUser.json index f8e2f0c..ac32c3c 100644 --- a/PadelClub/Data/Gen/CustomUser.json +++ b/PadelClub/Data/Gen/CustomUser.json @@ -6,7 +6,6 @@ "synchronizable": true, "observable": true, "tokenExemptedMethods": ["post"], - "filterByStoreIdentifier": false, "properties": [ { "name": "id", @@ -125,6 +124,11 @@ "type": "String", "optional": true, "defaultValue": "nil" + }, + { + "name": "agents", + "type": "[String]", + "defaultValue": "[]" } ] } diff --git a/PadelClub/Data/Gen/DateInterval.json b/PadelClub/Data/Gen/DateInterval.json index 58ac3a9..b7c1532 100644 --- a/PadelClub/Data/Gen/DateInterval.json +++ b/PadelClub/Data/Gen/DateInterval.json @@ -27,8 +27,7 @@ "type": "Date" } ], - "tokenExemptedMethods": [], - "filterByStoreIdentifier": false + "tokenExemptedMethods": [] } ] } diff --git a/PadelClub/Data/Gen/Event.json b/PadelClub/Data/Gen/Event.json index 3cb0533..0fa8d00 100644 --- a/PadelClub/Data/Gen/Event.json +++ b/PadelClub/Data/Gen/Event.json @@ -42,8 +42,7 @@ "defaultValue": "nil" } ], - "tokenExemptedMethods": [], - "filterByStoreIdentifier": false + "tokenExemptedMethods": [] } ] } diff --git a/PadelClub/Data/Gen/GroupStage.json b/PadelClub/Data/Gen/GroupStage.json index ef61cf2..ecfdad5 100644 --- a/PadelClub/Data/Gen/GroupStage.json +++ b/PadelClub/Data/Gen/GroupStage.json @@ -47,8 +47,7 @@ "defaultValue": "0" } ], - "tokenExemptedMethods": [], - "filterByStoreIdentifier": true + "tokenExemptedMethods": [] } ] } diff --git a/PadelClub/Data/Gen/Match.json b/PadelClub/Data/Gen/Match.json index 0da44c6..913014c 100644 --- a/PadelClub/Data/Gen/Match.json +++ b/PadelClub/Data/Gen/Match.json @@ -5,7 +5,6 @@ "synchronizable": true, "observable": true, "tokenExemptedMethods": [], - "filterByStoreIdentifier": true, "properties": [ { "name": "id", diff --git a/PadelClub/Data/Gen/MatchScheduler.json b/PadelClub/Data/Gen/MatchScheduler.json index 500bc3d..34eeb63 100644 --- a/PadelClub/Data/Gen/MatchScheduler.json +++ b/PadelClub/Data/Gen/MatchScheduler.json @@ -6,7 +6,6 @@ "synchronizable": false, "observable": true, "tokenExemptedMethods": [], - "filterByStoreIdentifier": false, "properties": [ { "name": "id", diff --git a/PadelClub/Data/Gen/MonthData.json b/PadelClub/Data/Gen/MonthData.json index 95c4d9b..896038f 100644 --- a/PadelClub/Data/Gen/MonthData.json +++ b/PadelClub/Data/Gen/MonthData.json @@ -6,7 +6,6 @@ "synchronizable": false, "observable": true, "tokenExemptedMethods": [], - "filterByStoreIdentifier": false, "properties": [ { "name": "id", diff --git a/PadelClub/Data/Gen/PlayerRegistration.json b/PadelClub/Data/Gen/PlayerRegistration.json index c1a58e1..77302ef 100644 --- a/PadelClub/Data/Gen/PlayerRegistration.json +++ b/PadelClub/Data/Gen/PlayerRegistration.json @@ -4,7 +4,6 @@ "name": "PlayerRegistration", "synchronizable": true, "sideStorable": true, - "filterByStoreIdentifier": true, "observable": true, "relationshipNames": ["teamRegistration"], "properties": [ diff --git a/PadelClub/Data/Gen/Purchase.json b/PadelClub/Data/Gen/Purchase.json index 1ce7169..a8dd49b 100644 --- a/PadelClub/Data/Gen/Purchase.json +++ b/PadelClub/Data/Gen/Purchase.json @@ -45,7 +45,6 @@ } ], "tokenExemptedMethods": [], - "filterByStoreIdentifier": false, "relationshipNames": [] } ] diff --git a/PadelClub/Data/Gen/Round.json b/PadelClub/Data/Gen/Round.json index 1464de5..48a6cf7 100644 --- a/PadelClub/Data/Gen/Round.json +++ b/PadelClub/Data/Gen/Round.json @@ -4,7 +4,6 @@ "name": "Round", "synchronizable": true, "sideStorable": true, - "filterByStoreIdentifier": true, "observable": true, "relationshipNames": [], "properties": [ diff --git a/PadelClub/Data/Gen/TeamRegistration.json b/PadelClub/Data/Gen/TeamRegistration.json index d9b74a7..995d08e 100644 --- a/PadelClub/Data/Gen/TeamRegistration.json +++ b/PadelClub/Data/Gen/TeamRegistration.json @@ -4,7 +4,6 @@ "name": "TeamRegistration", "synchronizable": true, "sideStorable": true, - "filterByStoreIdentifier": true, "observable": true, "relationshipNames": [], "properties": [ diff --git a/PadelClub/Data/Gen/TeamScore.json b/PadelClub/Data/Gen/TeamScore.json index 8257a86..9165c44 100644 --- a/PadelClub/Data/Gen/TeamScore.json +++ b/PadelClub/Data/Gen/TeamScore.json @@ -4,7 +4,6 @@ "name": "TeamScore", "synchronizable": true, "sideStorable": true, - "filterByStoreIdentifier": true, "observable": true, "relationshipNames": ["match"], "properties": [ diff --git a/PadelClub/Data/Gen/Tournament.json b/PadelClub/Data/Gen/Tournament.json index 43c734f..c2ade84 100644 --- a/PadelClub/Data/Gen/Tournament.json +++ b/PadelClub/Data/Gen/Tournament.json @@ -4,7 +4,6 @@ "name": "Tournament", "synchronizable": true, "copyable": true, - "filterByStoreIdentifier": false, "observable": true, "relationshipNames": [], "properties": [ diff --git a/PadelClub/Data/Gen/generator.py b/PadelClub/Data/Gen/generator.py index fc2b74e..a8ece00 100644 --- a/PadelClub/Data/Gen/generator.py +++ b/PadelClub/Data/Gen/generator.py @@ -24,7 +24,6 @@ class SwiftModelGenerator: resource = self.make_resource_name(model_name) resource_name = model_data.get("resource_name", resource) token_exempted = model_data.get("tokenExemptedMethods", []) - filter_by_store = model_data.get("filterByStoreIdentifier", False) lines = ["// Generated by SwiftModelGenerator", "// Do not modify this file manually", ""] @@ -44,7 +43,7 @@ class SwiftModelGenerator: lines.append("") # Add SyncedStorable protocol requirements - lines.extend(self._generate_protocol_requirements(resource_name, token_exempted, filter_by_store)) + lines.extend(self._generate_protocol_requirements(resource_name, token_exempted)) lines.append("") # Properties @@ -347,7 +346,7 @@ class SwiftModelGenerator: lines.append(" }") return lines - def _generate_protocol_requirements(self, resource_name: str, token_exempted: List[str], filter_by_store: bool) -> List[str]: + def _generate_protocol_requirements(self, resource_name: str, token_exempted: List[str]) -> List[str]: """Generate the static functions required by SyncedStorable protocol.""" # Convert HTTP methods to proper format formatted_methods = [f".{method.lower()}" for method in token_exempted] @@ -356,7 +355,6 @@ class SwiftModelGenerator: return [ f" static func resourceName() -> String {{ return \"{resource_name}\" }}", f" static func tokenExemptedMethods() -> [HTTPMethod] {{ return [{methods_str}] }}", - f" static func filterByStoreIdentifier() -> Bool {{ return {str(filter_by_store).lower()} }}" ] def _generate_relationships(self, model_name, properties: List[Dict[str, Any]]) -> List[str]: diff --git a/PadelClub/Views/Navigation/Agenda/EventListView.swift b/PadelClub/Views/Navigation/Agenda/EventListView.swift index eb848e7..7743ff5 100644 --- a/PadelClub/Views/Navigation/Agenda/EventListView.swift +++ b/PadelClub/Views/Navigation/Agenda/EventListView.swift @@ -121,13 +121,7 @@ struct EventListView: View { NavigationLink(value: tournament) { TournamentCellView(tournament: tournament) .popover(isPresented: self.$showUserSearch) { - UserSearchView { user in - do { - try StoreCenter.main.giveUserAccess(user.id, data: tournament) - } catch { - Logger.error(error) - } - } + ShareModelView(instance: tournament) } } .contextMenu { diff --git a/PadelClub/Views/Tournament/TournamentView.swift b/PadelClub/Views/Tournament/TournamentView.swift index f3c9992..ebe7651 100644 --- a/PadelClub/Views/Tournament/TournamentView.swift +++ b/PadelClub/Views/Tournament/TournamentView.swift @@ -112,13 +112,7 @@ struct TournamentView: View { case .print: PrintSettingsView(tournament: tournament) case .share: - UserSearchView { user in - do { - try StoreCenter.main.giveUserAccess(user.id, data: tournament) - } catch { - Logger.error(error) - } - } + ShareModelView(instance: tournament) } } .environment(tournament) diff --git a/PadelClub/Views/User/ShareModelView.swift b/PadelClub/Views/User/ShareModelView.swift new file mode 100644 index 0000000..90c6a45 --- /dev/null +++ b/PadelClub/Views/User/ShareModelView.swift @@ -0,0 +1,113 @@ +// +// UserSearchView.swift +// PadelClub +// +// Created by Laurent Morvillier on 03/12/2024. +// + +import Combine +import LeStorage +import SwiftUI + +class UserSearchViewModel: ObservableObject { + + @Published var searchText = "" + @Published var userNames: [ShortUser] = [] + + @Published var users: [String] = [] + @Published var availableUsers: [ShortUser] = [] + @Published var selectedUsers: [String] = [] + + init() { + Task { + do { + let service = try StoreCenter.main.service() + let userNames = try await service.getUserNames() + DispatchQueue.main.async { + self.userNames = userNames + self.availableUsers = self.users.compactMap { userId in + self.userNames.first(where: { $0.id == userId }) + } + } + } catch { + Logger.error(error) + } + } + } + + func userTapped(_ user: String) { + if let index = self.selectedUsers.firstIndex(of: user) { + self.selectedUsers.remove(at: index) + } else { + self.selectedUsers.append(user) + } + } + + func contains(_ user: String) -> Bool { + return self.selectedUsers.firstIndex(of: user) != nil + } +} + +struct ShareModelView : View { + @StateObject private var viewModel = UserSearchViewModel() + + let instance: T + + var body: some View { + NavigationView { + if !self.viewModel.availableUsers.isEmpty { + List { + ForEach(self.viewModel.availableUsers, id: \.id) { user in + let isSelected = viewModel.contains(user.id) + UserRow(user: user, isSelected: isSelected) + .contentShape(Rectangle()) + .onTapGesture { + self.viewModel.userTapped(user.id) + self._modifyAuthorizedUsersList() + } + } + } + .listStyle(PlainListStyle()) + .navigationTitle("Partage") + } else { + ContentUnavailableView("Si vous souhaitez partager votre tournoi avec d'autres utilisateurs, veuillez contacter notre support", image: "person.fill.xmark") + } + + }.onAppear { + self.viewModel.selectedUsers = StoreCenter.main.authorizedUsers(for: self.instance.stringId) + self.viewModel.users = DataStore.shared.user.agents + } + } + + fileprivate func _modifyAuthorizedUsersList() { + do { + try StoreCenter.main.setAuthorizedUsers(for: self.instance, users: self.viewModel.selectedUsers) + } catch { + Logger.error(error) + } + + } +} + +struct UserRow: View { + let user: ShortUser + let isSelected: Bool + + var body: some View { + HStack { + Text("\(user.firstName) \(user.lastName)") + Spacer() + if self.isSelected { + Image(systemName: "checkmark").foregroundStyle(.logoOrange) + } + } + .padding(.vertical, 4) + } +} + +// Preview provider +struct ShareModelView_Previews: PreviewProvider { + static var previews: some View { + ShareModelView(instance: Tournament.fake()) + } +} diff --git a/PadelClub/Views/User/UserSearchView.swift b/PadelClub/Views/User/UserSearchView.swift deleted file mode 100644 index 809a5d0..0000000 --- a/PadelClub/Views/User/UserSearchView.swift +++ /dev/null @@ -1,168 +0,0 @@ -// -// UserSearchView.swift -// PadelClub -// -// Created by Laurent Morvillier on 03/12/2024. -// - -import Combine -import LeStorage -import SwiftUI - -class UserSearchViewModel: ObservableObject { - @Published var searchText = "" - @Published var users: [ShortUser] = [] - @Published var isLoading = false - @Published var error: String? - @Published var selectedUser: ShortUser? = nil - - private var cancellables = Set() - private var originalUsers: [ShortUser] = [] - private var lastSearchTerm = "" - - init() { - // Debounce search to avoid too many requests - $searchText - .removeDuplicates() - .debounce(for: .milliseconds(300), scheduler: RunLoop.main) - .sink { [weak self] searchTerm in - self?.handleSearch(searchTerm) - } - .store(in: &cancellables) - } - - private func handleSearch(_ searchTerm: String) { - guard !searchTerm.isEmpty else { - users = [] - return - } - - // If going backwards in search, filter existing results - if searchTerm.count < lastSearchTerm.count && !originalUsers.isEmpty { - filterExistingResults(searchTerm) - return - } - - // Otherwise, make a new request - performServerSearch(searchTerm) - } - - private func filterExistingResults(_ searchTerm: String) { - users = originalUsers.filter { user in - user.firstName.localizedCaseInsensitiveContains(searchTerm) - || user.lastName.localizedCaseInsensitiveContains(searchTerm) - } - } - - private func performServerSearch(_ searchTerm: String) { - isLoading = true - error = nil - - Task { - do { - let services = try StoreCenter.main.service() - let searchResults = try await services.searchUsers(string: searchTerm) - - await MainActor.run { - self.originalUsers = searchResults - self.users = searchResults - self.lastSearchTerm = searchTerm - self.isLoading = false - } - } catch { - await MainActor.run { - self.error = error.localizedDescription - self.isLoading = false - } - } - } - } -} - -struct UserSearchView: View { - @StateObject private var viewModel = UserSearchViewModel() - - var handler: (ShortUser) -> Void - - var body: some View { - NavigationView { - VStack { - searchField - - if viewModel.isLoading { - loadingView - } else if let error = viewModel.error { - errorView(error) - } else { - List { - ForEach(viewModel.users, id: \.id) { user in - let isSelected = (user.id == viewModel.selectedUser?.id) - UserRow(user: user, isSelected: isSelected) - .contentShape(Rectangle()) - .onTapGesture { - viewModel.selectedUser = user - } - } - } - .listStyle(PlainListStyle()) - } - } - .navigationTitle("Search Users") - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button("Select") { - if let selectedUser = viewModel.selectedUser { - handler(selectedUser) - } - } - .disabled(viewModel.selectedUser == nil) - } - } - } - } - - private var searchField: some View { - TextField("Search users...", text: $viewModel.searchText) - .textFieldStyle(RoundedBorderTextFieldStyle()) - .padding() - } - - private var loadingView: some View { - ProgressView() - .progressViewStyle(CircularProgressViewStyle()) - .scaleEffect(1.5) - .frame(maxHeight: .infinity) - } - - private func errorView(_ error: String) -> some View { - Text(error) - .foregroundColor(.red) - .frame(maxHeight: .infinity) - } - -} - -struct UserRow: View { - let user: ShortUser - let isSelected: Bool - - var body: some View { - HStack { - Text("\(user.firstName) \(user.lastName)") - Spacer() - if self.isSelected { - Image(systemName: "checkmark").tint(.logoOrange) - } - } - .padding(.vertical, 4) - } -} - -// Preview provider -struct UserSearchView_Previews: PreviewProvider { - static var previews: some View { - UserSearchView { user in - - } - } -}