// // SubscriptionsViewController.swift // Earthquake Network // // Created by Busi Andrea on 29/07/2020. // Copyright © 2020 Earthquake Network. All rights reserved. // import UIKit import StoreKit import Shogun class SubscriptionsViewController: UITableViewController { private static let SegueIdentifierSubscriptionDetail = "ShowSubscriptionDetail" // sezioni private enum TableSection: CaseIterable { case active case description case monthly case yearly case perpetual var sectionTitle: String? { switch self { case .monthly: return NSLocalizedString("inapp_monthly_subscriptions", comment: "") case .yearly: return NSLocalizedString("inapp_yearly_subscriptions", comment: "") case .perpetual: return NSLocalizedString("inapp_lifetime_subscriptions", comment: "") default: return nil } } } private let sections = TableSection.allCases private var allProducts = [SKProduct]() private var monthlyProducts = [SKProduct]() private var yearlyProducts = [SKProduct]() private var perpetualProducts = [SKProduct]() /// Product already bought by the user private var subscribedProduct: SKProduct? /// Availability for subscriptions private var availability: EQNPurchaseAvailability? /// Tells if products are loading private var isLoading = false /// Tells if a restore is in progress private var isRestorePurchase = false // MARK: - View Lifecycle override func viewDidLoad() { super.viewDidLoad() addObservers() configureUI() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) loadData() checkAvailabilities() } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == Self.SegueIdentifierSubscriptionDetail, let controller = segue.destination as? SubscriptionDetailViewController, let product = sender as? SKProduct { controller.product = product } } // MARK: - Private private func addObservers() { NotificationCenter.default.addObserver(self, selector: #selector(handlePurchaseNotification(_:)), name: .EQNInAppPurchaseDidComplete, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(fail(_:)), name: .EQNInAppPurchaseDidFail, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handleNoTransactionsNotification(_:)), name: .EQNInAppPurchaseNoTransactions, object: nil) } private func configureUI() { let restoreButton = UIBarButtonItem(title: NSLocalizedString("purchase_pro_restore", comment: ""), style: .plain, target: self, action: #selector(restoreTapped(_:))) navigationItem.rightBarButtonItem = restoreButton // if is presented in Simulator, add done button if navigationController?.viewControllers.first == self { let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(closeTapped(_:))) navigationItem.leftBarButtonItem = doneButton } tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 600.0 tableView.registerCell(for: SubscriptionsActiveTableViewCell.self) tableView.registerCell(for: SubscriptionsDescriptionTableViewCell.self) tableView.registerCell(for: SubscriptionProductTableViewCell.self) tableView.registerHeaderFooterView(for: SubscriptionsHeaderTableViewCell.self) } private func updateUI() { monthlyProducts.removeAll() yearlyProducts.removeAll() perpetualProducts.removeAll() // creates list to show let isDiscountAvailable = checkDiscountPrice() allProducts.forEach { (product) in if isDiscountAvailable { if product.productIdentifier == VersioneProProducts.Identifier.Subscription10kMonthly || product.productIdentifier == VersioneProProducts.Identifier.Subscription100kMonthly { monthlyProducts.append(product) } else if product.productIdentifier == VersioneProProducts.Identifier.Subscription10kYearlyDiscounted || product.productIdentifier == VersioneProProducts.Identifier.Subscription100kYearlyDiscounted { yearlyProducts.append(product) } } else { if product.productIdentifier == VersioneProProducts.Identifier.Subscription10kMonthly || product.productIdentifier == VersioneProProducts.Identifier.Subscription100kMonthly { monthlyProducts.append(product) } else if product.productIdentifier == VersioneProProducts.Identifier.Subscription10kYearly || product.productIdentifier == VersioneProProducts.Identifier.Subscription100kYearly { yearlyProducts.append(product) } } // perpetual scribuscriptions doesn't have discounted version if product.productIdentifier == VersioneProProducts.Identifier.Subscription10kPerpetual || product.productIdentifier == VersioneProProducts.Identifier.Subscription100kPerpetual { perpetualProducts.append(product) } } tableView.reloadData() } private func loadData() { isLoading = true VersioneProProducts.store.requestProducts{ [weak self] success, products in self?.isLoading = false guard let self = self, let products = products, success == true else { return } let purchased = products.filter { (product) -> Bool in let isPurchased = VersioneProProducts.store.isProductPurchased(product.productIdentifier) let isSubscription = VersioneProProducts.isSubscription(for: product.productIdentifier) return isPurchased && isSubscription } self.subscribedProduct = purchased.first self.allProducts = products.sorted(by: { $0.productIdentifier > $1.productIdentifier }) self.updateUI() } } private func checkDiscountPrice() -> Bool { let downloaded = EQNManager.manager().rete_smartphone?.subscriptionsDiscounted return downloaded ?? false } private func checkAvailabilities() { EQNPurchaseUtility.availableSubscriptions { (availability) in DispatchQueue.main.async { self.availability = availability self.updateUI() } } } // MARK: - Actions @objc func restoreTapped(_ sender: AnyObject) { isRestorePurchase = true VersioneProProducts.store.restorePurchases() } @objc func closeTapped(_ sender: AnyObject) { dismiss(animated: true, completion: nil) } // MARK: - Notifications @objc func fail(_ notification: Notification){ VersioneProProducts.store.loadPurchase() } @objc func handlePurchaseNotification(_ notification: Notification) { if isRestorePurchase { isRestorePurchase = false var product: String = "unknown" if let productIdentifier = notification.object as? String, let productName = resourceNameForProductIdentifier(productIdentifier) { product = productName } let message = "\(NSLocalizedString("purchase_pro_restore_alert_message", comment: ""))\n\n(\(product))" let alert = UIAlertController(title: NSLocalizedString("purchase_pro_restore_alert_title", comment: ""), message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "ok", style: .default, handler: nil)) present(alert, animated: true, completion: nil) } VersioneProProducts.store.loadPurchase() loadData() } @objc func handleNoTransactionsNotification(_ notification: Notification) { let alert = UIAlertController(title: NSLocalizedString("attention", comment: ""), message: NSLocalizedString("purchase_pro_no_subscriptions_alert_message", comment: ""), preferredStyle: .alert) alert.addAction(UIAlertAction(title: "ok", style: .default, handler: nil)) present(alert, animated: true, completion: nil) } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { sections.count } override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let tableSection = sections[section] let view = tableView.dequeueHeaderFooterView(cellIdentifiable: SubscriptionsHeaderTableViewCell.self) view.update(isLoading: isLoading, title: tableSection.sectionTitle) return view } override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { let tableSection = sections[section] if tableSection.sectionTitle != nil { return 50 } return 0 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { let tableSection = sections[section] switch tableSection { case .active: return 1 case .description: return 1 case .monthly, .yearly, .perpetual: return availableProducts(for: tableSection).count } } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let tableSection = sections[indexPath.section] if tableSection == .active { let cell = tableView.dequeueReusableCell(cellIdentifiable: SubscriptionsActiveTableViewCell.self, for: indexPath) cell.selectionStyle = .none cell.update(with: subscribedProduct) return cell } if tableSection == .description { let cell = tableView.dequeueReusableCell(cellIdentifiable: SubscriptionsDescriptionTableViewCell.self, for: indexPath) cell.selectionStyle = .none return cell } let products = availableProducts(for: tableSection) let cell = tableView.dequeueReusableCell(cellIdentifiable: SubscriptionProductTableViewCell.self, for: indexPath) cell.update(product: products[indexPath.row], availability: availability) return cell } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let tableSection = sections[indexPath.section] let products = availableProducts(for: tableSection) if !products.isEmpty { performSegue(withIdentifier: Self.SegueIdentifierSubscriptionDetail, sender: products[indexPath.row]) } } // MARK: - Helpers private func availableProducts(for section: TableSection) -> [SKProduct] { switch section { case .monthly: return monthlyProducts case .yearly: return yearlyProducts case .perpetual: return perpetualProducts default: return [] } } } extension SubscriptionsViewController: StoryboardInitializable { static var storyboardName: String { "Main" } static var storyboardControllerId: String { "subscriptionsController" } }