310 lines
12 KiB
Swift
310 lines
12 KiB
Swift
//
|
|
// 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"
|
|
}
|
|
}
|