Skip to content

Instantly share code, notes, and snippets.

@yusufonderd
Created February 7, 2022 13:34
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save yusufonderd/2cf6e360dff1fff9a8719bd04e88eb6b to your computer and use it in GitHub Desktop.
Save yusufonderd/2cf6e360dff1fff9a8719bd04e88eb6b to your computer and use it in GitHub Desktop.
class PaymentViewModel : ObservableObject{
@Published var isLoadingRetrieveProducts = false
@Published var yearlySubscriptionPrice = ""
@Published var monthlySubscriptionPrice = ""
@Published var lifetimeSubscriptionPrice = ""
@Published var isLoadingPayment = false
@Published var showAlert = false
@Published var title: String = ""
@Published var payments : [PaymentView] = []
init(){
payments.append(PaymentView.init(paymentId: PaymentId.monthly, title: "_monthly".localized, index: 0,price: "",extraInfo: "Free for 3 days".localized))
payments.append(PaymentView.init(paymentId: PaymentId.yearly, title: "_annual".localized, index: 1,price: "",extraInfo: "Free for 3 days".localized))
payments.append(PaymentView.init(paymentId: PaymentId.lifetime, title: "_lifetime".localized, index: 2,price : "",extraInfo: ""))
}
func retrieveProducts(){
isLoadingRetrieveProducts = true
SwiftyStoreKit.retrieveProductsInfo([PaymentId.monthly,PaymentId.yearly,PaymentId.lifetime]) { result in
self.isLoadingRetrieveProducts = false
result.retrievedProducts.forEach { skProduct in
switch(skProduct.productIdentifier){
case PaymentId.monthly:
self.payments[0].price = skProduct.localizedPrice ?? "\(skProduct.price)"
break;
case PaymentId.yearly:
self.payments[1].price = skProduct.localizedPrice ?? "\(skProduct.price)"
let monthlyPrice = String(format: "%.1f",Float(skProduct.price) / 12)
let currency = skProduct.priceLocale.currencySymbol ?? ""
self.payments[1].discount = "\(currency)\(monthlyPrice) / \("_mo".localized) "
break;
case PaymentId.lifetime:
self.payments[2].price = skProduct.localizedPrice ?? "\(skProduct.price)"
break;
default:
debugPrint("PaymentViewModel default")
break;
}
}
}
}
func startPayment(with paymentId: String, completion: @escaping (PaymentResult) -> Void){
isLoadingPayment = true
SwiftyStoreKit.purchaseProduct(paymentId, quantity: 1, atomically: true) { result in
debugPrint("PaymentManager startPayment => \(paymentId)")
switch result {
case .success(let purchase):
debugPrint("PaymentManager success => \(purchase.productId)")
completion(PaymentResult(success: true,error: nil))
case .error(let error):
if let _error = PaymentErrorHandler.map(from: error){
debugPrint("PaymentManager error => \(_error)")
completion(PaymentResult(success: false,error: _error))
}else {
completion(PaymentResult(success: false,error: nil))
}
case .deferred(purchase: let purchase):
debugPrint("PaymentManager deferred => \(purchase.productId)")
completion(PaymentResult(success: false,error: nil))
}
self.isLoadingPayment = false
}
}
private func showAlert(title : String){
self.title = title
self.showAlert = true
}
func restorePurchases(completion: @escaping (PaymentResult) -> Void){
debugPrint("PaymentManager restorePurchases")
isLoadingPayment = true
SwiftyStoreKit.restorePurchases(atomically: true) { results in
debugPrint("PaymentManager restorePurchases results => \(results)")
if results.restoreFailedPurchases.count > 0 {
self.showAlert(title: "No restored purchase")
completion(PaymentResult(success: false,error: nil))
}
else if results.restoredPurchases.count > 0 {
if let purchase = results.restoredPurchases.first{
self.startPayment(with: purchase.productId, completion: completion)
}
}
else {
self.showAlert(title: "No restored purchase")
completion(PaymentResult(success: false,error: nil))
}
self.isLoadingPayment = false
}
}
}
struct PaymentResult {
var success: Bool
var error : String?
}
struct PaymentErrorHandler{
static func map(from error: SKError) -> String? {
var errorDescription : String? = nil
switch error.code {
case .unknown:
errorDescription = "Unknown error. Please contact support"
case .clientInvalid:
errorDescription = "Not allowed to make the payment"
case .paymentCancelled:
errorDescription = "Payment cancelled"
case .paymentInvalid:
errorDescription = "The purchase identifier was invalid"
case .paymentNotAllowed:
errorDescription = "The device is not allowed to make the payment"
case .storeProductNotAvailable:
errorDescription = "The product is not available in the current storefront"
case .cloudServicePermissionDenied:
errorDescription = "Access to cloud service information is not allowed"
case .cloudServiceNetworkConnectionFailed:
errorDescription = "Could not connect to the network"
case .cloudServiceRevoked:
errorDescription = "User has revoked permission to use this cloud service"
default:
errorDescription = (error as NSError).localizedDescription
}
return errorDescription
}
}
@kurdex
Copy link

kurdex commented Apr 25, 2022

gid:PEYNFhLLRVUeoSQeLbyy8d

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment