diff --git a/Cliqz/HomePanel/VPN/VPN.swift b/Cliqz/HomePanel/VPN/VPN.swift index 4fd7e4c2e..9b9637263 100644 --- a/Cliqz/HomePanel/VPN/VPN.swift +++ b/Cliqz/HomePanel/VPN/VPN.swift @@ -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 } diff --git a/Cliqz/HomePanel/VPN/VPNEndPointManager.swift b/Cliqz/HomePanel/VPN/VPNEndPointManager.swift index 11cc6632d..2083b8119 100644 --- a/Cliqz/HomePanel/VPN/VPNEndPointManager.swift +++ b/Cliqz/HomePanel/VPN/VPNEndPointManager.swift @@ -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 } } diff --git a/Cliqz/HomePanel/VPN/VPNViewController.swift b/Cliqz/HomePanel/VPN/VPNViewController.swift index d913978fe..43c8586f6 100644 --- a/Cliqz/HomePanel/VPN/VPNViewController.swift +++ b/Cliqz/HomePanel/VPN/VPNViewController.swift @@ -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) diff --git a/Cliqz/Upgrade&Payment/Services/IAPService.swift b/Cliqz/Upgrade&Payment/Services/IAPService.swift index 581a585c7..cd97cc63f 100644 --- a/Cliqz/Upgrade&Payment/Services/IAPService.swift +++ b/Cliqz/Upgrade&Payment/Services/IAPService.swift @@ -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") } diff --git a/Cliqz/Upgrade&Payment/Services/RevenueCatService.swift b/Cliqz/Upgrade&Payment/Services/RevenueCatService.swift index 83efe1ecd..fcb6d44f9 100644 --- a/Cliqz/Upgrade&Payment/Services/RevenueCatService.swift +++ b/Cliqz/Upgrade&Payment/Services/RevenueCatService.swift @@ -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? { diff --git a/Cliqz/Upgrade&Payment/View/UpgradeViews/BaseUpgradeViewController.swift b/Cliqz/Upgrade&Payment/View/UpgradeViews/BaseUpgradeViewController.swift index f7a3595cb..9c41df349 100644 --- a/Cliqz/Upgrade&Payment/View/UpgradeViews/BaseUpgradeViewController.swift +++ b/Cliqz/Upgrade&Payment/View/UpgradeViews/BaseUpgradeViewController.swift @@ -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) diff --git a/Cliqz/Upgrade&Payment/View/UpgradeViews/UpgradLumenViewController.swift b/Cliqz/Upgrade&Payment/View/UpgradeViews/UpgradLumenViewController.swift index 2a7960687..30684ab24 100644 --- a/Cliqz/Upgrade&Payment/View/UpgradeViews/UpgradLumenViewController.swift +++ b/Cliqz/Upgrade&Payment/View/UpgradeViews/UpgradLumenViewController.swift @@ -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 }