multistore
Laurent 2 years ago
parent 1356ecf71d
commit a25dadf1b8
  1. 10
      PadelClub/Data/Tournament.swift
  2. 81
      PadelClub/Views/Subscription/Guard.swift
  3. 2
      PadelClub/Views/Subscription/StoreItem.swift
  4. 9
      PadelClub/Views/Subscription/StoreManager.swift

@ -84,6 +84,16 @@ class Tournament : ModelObject, Storable {
enum TournamentPayment: Int { enum TournamentPayment: Int {
case free, unit, subscriptionUnit, unlimited case free, unit, subscriptionUnit, unlimited
var isSubscription: Bool {
switch self {
case .subscriptionUnit, .unlimited:
return true
default:
return false
}
}
} }
enum State { enum State {

@ -10,7 +10,7 @@ import StoreKit
import LeStorage import LeStorage
@available(iOS 15, *) @available(iOS 15, *)
@objc class Guard : NSObject { @objc class Guard: NSObject {
static var main: Guard = Guard() static var main: Guard = Guard()
@ -20,17 +20,18 @@ import LeStorage
var updateListenerTask: Task<Void, Error>? = nil var updateListenerTask: Task<Void, Error>? = nil
fileprivate var _userPurchases: [Purchase] = [] fileprivate var _purchases: StoredCollection<Purchase>
override init() { override init() {
self._purchases = Store.main.registerCollection(synchronized: true, inMemory: true)
super.init() super.init()
self.updateListenerTask = self.listenForTransactions() self.updateListenerTask = self.listenForTransactions()
Task { Task {
do { do {
try await self._retrievePrivateServerPurchases()
try await self.refreshPurchasedAppleProducts() try await self.refreshPurchasedAppleProducts()
} catch { } catch {
Logger.error(error) Logger.error(error)
@ -38,23 +39,6 @@ import LeStorage
} }
} }
fileprivate func _uploadTransaction(_ transaction: StoreKit.Transaction) async throws {
let service = try Store.main.service()
var purchase = try transaction.purchase()
// if let apiCall = try self._callForInstance(purchase, method: Method.post) {
//
// }
}
fileprivate func _retrievePrivateServerPurchases() async throws {
let service = try Store.main.service()
self._userPurchases = try await service.get()
}
func refreshPurchasedAppleProducts() async throws { func refreshPurchasedAppleProducts() async throws {
// Iterate through the user's purchased products. // Iterate through the user's purchased products.
@ -105,8 +89,10 @@ import LeStorage
if transaction.revocationDate == nil { if transaction.revocationDate == nil {
// If the App Store has not revoked the transaction, add it to the list of `purchasedIdentifiers`. // If the App Store has not revoked the transaction, add it to the list of `purchasedIdentifiers`.
purchasedTransactions.insert(transaction) purchasedTransactions.insert(transaction)
do { do {
try await self._uploadTransaction(transaction) let purchase: Purchase = transaction.purchase()
try self._purchases.addOrUpdate(instance: purchase)
} catch { } catch {
Logger.error(error) Logger.error(error)
} }
@ -146,7 +132,7 @@ import LeStorage
fileprivate func _userFilteredPurchases() -> [StoreKit.Transaction] { fileprivate func _userFilteredPurchases() -> [StoreKit.Transaction] {
return self.purchasedTransactions.filter { transaction in return self.purchasedTransactions.filter { transaction in
return self._userPurchases.contains(where: { $0.identifier == transaction.id } ) return self._purchases.contains(where: { $0.identifier == transaction.id } )
} }
} }
@ -171,42 +157,61 @@ import LeStorage
return units.reduce(0) { $0 + $1.purchasedQuantity } return units.reduce(0) { $0 + $1.purchasedQuantity }
} }
func canAddTournament() -> Bool { // func canAddTournament() -> Bool {
if self.currentPlan == .monthlyUnlimited { // switch self.currentPlan {
return true // case .monthlyUnlimited: return true
} // case .fivePerMonth:
let tournamentCount = DataStore.shared.tournaments.count // if let date = self.currentBestPlan?.originalPurchaseDate {
let tournamentCreditCount = self._purchasedTournamentCount() // let tournaments = DataStore.shared.tournaments.filter { $0.creationDate > date }
return tournamentCreditCount > tournamentCount // return tournaments.count < StoreItem.five
} // } else {
// Logger.error(StoreManagerError.missingPlan)
// return false
// }
// case .unit:
// let tournamentCount = DataStore.shared.tournaments.count
// let tournamentCreditCount = self._purchasedTournamentCount()
// return tournamentCreditCount > tournamentCount
// case nil:
// return DataStore.shared.tournaments.count == 0
// }
// }
func paymentForNewTournament() -> Tournament.TournamentPayment? { func paymentForNewTournament() -> Tournament.TournamentPayment? {
if self.currentPlan == .monthlyUnlimited {
switch self.currentPlan {
case .monthlyUnlimited:
return Tournament.TournamentPayment.unlimited return Tournament.TournamentPayment.unlimited
} else if self.currentPlan == .fivePerMonth, let purchaseDate = self.currentBestPlan?.originalPurchaseDate { case .fivePerMonth:
if let purchaseDate = self.currentBestPlan?.originalPurchaseDate {
let tournaments = DataStore.shared.tournaments.filter { $0.creationDate > purchaseDate } let tournaments = DataStore.shared.tournaments.filter { $0.creationDate > purchaseDate }
if tournaments.count < 5 { if tournaments.count < StoreItem.five {
return Tournament.TournamentPayment.subscriptionUnit return Tournament.TournamentPayment.subscriptionUnit
} }
} }
return nil
default:
let subscriptionPayed = DataStore.shared.tournaments.filter { $0.payment.isSubscription }
let tournamentCount = DataStore.shared.tournaments.count let unitlyPayed = DataStore.shared.tournaments.count - subscriptionPayed.count
if tournamentCount == 0 { if unitlyPayed == 0 {
return Tournament.TournamentPayment.free return Tournament.TournamentPayment.free
} }
let tournamentCreditCount = self._purchasedTournamentCount() let tournamentCreditCount = self._purchasedTournamentCount()
if tournamentCreditCount > tournamentCount { if tournamentCreditCount > unitlyPayed {
return Tournament.TournamentPayment.unit return Tournament.TournamentPayment.unit
} }
return nil return nil
} }
}
} }
fileprivate extension StoreKit.Transaction { fileprivate extension StoreKit.Transaction {
func purchase() throws -> Purchase { func purchase() -> Purchase {
let userId = try Store.main.currentUserUUID().uuidString let userId = Store.main.currentUserUUID().uuidString
return Purchase(user: userId, return Purchase(user: userId,
identifier: self.id, identifier: self.id,
purchaseDate: self.purchaseDate, purchaseDate: self.purchaseDate,

@ -12,6 +12,8 @@ enum StoreItem: String, Identifiable, CaseIterable {
case fivePerMonth = "app.padelclub.tournament.subscription.five.per.month" case fivePerMonth = "app.padelclub.tournament.subscription.five.per.month"
case unit = "app.padelclub.tournament.unit" case unit = "app.padelclub.tournament.unit"
static let five: Int = 5
var id: String { return self.rawValue } var id: String { return self.rawValue }
// var title: String { return "Tournoi illimités" } // var title: String { return "Tournoi illimités" }

@ -11,6 +11,7 @@ import LeStorage
public enum StoreManagerError: Error { public enum StoreManagerError: Error {
case failedVerification case failedVerification
case missingPlan
} }
protocol StoreDelegate { protocol StoreDelegate {
@ -25,8 +26,6 @@ extension Notification.Name {
@available(iOS 15, *) @available(iOS 15, *)
class StoreManager { class StoreManager {
// @Published private(set) var products: [Product] = []
@Published private(set) var purchasedTransactions = Set<StoreKit.Transaction>() @Published private(set) var purchasedTransactions = Set<StoreKit.Transaction>()
var delegate: StoreDelegate? = nil var delegate: StoreDelegate? = nil
@ -48,10 +47,6 @@ class StoreManager {
self.updateListenerTask?.cancel() self.updateListenerTask?.cancel()
} }
// func indexOf(identifier: String) -> Int? {
// return self.products.map { $0.id }.firstIndex(of: identifier)
// }
@MainActor @MainActor
func requestProducts() async { func requestProducts() async {
do { do {
@ -95,7 +90,7 @@ class StoreManager {
Logger.log("Store purchase started...") Logger.log("Store purchase started...")
var options: Set<Product.PurchaseOption> = [] var options: Set<Product.PurchaseOption> = []
let uuid: UUID = try Store.main.currentUserUUID() let uuid: UUID = Store.main.currentUserUUID()
let tokenOption = Product.PurchaseOption.appAccountToken(uuid) let tokenOption = Product.PurchaseOption.appAccountToken(uuid)
options.insert(tokenOption) options.insert(tokenOption)

Loading…
Cancel
Save