Files
eqn.ios/Sources/Earthquake Network/Controllers/InApp/SubscriptionDetailsViewController.swift
T
2024-06-20 16:26:19 +02:00

195 lines
7.3 KiB
Swift

//
// SubscriptionDetailsViewController.swift
// Earthquake Network
//
// Created by Andrea Busi on 18/06/24.
// Copyright © 2024 Earthquake Network. All rights reserved.
//
import UIKit
import StoreKit
import SafariServices
import Shogun
class SubscriptionDetailsViewController: UITableViewController {
/// Enable this allows shake to enable the current subscription
private static let ShakeToEnableSubscription = false
// MARK: - Internal
private let products: [SKProduct]
private var selectedProduct: SKProduct {
didSet {
onProductSelected()
}
}
private var priceFormatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.formatterBehavior = .behavior10_4
formatter.numberStyle = .currency
return formatter
}()
// MARK: - Init
init(
products: [SKProduct]
) {
self.products = products
self.selectedProduct = products.first(where: { $0.plan == .yearly }) ?? products.first!
super.init(style: .plain)
}
required init?(coder: NSCoder) {
fatalError("Please use init(products:) instead.")
}
// MARK: - View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
addObservers()
}
private func addObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(handlePurchaseNotification(_:)),
name: .EQNInAppPurchaseDidComplete,
object: nil)
}
private func configureUI() {
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 2000.0
tableView.separatorStyle = .none
tableView.backgroundColor = .systemGroupedBackground
tableView.registerCell(for: SubscriptionDetailsTableViewCell.self)
}
// MARK: - Notifications
@objc private func handlePurchaseNotification(_ notification: Notification) {
navigationController?.popViewController(animated: true)
}
// MARK: - Table view delegate & data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(cellIdentifiable: SubscriptionDetailsTableViewCell.self, for: indexPath)
cell.selectionStyle = .none
cell.productTitleLabel.text = selectedProduct.localizedTitle
cell.productImageView.image = VersioneProProducts.image(for: selectedProduct.productIdentifier)
var purchaseRecapString = ""
var subscriptionDetailsString = ""
switch selectedProduct.productIdentifier {
case VersioneProProducts.Identifier.Subscription10kMonthly,
VersioneProProducts.Identifier.Subscription100kMonthly:
purchaseRecapString = "inapp_monthly_payment"
subscriptionDetailsString = "inapp_detail_description"
case VersioneProProducts.Identifier.Subscription100kYearly,
VersioneProProducts.Identifier.Subscription100kYearlyDiscounted,
VersioneProProducts.Identifier.Subscription10kYearly,
VersioneProProducts.Identifier.Subscription10kYearlyDiscounted:
purchaseRecapString = "inapp_yearly_payment"
subscriptionDetailsString = "inapp_detail_description"
case VersioneProProducts.Identifier.Subscription10kPerpetual,
VersioneProProducts.Identifier.Subscription100kPerpetual:
purchaseRecapString = "inapp_lifetime_payment"
subscriptionDetailsString = "inapp_lifetime_detail_description"
default:
break
}
cell.subscriptionDetailsLabel.text = NSLocalizedString(subscriptionDetailsString, comment: "")
cell.onTapPrivacy = { [weak self] in
self?.openExternalLink("\(EQNWebsiteAddress)/privacy/")
}
cell.onTapTerms = { [weak self] in
self?.openExternalLink("\(EQNWebsiteAddress)/terms-conditions/")
}
cell.onTapPurchase = { [weak self] in
self?.purchaseSelectedProduct()
}
cell.onChangeProduct = { [weak self] type in
if let product = self?.productFromProductType(type) {
self?.selectedProduct = product
}
}
let type = productToProductType()
cell.productSegmentedControl.selectedSegmentIndex = type.index
cell.purchaseRecapLabel.text = "\(selectedProduct.localizedDescription), \(NSLocalizedString(purchaseRecapString, comment: ""))"
cell.productPriceLabel.text = priceFormatter.string(from: selectedProduct.price)
return cell
}
// MARK: - Private
private func onProductSelected() {
priceFormatter.locale = selectedProduct.priceLocale
tableView.reloadData()
}
private func openExternalLink(_ stringUrl: String) {
if let url = URL(string: stringUrl) {
let controller = SFSafariViewController(url: url)
present(controller, animated: true, completion: nil)
}
}
private func purchaseSelectedProduct() {
VersioneProProducts.store.buyProduct(selectedProduct)
}
private func productToProductType() -> SubscriptionDetailsTableViewCell.ProductType {
let identifier = selectedProduct.productIdentifier
if VersioneProProducts.isMonthlySubscription(for: identifier) {
return .monthly
} else if VersioneProProducts.isYearlySubscription(for: identifier) {
return .yearly
} else {
return .perpetual
}
}
private func productFromProductType(_ type: SubscriptionDetailsTableViewCell.ProductType) -> SKProduct? {
let product: SKProduct?
switch type {
case .monthly:
product = products.first(where: { VersioneProProducts.isMonthlySubscription(for: $0.productIdentifier) })
case .yearly:
product = products.first(where: { VersioneProProducts.isYearlySubscription(for: $0.productIdentifier) })
case .perpetual:
product = products.first(where: { VersioneProProducts.isPerpetualSubscription(for: $0.productIdentifier) })
}
return product
}
}
extension SubscriptionDetailsViewController {
override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
guard event?.subtype == .motionShake, Self.ShakeToEnableSubscription else {
return
}
let alert = UIAlertController(title: "🧑‍💻", message: "Please select an action", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Reset all purchases", style: .default) { action in
EQNPurchaseUtility.resetInAppPurchases()
})
alert.addAction(UIAlertAction(title: "Activate this subscription", style: .default) { action in
EQNPurchaseUtility.simulateProPurchase(identifier: self.selectedProduct.productIdentifier)
})
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(alert, animated: true, completion: nil)
}
}