Merge remote-tracking branch 'refs/remotes/origin/main'

sync_v2
Raz 7 months ago
commit 0db09bc475
  1. 33
      PadelClub/Data/DataStore.swift
  2. 29
      PadelClub/Data/Tournament.swift
  3. 23
      PadelClub/Data/TournamentStore.swift
  4. 7
      PadelClub/Utils/Patcher.swift
  5. 2
      PadelClub/Views/Navigation/Agenda/EventListView.swift
  6. 5
      PadelClub/Views/Navigation/Toolbox/DebugSettingsView.swift
  7. 106
      PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift
  8. 20
      PadelClub/Views/Tournament/Subscription/Guard.swift
  9. 2
      PadelClub/Views/Tournament/Subscription/Purchase.swift

@ -15,17 +15,14 @@ class DataStore: ObservableObject {
@Published var user: CustomUser = CustomUser.placeHolder() { @Published var user: CustomUser = CustomUser.placeHolder() {
didSet { didSet {
let loggedUser = StoreCenter.main.userId != nil let loggedUser = StoreCenter.main.isAuthenticated
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 StoreCenter.main.collectionsCanSynchronize { StoreCenter.main.initialSynchronization(clear: false)
StoreCenter.main.initialSynchronization() self._fixMissingClubCreatorIfNecessary(self.clubs)
self._fixMissingClubCreatorIfNecessary(self.clubs) self._fixMissingEventCreatorIfNecessary(self.events)
self._fixMissingEventCreatorIfNecessary(self.events)
}
} }
} else { } else {
self._temporaryLocalUser.item = self.user self._temporaryLocalUser.item = self.user
@ -33,13 +30,13 @@ class DataStore: ObservableObject {
} }
} }
fileprivate(set) var tournaments: StoredCollection<Tournament> fileprivate(set) var tournaments: SyncedCollection<Tournament>
fileprivate(set) var clubs: StoredCollection<Club> fileprivate(set) var clubs: SyncedCollection<Club>
fileprivate(set) var courts: StoredCollection<Court> fileprivate(set) var courts: SyncedCollection<Court>
fileprivate(set) var events: StoredCollection<Event> fileprivate(set) var events: SyncedCollection<Event>
fileprivate(set) var monthData: StoredCollection<MonthData> fileprivate(set) var monthData: StoredCollection<MonthData>
fileprivate(set) var dateIntervals: StoredCollection<DateInterval> fileprivate(set) var dateIntervals: SyncedCollection<DateInterval>
fileprivate(set) var purchases: StoredCollection<Purchase> fileprivate(set) var purchases: SyncedCollection<Purchase>
fileprivate var userStorage: StoredSingleton<CustomUser> fileprivate var userStorage: StoredSingleton<CustomUser>
@ -127,9 +124,9 @@ class DataStore: ObservableObject {
if let userSingleton: StoredSingleton<CustomUser> = notification.object as? StoredSingleton<CustomUser> { if let userSingleton: StoredSingleton<CustomUser> = notification.object as? StoredSingleton<CustomUser> {
self.user = userSingleton.item() ?? self._temporaryLocalUser.item ?? CustomUser.placeHolder() self.user = userSingleton.item() ?? self._temporaryLocalUser.item ?? CustomUser.placeHolder()
} else if let clubsCollection: StoredCollection<Club> = notification.object as? StoredCollection<Club> { } else if let clubsCollection: SyncedCollection<Club> = notification.object as? SyncedCollection<Club> {
self._fixMissingClubCreatorIfNecessary(clubsCollection) self._fixMissingClubCreatorIfNecessary(clubsCollection)
} else if let eventsCollection: StoredCollection<Event> = notification.object as? StoredCollection<Event> { } else if let eventsCollection: SyncedCollection<Event> = notification.object as? SyncedCollection<Event> {
self._fixMissingEventCreatorIfNecessary(eventsCollection) self._fixMissingEventCreatorIfNecessary(eventsCollection)
} }
@ -139,7 +136,7 @@ class DataStore: ObservableObject {
} }
fileprivate func _fixMissingClubCreatorIfNecessary(_ clubsCollection: StoredCollection<Club>) { fileprivate func _fixMissingClubCreatorIfNecessary(_ clubsCollection: SyncedCollection<Club>) {
for club in clubsCollection { for club in clubsCollection {
if let userId = StoreCenter.main.userId, club.creator == nil { if let userId = StoreCenter.main.userId, club.creator == nil {
club.creator = userId club.creator = userId
@ -150,7 +147,7 @@ class DataStore: ObservableObject {
} }
} }
fileprivate func _fixMissingEventCreatorIfNecessary(_ eventsCollection: StoredCollection<Event>) { fileprivate func _fixMissingEventCreatorIfNecessary(_ eventsCollection: SyncedCollection<Event>) {
for event in eventsCollection { for event in eventsCollection {
if let userId = StoreCenter.main.userId, event.creator == nil { if let userId = StoreCenter.main.userId, event.creator == nil {
event.creator = userId event.creator = userId
@ -224,8 +221,6 @@ class DataStore: ObservableObject {
fileprivate func _localDisconnect() { fileprivate func _localDisconnect() {
StoreCenter.main.collectionsCanSynchronize = false
let tournamendIds: [String] = self.tournaments.map { $0.id } let tournamendIds: [String] = self.tournaments.map { $0.id }
TournamentLibrary.shared.reset() TournamentLibrary.shared.reset()

@ -2406,17 +2406,24 @@ defer {
func insertOnServer() throws { func insertOnServer() throws {
// DataStore.shared.tournaments.writeChangeAndInsertOnServer(instance: self) DataStore.shared.tournaments.writeChangeAndInsertOnServer(instance: self)
//
// for teamRegistration in self.tournamentStore?.teamRegistrations { if let teamRegistrations = self.tournamentStore?.teamRegistrations {
// teamRegistration.insertOnServer() for teamRegistration in teamRegistrations {
// } teamRegistration.insertOnServer()
// for groupStage in self.tournamentStore?.groupStages { }
// groupStage.insertOnServer() }
// }
// for round in self.tournamentStore.rounds { if let groupStages = self.tournamentStore?.groupStages {
// round.insertOnServer() for groupStage in groupStages {
// } groupStage.insertOnServer()
}
}
if let rounds = self.tournamentStore?.rounds {
for round in rounds {
round.insertOnServer()
}
}
} }

@ -13,15 +13,15 @@ class TournamentStore: ObservableObject {
var store: Store var store: Store
fileprivate(set) var groupStages: StoredCollection<GroupStage> = StoredCollection.placeholder() fileprivate(set) var groupStages: SyncedCollection<GroupStage> = SyncedCollection.placeholder()
fileprivate(set) var matches: StoredCollection<Match> = StoredCollection.placeholder() fileprivate(set) var matches: SyncedCollection<Match> = SyncedCollection.placeholder()
fileprivate(set) var teamRegistrations: StoredCollection<TeamRegistration> = StoredCollection.placeholder() fileprivate(set) var teamRegistrations: SyncedCollection<TeamRegistration> = SyncedCollection.placeholder()
fileprivate(set) var playerRegistrations: StoredCollection<PlayerRegistration> = StoredCollection.placeholder() fileprivate(set) var playerRegistrations: SyncedCollection<PlayerRegistration> = SyncedCollection.placeholder()
fileprivate(set) var rounds: StoredCollection<Round> = StoredCollection.placeholder() fileprivate(set) var rounds: SyncedCollection<Round> = SyncedCollection.placeholder()
fileprivate(set) var teamScores: StoredCollection<TeamScore> = StoredCollection.placeholder() fileprivate(set) var teamScores: SyncedCollection<TeamScore> = SyncedCollection.placeholder()
fileprivate(set) var matchSchedulers: StoredCollection<MatchScheduler> = StoredCollection.placeholder() fileprivate(set) var matchSchedulers: StoredCollection<MatchScheduler> = StoredCollection.placeholder()
fileprivate(set) var drawLogs: StoredCollection<DrawLog> = StoredCollection.placeholder() fileprivate(set) var drawLogs: SyncedCollection<DrawLog> = SyncedCollection.placeholder()
// convenience init(tournament: Tournament) { // convenience init(tournament: Tournament) {
// let store = StoreCenter.main.store(identifier: tournament.id) // let store = StoreCenter.main.store(identifier: tournament.id)
@ -36,15 +36,8 @@ class TournamentStore: ObservableObject {
fileprivate func _initialize() { fileprivate func _initialize() {
var synchronized: Bool = true
let indexed: Bool = true let indexed: Bool = true
#if DEBUG
if let sync = PListReader.readBool(plist: "local", key: "synchronized") {
synchronized = sync
}
#endif
self.groupStages = self.store.registerSynchronizedCollection(indexed: indexed) self.groupStages = self.store.registerSynchronizedCollection(indexed: indexed)
self.rounds = self.store.registerSynchronizedCollection(indexed: indexed) self.rounds = self.store.registerSynchronizedCollection(indexed: indexed)
self.teamRegistrations = self.store.registerSynchronizedCollection(indexed: indexed) self.teamRegistrations = self.store.registerSynchronizedCollection(indexed: indexed)
@ -52,7 +45,7 @@ class TournamentStore: ObservableObject {
self.matches = self.store.registerSynchronizedCollection(indexed: indexed) self.matches = self.store.registerSynchronizedCollection(indexed: indexed)
self.teamScores = self.store.registerSynchronizedCollection(indexed: indexed) self.teamScores = self.store.registerSynchronizedCollection(indexed: indexed)
self.matchSchedulers = self.store.registerCollection(indexed: indexed) self.matchSchedulers = self.store.registerCollection(indexed: indexed)
self.drawLogs = self.store.registerCollection(indexed: indexed) self.drawLogs = self.store.registerSynchronizedCollection(indexed: indexed)
self.store.loadCollectionsFromServerIfNoFile() self.store.loadCollectionsFromServerIfNoFile()

@ -54,6 +54,7 @@ enum Patch: String, CaseIterable {
case cleanLogs case cleanLogs
case syncUpgrade case syncUpgrade
case updateTournaments case updateTournaments
case cleanPurchaseApiCalls
var id: String { var id: String {
return "padelclub.app.patch.\(self.rawValue)" return "padelclub.app.patch.\(self.rawValue)"
@ -85,6 +86,7 @@ class AutomaticPatcher {
case .cleanLogs: self._cleanLogs() case .cleanLogs: self._cleanLogs()
case .syncUpgrade: self._syncUpgrade() case .syncUpgrade: self._syncUpgrade()
case .updateTournaments: self._updateTournaments() case .updateTournaments: self._updateTournaments()
case .cleanPurchaseApiCalls: self._cleanPurchaseApiCalls()
} }
} }
@ -133,4 +135,9 @@ class AutomaticPatcher {
fileprivate static func _updateTournaments() { fileprivate static func _updateTournaments() {
DataStore.shared.tournaments.addOrUpdate(contentOfs: DataStore.shared.tournaments) DataStore.shared.tournaments.addOrUpdate(contentOfs: DataStore.shared.tournaments)
} }
fileprivate static func _cleanPurchaseApiCalls() {
StoreCenter.main.resetApiCalls(type: Purchase.self)
}
} }

@ -314,7 +314,7 @@ struct EventListView: View {
TournamentCellView(tournament: tournament) TournamentCellView(tournament: tournament)
.onReceive(NotificationCenter.default.publisher(for: NSNotification.Name.CollectionDidLoad), perform: { notification in .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name.CollectionDidLoad), perform: { notification in
if let store = notification.object as? StoredCollection<TeamRegistration> { if let store = notification.object as? SyncedCollection<TeamRegistration> {
if store.storeId == tournament.id { if store.storeId == tournament.id {
tournament.lastTeamRefresh = Date() tournament.lastTeamRefresh = Date()
} }

@ -25,7 +25,6 @@ struct DebugSettingsView: View {
LabeledContent("Token", value: self._token) LabeledContent("Token", value: self._token)
LabeledContent("Server", value: self._apiURL) LabeledContent("Server", value: self._apiURL)
LabeledContent("Synchronized", value: self._synchronized) LabeledContent("Synchronized", value: self._synchronized)
LabeledContent("CollectionsCanSynchronize", value: self._canSynchronize)
} }
} }
} }
@ -55,10 +54,6 @@ struct DebugSettingsView: View {
} }
} }
fileprivate var _canSynchronize: String {
return "\(StoreCenter.main.collectionsCanSynchronize)"
}
fileprivate var _wsPingStatus: String { fileprivate var _wsPingStatus: String {
return "\(StoreCenter.main.websocketPingStatus)" return "\(StoreCenter.main.websocketPingStatus)"
} }

@ -1048,59 +1048,59 @@ struct InscriptionManagerView: View {
} }
} }
@ViewBuilder // @ViewBuilder
private func _prioritizeClubMembersButton() -> some View { // private func _prioritizeClubMembersButton() -> some View {
@Bindable var tournament = tournament // @Bindable var tournament = tournament
if let federalClub = tournament.club() { // if let federalClub = tournament.club() {
Menu { // Menu {
Picker(selection: $tournament.prioritizeClubMembers) { // Picker(selection: $tournament.prioritizeClubMembers) {
Text("Oui").tag(true) // Text("Oui").tag(true)
Text("Non").tag(false) // Text("Non").tag(false)
} label: { // } label: {
//
} // }
.labelsHidden() // .labelsHidden()
//
Divider() // Divider()
NavigationLink { // NavigationLink {
ClubsView() { club in // ClubsView() { club in
if let event = tournament.eventObject() { // if let event = tournament.eventObject() {
event.club = club.id // event.club = club.id
do { // do {
try dataStore.events.addOrUpdate(instance: event) // try dataStore.events.addOrUpdate(instance: event)
} catch { // } catch {
Logger.error(error) // Logger.error(error)
} // }
} // }
_save() // _save()
} // }
} label: { // } label: {
Text("Changer de club") // Text("Changer de club")
} // }
} label: { // } label: {
Text("Membres prioritaires") // Text("Membres prioritaires")
Text(federalClub.acronym) // Text(federalClub.acronym)
} // }
Divider() // Divider()
} else { // } else {
NavigationLink { // NavigationLink {
ClubsView() { club in // ClubsView() { club in
if let event = tournament.eventObject() { // if let event = tournament.eventObject() {
event.club = club.id // event.club = club.id
do { // do {
try dataStore.events.addOrUpdate(instance: event) // try dataStore.events.addOrUpdate(instance: event)
} catch { // } catch {
Logger.error(error) // Logger.error(error)
} // }
} // }
_save() // _save()
} // }
} label: { // } label: {
Text("Identifier le club") // Text("Identifier le club")
} // }
Divider() // Divider()
} // }
} // }
private func _teamFooterView(_ team: TeamRegistration) -> some View { private func _teamFooterView(_ team: TeamRegistration) -> some View {
HStack { HStack {

@ -187,18 +187,18 @@ import LeStorage
} }
var currentPlan: StoreItem? { var currentPlan: StoreItem? {
#if DEBUG // #if DEBUG
return .monthlyUnlimited // return .monthlyUnlimited
#elseif TESTFLIGHT // #elseif TESTFLIGHT
return .monthlyUnlimited // return .monthlyUnlimited
#elseif PRODTEST // #elseif PRODTEST
return .monthlyUnlimited // return .monthlyUnlimited
#else // #else
if let currentBestPurchase = self.currentBestPurchase, let plan = StoreItem(rawValue: currentBestPurchase.productId) { if let currentBestPurchase = self.currentBestPurchase, let plan = StoreItem(rawValue: currentBestPurchase.productId) {
return plan return plan
} }
return nil return nil
#endif // #endif
} }
func userFilteredPurchases() -> [StoreKit.Transaction] { func userFilteredPurchases() -> [StoreKit.Transaction] {
@ -316,8 +316,8 @@ fileprivate extension StoreKit.Transaction {
throw StoreError.missingUserId throw StoreError.missingUserId
} }
return Purchase(user: userId, return Purchase(transactionId: self.originalID,
transactionId: self.originalID, user: userId,
purchaseDate: self.purchaseDate, purchaseDate: self.purchaseDate,
productId: self.productID, productId: self.productID,
quantity: self.purchasedQuantity, quantity: self.purchasedQuantity,

@ -24,7 +24,7 @@ class Purchase: BasePurchase {
// var revocationDate: Date? = nil // var revocationDate: Date? = nil
// var expirationDate: Date? = nil // var expirationDate: Date? = nil
init(user: String, transactionId: UInt64, purchaseDate: Date, productId: String, quantity: Int? = nil, revocationDate: Date? = nil, expirationDate: Date? = nil) { init(transactionId: UInt64, user: String, purchaseDate: Date, productId: String, quantity: Int? = nil, revocationDate: Date? = nil, expirationDate: Date? = nil) {
super.init(id: transactionId, user: user, purchaseDate: purchaseDate, productId: productId, quantity: quantity, revocationDate: revocationDate, expirationDate: expirationDate) super.init(id: transactionId, user: user, purchaseDate: purchaseDate, productId: productId, quantity: quantity, revocationDate: revocationDate, expirationDate: expirationDate)
// self.id = transactionId // self.id = transactionId

Loading…
Cancel
Save