Make system to manage a local User before having a logged one

multistore
Laurent 2 years ago
parent 95d0ceac0b
commit d19b679656
  1. 2
      PadelClub/Data/AppSettings.swift
  2. 50
      PadelClub/Data/DataStore.swift
  3. 14
      PadelClub/Data/User.swift
  4. 2
      PadelClub/Info.plist
  5. 6
      PadelClub/Views/Calling/CallMessageCustomizationView.swift
  6. 16
      PadelClub/Views/Club/ClubDetailView.swift
  7. 2
      PadelClub/Views/Club/ClubSearchView.swift
  8. 10
      PadelClub/Views/Club/CreateClubView.swift
  9. 6
      PadelClub/Views/Navigation/Toolbox/GlobalSettingsView.swift
  10. 6
      PadelClub/Views/Navigation/Toolbox/MatchFormatStorageView.swift
  11. 8
      PadelClub/Views/Navigation/Umpire/UmpireView.swift
  12. 3
      PadelClub/Views/Subscription/Guard.swift
  13. 4
      PadelClub/Views/Subscription/PurchaseListView.swift
  14. 1
      PadelClub/Views/Subscription/StoreManager.swift
  15. 17
      PadelClub/Views/Subscription/SubscriptionView.swift
  16. 1
      PadelClub/Views/User/UserCreationView.swift

@ -12,8 +12,6 @@ import SwiftUI
@Observable @Observable
class AppSettings: MicroStorable { class AppSettings: MicroStorable {
static var fileName: String { "appsettings.json" }
var lastDataSource: String? = nil var lastDataSource: String? = nil
var callMessageBody : String? = nil var callMessageBody : String? = nil

@ -16,16 +16,18 @@ class DataStore: ObservableObject {
@Published var user: User = User.placeHolder() { @Published var user: User = User.placeHolder() {
didSet { didSet {
Store.main.collectionsCanSynchronize = (user.username.count > 0) let loggedUser = (user.username.count > 0)
do { Store.main.collectionsCanSynchronize = loggedUser
if loggedUser {
if self.user.id != self.userStorage.item()?.id { if self.user.id != self.userStorage.item()?.id {
try self.userStorage.setItemNoSync(self.user) self.userStorage.setItemNoSync(self.user)
if Store.main.collectionsCanSynchronize { if Store.main.collectionsCanSynchronize {
Store.main.loadCollectionFromServer() Store.main.loadCollectionFromServer()
} }
} }
} catch { } else {
Logger.error(error) self._temporaryLocalUser.item = self.user
} }
} }
} }
@ -44,10 +46,10 @@ class DataStore: ObservableObject {
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(set) var userStorage: StoredSingleton<User> fileprivate var userStorage: StoredSingleton<User>
// fileprivate var _userStorage: OptionalStorage<User> = OptionalStorage<User>(fileName: "user.json") fileprivate var _temporaryLocalUser: OptionalStorage<User> = OptionalStorage(fileName: "tmp_local_user.json")
fileprivate(set) var appSettingsStorage: MicroStorage<AppSettings> = MicroStorage() fileprivate(set) var appSettingsStorage: MicroStorage<AppSettings> = MicroStorage(fileName: "appsettings.json")
var appSettings: AppSettings { var appSettings: AppSettings {
appSettingsStorage.item appSettingsStorage.item
@ -57,6 +59,8 @@ class DataStore: ObservableObject {
let store = Store.main let store = Store.main
store.synchronizationApiURL = "https://xlr.alwaysdata.net/api/" store.synchronizationApiURL = "https://xlr.alwaysdata.net/api/"
var synchronized : Bool = true var synchronized : Bool = true
self.user = User.placeHolder() // force the didSet
#if DEBUG #if DEBUG
if let server = PListReader.readString(plist: "local", key: "server") { if let server = PListReader.readString(plist: "local", key: "server") {
@ -91,14 +95,32 @@ class DataStore: ObservableObject {
} }
func saveUser() {
do {
if user.username.count > 0 {
try self.userStorage.update()
} else {
self._temporaryLocalUser.item = self.user
}
} catch {
Logger.error(error)
}
}
@objc func collectionDidLoad(notification: Notification) { @objc func collectionDidLoad(notification: Notification) {
self.objectWillChange.send() self.objectWillChange.send()
if let object: StoredSingleton<User> = notification.object as? StoredSingleton<User> { if let userSingleton: StoredSingleton<User> = notification.object as? StoredSingleton<User> {
Logger.log("StoredObject<User> loaded with user = \(String(describing: object.item()))") Logger.log("StoredObject<User> loaded with user = \(String(describing: userSingleton.item()))")
if let user = object.item() { self.user = userSingleton.item() ?? User.placeHolder()
self.user = user // if let user = object.item() {
} // self.user = user
// } else {
// self.
// }
} }
} }
@ -112,6 +134,8 @@ class DataStore: ObservableObject {
// todo qu'est ce qu'on fait des API Call ? // todo qu'est ce qu'on fait des API Call ?
} }
self.user = self._temporaryLocalUser.item ?? User.placeHolder()
Store.main.disconnect() Store.main.disconnect()
Store.main.collectionsCanSynchronize = false Store.main.collectionsCanSynchronize = false

@ -130,9 +130,21 @@ class User: ModelObject, UserBase, Storable {
class UserCreationForm: User, UserPasswordBase { class UserCreationForm: User, UserPasswordBase {
init(username: String, password: String, firstName: String, lastName: String, email: String, phone: String?, country: String?) { init(user: User, username: String, password: String, firstName: String, lastName: String, email: String, phone: String?, country: String?) {
self.password = password self.password = password
super.init(username: username, email: email, firstName: firstName, lastName: lastName, phone: phone, country: country) super.init(username: username, email: email, firstName: firstName, lastName: lastName, phone: phone, country: country)
self.summonsMessageBody = user.summonsMessageBody
self.summonsMessageSignature = user.summonsMessageSignature
self.summonsAvailablePaymentMethods = user.summonsAvailablePaymentMethods
self.summonsDisplayFormat = user.summonsDisplayFormat
self.summonsDisplayEntryFee = user.summonsDisplayEntryFee
self.summonsUseFullCustomMessage = user.summonsUseFullCustomMessage
self.matchFormatsDefaultDuration = user.matchFormatsDefaultDuration
self.bracketMatchFormatPreference = user.bracketMatchFormatPreference
self.groupStageMatchFormatPreference = user.groupStageMatchFormatPreference
self.loserBracketMatchFormatPreference = user.loserBracketMatchFormatPreference
} }
required init(from decoder: Decoder) throws { required init(from decoder: Decoder) throws {

@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>UIFileSharingEnabled</key>
<true/>
<key>CFBundleDocumentTypes</key> <key>CFBundleDocumentTypes</key>
<array> <array>
<dict> <dict>

@ -116,11 +116,7 @@ struct CallMessageCustomizationView: View {
} }
private func _save() { private func _save() {
do { self.dataStore.saveUser()
try dataStore.userStorage.update()
} catch {
Logger.error(error)
}
} }
@ViewBuilder @ViewBuilder

@ -154,7 +154,7 @@ struct ClubDetailView: View {
do { do {
try dataStore.clubs.deleteById(club.id) try dataStore.clubs.deleteById(club.id)
dataStore.user.clubs.removeAll(where: { $0 == club.id }) dataStore.user.clubs.removeAll(where: { $0 == club.id })
try dataStore.userStorage.update() self.dataStore.saveUser()
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -174,16 +174,12 @@ struct ClubDetailView: View {
let isFavorite = club.isFavorite() let isFavorite = club.isFavorite()
ToolbarItem(placement: .topBarTrailing) { ToolbarItem(placement: .topBarTrailing) {
BarButtonView("Favori", icon: isFavorite ? "star.fill" : "star") { BarButtonView("Favori", icon: isFavorite ? "star.fill" : "star") {
do { if isFavorite {
if isFavorite { dataStore.user.clubs.removeAll(where: { $0 == club.id })
dataStore.user.clubs.removeAll(where: { $0 == club.id }) } else {
} else { dataStore.user.clubs.append(club.id)
dataStore.user.clubs.append(club.id)
}
try dataStore.userStorage.update()
} catch {
Logger.error(error)
} }
self.dataStore.saveUser()
} }
.tint(isFavorite ? .green : .logoRed) .tint(isFavorite ? .green : .logoRed)
} }

@ -100,7 +100,7 @@ struct ClubSearchView: View {
try dataStore.clubs.addOrUpdate(instance: clubToEdit) try dataStore.clubs.addOrUpdate(instance: clubToEdit)
if dataStore.user.clubs.contains(where: { $0 == clubToEdit.id }) == false { if dataStore.user.clubs.contains(where: { $0 == clubToEdit.id }) == false {
dataStore.user.clubs.append(clubToEdit.id) dataStore.user.clubs.append(clubToEdit.id)
try dataStore.userStorage.update() self.dataStore.saveUser()
} }
} catch { } catch {
Logger.error(error) Logger.error(error)

@ -43,13 +43,9 @@ struct CreateClubView: View {
} }
//save into user //save into user
do { if dataStore.user.clubs.contains(where: { $0 == existingOrCreatedClub.id }) == false {
if dataStore.user.clubs.contains(where: { $0 == existingOrCreatedClub.id }) == false { dataStore.user.clubs.append(existingOrCreatedClub.id)
dataStore.user.clubs.append(existingOrCreatedClub.id) self.dataStore.saveUser()
try dataStore.userStorage.update()
}
} catch {
Logger.error(error)
} }
dismiss() dismiss()
} }

@ -59,11 +59,7 @@ struct GlobalSettingsView: View {
user.groupStageMatchFormatPreference, user.groupStageMatchFormatPreference,
user.loserBracketMatchFormatPreference user.loserBracketMatchFormatPreference
]) { ]) {
do { self.dataStore.saveUser()
try dataStore.userStorage.update()
} catch {
Logger.error(error)
}
} }
.navigationTitle("Formats par défaut") .navigationTitle("Formats par défaut")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)

@ -44,11 +44,7 @@ struct MatchFormatStorageView: View {
} }
.onChange(of: estimatedDuration) { .onChange(of: estimatedDuration) {
dataStore.user.saveMatchFormatsDefaultDuration(matchFormat, estimatedDuration: estimatedDuration) dataStore.user.saveMatchFormatsDefaultDuration(matchFormat, estimatedDuration: estimatedDuration)
do { self.dataStore.saveUser()
try dataStore.userStorage.update()
} catch {
Logger.error(error)
}
} }
} }
} }

@ -73,11 +73,7 @@ struct UmpireView: View {
} else { } else {
Button("supprimer", role: .destructive) { Button("supprimer", role: .destructive) {
dataStore.user.licenceId = nil dataStore.user.licenceId = nil
do { self.dataStore.saveUser()
try dataStore.userStorage.update()
} catch {
Logger.error(error)
}
} }
} }
} }
@ -168,7 +164,7 @@ struct UmpireView: View {
do { do {
try dataStore.clubs.addOrUpdate(instance: userClub) try dataStore.clubs.addOrUpdate(instance: userClub)
user.setUserClub(userClub) user.setUserClub(userClub)
try dataStore.userStorage.update() self.dataStore.saveUser()
} catch { } catch {
Logger.error(error) Logger.error(error)
} }

@ -216,11 +216,10 @@ import LeStorage
} }
struct PurchaseRow: Identifiable { struct PurchaseRow: Identifiable {
var id: UInt64
var name: String var name: String
var item: StoreItem var item: StoreItem
var quantity: Int? var quantity: Int?
var id: String { self.item.rawValue }
} }
fileprivate extension StoreKit.Transaction { fileprivate extension StoreKit.Transaction {

@ -61,7 +61,7 @@ class PurchaseManager: ObservableObject {
let product = self._products.first(where: { $0.id == item.rawValue } ) { let product = self._products.first(where: { $0.id == item.rawValue } ) {
switch item { switch item {
case .fivePerMonth, .monthlyUnlimited: case .fivePerMonth, .monthlyUnlimited:
rows.append(PurchaseRow(name: product.displayName, item: item)) rows.append(PurchaseRow(id: userPurchase.originalID, name: product.displayName, item: item))
case .unit: case .unit:
break break
} }
@ -73,7 +73,7 @@ class PurchaseManager: ObservableObject {
if remainingTournaments > 0 { if remainingTournaments > 0 {
let unitItem: StoreItem = StoreItem.unit let unitItem: StoreItem = StoreItem.unit
if let product = self._products.first(where: { $0.id == unitItem.rawValue } ) { if let product = self._products.first(where: { $0.id == unitItem.rawValue } ) {
rows.append(PurchaseRow(name: product.displayName, item: unitItem, quantity: remainingTournaments)) rows.append(PurchaseRow(id: 0, name: product.displayName, item: unitItem, quantity: remainingTournaments))
} }
} }

@ -23,7 +23,6 @@ extension Notification.Name {
static let StoreEventHappened = Notification.Name("storePurchaseSucceeded") static let StoreEventHappened = Notification.Name("storePurchaseSucceeded")
} }
@available(iOS 15, *)
class StoreManager { class StoreManager {
@Published private(set) var purchasedTransactions = Set<StoreKit.Transaction>() @Published private(set) var purchasedTransactions = Set<StoreKit.Transaction>()

@ -74,16 +74,21 @@ class SubscriptionModel: ObservableObject, StoreDelegate {
func purchase() { func purchase() {
Logger.log("start purchase...") Logger.log("start purchase...")
guard let product: Product = self.selectedProduct else { guard let product: Product = self.selectedProduct, let storeManager = self.storeManager else {
Logger.w("missing product or store manager")
return return
} }
Task { Task {
if product.item.isConsumable { do {
if let _ = try await self.storeManager?.purchase(product, quantity: self.quantity) { if product.item.isConsumable {
self.showSuccessfulPurchaseView = true if let _ = try await storeManager.purchase(product, quantity: self.quantity) {
self.showSuccessfulPurchaseView = true
}
} else {
let _ = try await storeManager.purchase(product)
} }
} else { } catch {
let _ = try await self.storeManager?.purchase(product) Logger.error(error)
} }
} }
} }

@ -113,6 +113,7 @@ struct UserCreationFormView: View {
Task { Task {
do { do {
let userCreationForm = UserCreationForm( let userCreationForm = UserCreationForm(
user: DataStore.shared.user, // local user
username: self.username, username: self.username,
password: self.password1, password: self.password1,
firstName: self.firstName, firstName: self.firstName,

Loading…
Cancel
Save