Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

[IP-624] [Subscriptions UI] Loading indicator after clicking on subsc…

…ribe (#361)

* Fix a possible bug in BaseUpgradeViewController with telemetry

* Show loading indicator when tapping buy button

* Fix a nil issue in VPNEndPointManager

* Blur UpgradeViewController when loading

* Fix iffies, viewsies
  • Loading branch information
Daniel Jilg committed Jun 25, 2019
1 parent 9f48158 commit 9bd2b9c493bceadd78aa6bd34747233f3c46adbb
@@ -135,8 +135,8 @@ class VPN {
VPN.shared.lastStatus = .invalid
}

let country = VPNEndPointManager.shared.selectedCountry
guard let creds = VPNEndPointManager.shared.getCredentials(country: country),
guard let country = VPNEndPointManager.shared.selectedCountry,
let creds = VPNEndPointManager.shared.getCredentials(country: country),
!country.endpoint.isEmpty else { return }

NEVPNManager.shared().loadFromPreferences { (error) in
@@ -180,9 +180,11 @@ class VPN {
}
catch (let error) {
print("VPN Connecttion failed --- \(error)")
LegacyTelemetryHelper.logVPN(action: "error",
location: VPNEndPointManager.shared.selectedCountry.id,
if let selectedCountry = VPNEndPointManager.shared.selectedCountry {
LegacyTelemetryHelper.logVPN(action: "error",
location: selectedCountry.id,
connectionTime: 0)
}
VPN.shared.retryCount = 0
}

@@ -173,7 +173,7 @@ class VPNEndPointManager {
}

//MARK:- VPN Countries
var selectedCountry: VPNCountry {
var selectedCountry: VPNCountry? {
set {
UserDefaults.standard.set(try? PropertyListEncoder().encode(newValue), forKey: SelectedCountryKey)
UserDefaults.standard.synchronize()
@@ -182,7 +182,7 @@ class VPNEndPointManager {
if let data = UserDefaults.standard.value(forKey: SelectedCountryKey) as? Data, let country = try? PropertyListDecoder().decode(VPNCountry.self, from: data) {
return country
}
return countries.first!
return countries.first
}
}

@@ -262,8 +262,9 @@ class VPNViewController: UIViewController {
//start timer
timer = Timer.scheduledTimer(timeInterval: 0.95, target: self, selector: #selector(timerFired), userInfo: nil, repeats: true)
timer?.fire()
LegacyTelemetryHelper.logVPN(action: "connect",
location: VPNEndPointManager.shared.selectedCountry.id)
if let selectedCountry = VPNEndPointManager.shared.selectedCountry {
LegacyTelemetryHelper.logVPN(action: "connect", location: selectedCountry.id)
}
}
else if VPNStatus == .disconnected {
if self.connectButton.currentState == .Connecting || self.connectButton.currentState == .Connect {
@@ -314,10 +315,12 @@ class VPNViewController: UIViewController {
if (VPN.shared.status == .connected) {
VPN.disconnectVPN()
LegacyTelemetryHelper.logVPN(action: "click", target: "toggle", state: "off")

LegacyTelemetryHelper.logVPN(action: "disconnect",
location: VPNEndPointManager.shared.selectedCountry.id,

if let selectedCountry = VPNEndPointManager.shared.selectedCountry {
LegacyTelemetryHelper.logVPN(action: "disconnect",
location: selectedCountry.id,
connectionTime: getConnectionTime())
}
} else {
guard SubscriptionController.shared.isVPNEnabled() else {
displayUnlockVPNAlert()
@@ -426,7 +429,7 @@ extension VPNViewController: UITableViewDataSource {
cell.textLabel?.text = NSLocalizedString("Choose VPN Location", tableName: "Lumen", comment: "[VPN] vpn choose location")
cell.textLabel?.textColor = Lumen.VPN.selectTextColor(lumenTheme, .Normal)
cell.backgroundColor = .clear
cell.detailTextLabel?.text = VPNEndPointManager.shared.selectedCountry.name
cell.detailTextLabel?.text = VPNEndPointManager.shared.selectedCountry?.name
cell.detailTextLabel?.textColor = Lumen.VPN.selectDetailTextColor(lumenTheme, .Normal)
cell.selectionStyle = .none

@@ -458,7 +461,7 @@ extension VPNViewController: VPNCountrySelectionDelegate {
func didSelectCountry(country: VPNCountry) {
LegacyTelemetryHelper.logVPN(action: "click",
target: "location",
location: VPNEndPointManager.shared.selectedCountry.id)
location: country.id)
//country changed, reconnect if necessary
VPN.countryDidChange(country: country)

@@ -16,6 +16,7 @@ public typealias ProductsRequestCompletionHandler = (_ success: Bool, _ products
extension Notification.Name {
static let ProductPurchaseSuccessNotification = Notification.Name("ProductPurchaseSuccessNotification")
static let ProductPurchaseErrorNotification = Notification.Name("ProductPurchaseErrorNotification")
static let ProductPurchaseCancelledNotification = Notification.Name("ProductPurchaseCancelledNotification")
static let SubscriptionRefreshNotification = Notification.Name("SubscriptionRefreshNotification")
}

@@ -53,13 +53,17 @@ class RevenueCatService: NSObject, IAPService {

public func buyProduct(_ product: SKProduct) {
print("Buying \(product.productIdentifier)...")
purchases?.makePurchase(product, { (transaction, purchaserInfo, error) in
if let error = error as? SKError, error.code != .paymentCancelled {
NotificationCenter.default.post(name: .ProductPurchaseErrorNotification, object: error.localizedDescription)
purchases?.makePurchase(product) { (transaction, purchaserInfo, error) in
if let error = error as? SKError {
if error.code == .paymentCancelled {
NotificationCenter.default.post(name: .ProductPurchaseCancelledNotification, object: nil)
} else {
NotificationCenter.default.post(name: .ProductPurchaseErrorNotification, object: nil)
}
} else if let purchaserInfo = purchaserInfo {
self.processPurchaseInfo(purchaserInfo)
}
})
}
}

public func isUserPromoEligible(productID:String, completion: @escaping (Bool) -> Void) {
@@ -78,13 +82,17 @@ class RevenueCatService: NSObject, IAPService {
}

public func restorePurchases() {
purchases?.restoreTransactions({ (purchaserInfo, error) in
if let error = error as? SKError, error.code != .paymentCancelled {
NotificationCenter.default.post(name: .ProductPurchaseErrorNotification, object: error.localizedDescription)
purchases?.restoreTransactions() { (purchaserInfo, error) in
if let error = error as? SKError {
if error.code == .paymentCancelled {
NotificationCenter.default.post(name: .ProductPurchaseCancelledNotification, object: nil)
} else {
NotificationCenter.default.post(name: .ProductPurchaseErrorNotification, object: error.localizedDescription)
}
} else if let purchaserInfo = purchaserInfo {
self.processPurchaseInfo(purchaserInfo)
}
})
}
}

public func getSubscriptionUserId() -> String? {
@@ -104,12 +112,13 @@ extension RevenueCatService: PurchasesDelegate {
private func processPurchaseInfo(_ purchaserInfo: PurchaserInfo) {
guard let identifier = getLastestIdentifier(purchaserInfo),
let expirationDate = purchaserInfo.expirationDate(forProductIdentifier: identifier) else {
NotificationCenter.default.post(name: .ProductPurchaseCancelledNotification, object: nil)
return
}
let lumenPurchaseInfo = LumenPurchaseInfo(productIdentifier: identifier, expirationDate: expirationDate)
print("processPurchaseInfo -> identifier: \(identifier), expirationDate: \(expirationDate)")
observable.onNext(lumenPurchaseInfo)
NotificationCenter.default.post(name: .ProductPurchaseSuccessNotification, object: identifier)
NotificationCenter.default.post(name: .ProductPurchaseSuccessNotification, object: nil)
}

fileprivate func getLastestIdentifier(_ purchaserInfo: PurchaserInfo) -> String? {
@@ -20,6 +20,12 @@ class UpgradLumenNavigationController: UINavigationController {
class BaseUpgradeViewController: UIViewController {
#if PAID
let loadingView = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
let loadingOverlay: UIView = {
let blurEffect = UIBlurEffect(style: .dark)
let blurredEffectView = UIVisualEffectView(effect: blurEffect)
return blurredEffectView
}()

let dataSource: SubscriptionDataSource

var selectedProduct: LumenSubscriptionProduct?
@@ -40,6 +46,9 @@ class BaseUpgradeViewController: UIViewController {
NotificationCenter.default.addObserver(self, selector: #selector(handlePurchaseSuccessNotification(_:)),
name: .ProductPurchaseSuccessNotification,
object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handlePurchaseCancelledNotification(_:)),
name: .ProductPurchaseCancelledNotification,
object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handlePurchaseErrorNotification(_:)),
name: .ProductPurchaseErrorNotification,
object: nil)
@@ -65,13 +74,19 @@ class BaseUpgradeViewController: UIViewController {
self.selectedProduct = nil
self.dismiss(animated: true)
}

@objc func handlePurchaseCancelledNotification(_ notification: Notification) {
self.selectedProduct = nil
self.stopLoadingAnimation()
}

@objc func handlePurchaseErrorNotification(_ notification: Notification) {
self.stopLoadingAnimation()
guard let lumenProduct = self.selectedProduct else {
return
}
self.selectedProduct = nil
let telemetrySignals = self.dataSource.telemeterySignals()
let telemetrySignals = self.dataSource.telemeterySignals(product: lumenProduct)
LegacyTelemetryHelper.logPromoPayment(action: "error", target: telemetrySignals["target"], view: telemetrySignals["view"])
let errorDescirption = NSLocalizedString("We are sorry, but something went wrong. The payment was not successful, please try again.", tableName: "Lumen", comment: "Error message when there is failing payment transaction")
let alertController = UIAlertController(title: "", message: errorDescirption, preferredStyle: .alert)
@@ -126,14 +141,37 @@ class BaseUpgradeViewController: UIViewController {
}
}

private func startLoadingAnimation() {
self.loadingView.startAnimating()
// MARK: - Loading
func startLoadingAnimation() {

loadingOverlay.alpha = 0
view.addSubview(loadingOverlay)
loadingOverlay.snp.makeConstraints { (make) in
make.top.equalTo(view)
make.bottom.equalTo(view)
make.left.equalTo(view)
make.right.equalTo(view)
}

view.bringSubview(toFront: loadingView)
loadingView.startAnimating()

UIView.animate(withDuration: 0.5) {
self.loadingOverlay.alpha = 0.8
}
}

private func stopLoadingAnimation() {
func stopLoadingAnimation() {
self.loadingView.stopAnimating()

UIView.animate(withDuration: 0.25, animations: {
self.loadingOverlay.alpha = 0
}) { finished in
self.loadingOverlay.removeFromSuperview()
}
}


// MARK: - Alerts
private func showProductsRetrievalFailedAlert() {
let errorDescirption = NSLocalizedString("Sorry, Lumen cannot connect to the Internet.", tableName: "Lumen", comment: "Error when can't get list of available subscriptions")
let alertController = UIAlertController(title: "", message: errorDescirption, preferredStyle: .alert)
@@ -165,6 +165,7 @@ class UpgradLumenViewController: BaseUpgradeViewController {
@objc func restoreSubscription() {
self.telemetrySignals?["target"] = "restore"
LegacyTelemetryHelper.logPayment(action: "click", target: self.telemetrySignals?["target"])
startLoadingAnimation()
SubscriptionController.shared.restorePurchases()
}

@@ -266,6 +267,7 @@ extension UpgradLumenViewController: UITableViewDelegate, UITableViewDataSource
self?.selectedProduct = subscriptionProduct
self?.telemetrySignals = subscriptionInfo?.telemetrySignals
LegacyTelemetryHelper.logPayment(action: "click", target: self?.telemetrySignals?["target"])
self?.startLoadingAnimation()
}
return cell
}

0 comments on commit 9bd2b9c

Please sign in to comment.