diff --git a/Passepartout-iOS/Global/ProductManager.swift b/Passepartout-iOS/Global/ProductManager.swift index 32039f2c..832d60db 100644 --- a/Passepartout-iOS/Global/ProductManager.swift +++ b/Passepartout-iOS/Global/ProductManager.swift @@ -66,12 +66,14 @@ class ProductManager: NSObject { SKPaymentQueue.default().remove(self) } - func listProducts(completionHandler: (([SKProduct]) -> Void)?) { - inApp.requestProducts(withIdentifiers: Product.all) { _ in + func listProducts(completionHandler: (([SKProduct]?, Error?) -> Void)?) { + inApp.requestProducts(withIdentifiers: Product.all, completionHandler: { _ in log.debug("In-app products: \(self.inApp.products.map { $0.productIdentifier })") - completionHandler?(self.inApp.products) - } + completionHandler?(self.inApp.products, nil) + }, failureHandler: { + completionHandler?(nil, $0) + }) } func product(withIdentifier identifier: Product) -> SKProduct? { diff --git a/Passepartout-iOS/Global/SwiftGen+Strings.swift b/Passepartout-iOS/Global/SwiftGen+Strings.swift index 82549a11..18a14a3c 100644 --- a/Passepartout-iOS/Global/SwiftGen+Strings.swift +++ b/Passepartout-iOS/Global/SwiftGen+Strings.swift @@ -1048,6 +1048,12 @@ internal enum L10n { } } internal enum Provider { + internal enum Alerts { + internal enum Unavailable { + /// Could not download provider infrastructure, please retry later. + internal static let message = L10n.tr("Core", "wizards.provider.alerts.unavailable.message") + } + } internal enum Cells { internal enum UpdateList { /// Update list diff --git a/Passepartout-iOS/Global/Theme.swift b/Passepartout-iOS/Global/Theme.swift index b3548b60..718fa25f 100644 --- a/Passepartout-iOS/Global/Theme.swift +++ b/Passepartout-iOS/Global/Theme.swift @@ -187,8 +187,12 @@ extension MFMailComposeViewController { // FIXME: load from index JSON extension Infrastructure.Metadata { - var logo: UIImage { - return ImageAsset(name: name.lowercased()).image + var logo: UIImage? { + let bundle = Bundle(for: AppDelegate.self) + guard let image = AssetImageTypeAlias(named: name.lowercased(), in: bundle, compatibleWith: nil) else { + return Asset.Providers.placeholder.image + } + return image } } diff --git a/Passepartout-iOS/Scenes/Organizer/DonationViewController.swift b/Passepartout-iOS/Scenes/Organizer/DonationViewController.swift index 0cdb8359..417b1057 100644 --- a/Passepartout-iOS/Scenes/Organizer/DonationViewController.swift +++ b/Passepartout-iOS/Scenes/Organizer/DonationViewController.swift @@ -27,6 +27,9 @@ import UIKit import StoreKit import PassepartoutCore import Convenience +import SwiftyBeaver + +private let log = SwiftyBeaver.self class DonationViewController: UITableViewController, StrongTableHost { private var donationList: [Product] = [] @@ -81,7 +84,11 @@ class DonationViewController: UITableViewController, StrongTableHost { ProductManager.shared.listProducts { self.isLoading = false - self.setProducts($0) + guard let products = $0 else { + log.error("Unable to list products: \($1?.localizedDescription ?? "")") + return + } + self.setProducts(products) } } diff --git a/Passepartout-iOS/Scenes/Organizer/OrganizerViewController.swift b/Passepartout-iOS/Scenes/Organizer/OrganizerViewController.swift index 6ed2570a..50f9061f 100644 --- a/Passepartout-iOS/Scenes/Organizer/OrganizerViewController.swift +++ b/Passepartout-iOS/Scenes/Organizer/OrganizerViewController.swift @@ -474,13 +474,9 @@ extension OrganizerViewController { let cell = Cells.setting.dequeue(from: tableView, for: indexPath) let rowProfile = profileKey(at: indexPath) if rowProfile.context == .provider { - if let metadata = InfrastructureFactory.shared.metadata(forName: rowProfile.id) { - cell.imageView?.image = metadata.logo - cell.leftText = metadata.description - } else { - cell.imageView?.image = Asset.Providers.placeholder.image - cell.leftText = rowProfile.id - } + let metadata = InfrastructureFactory.shared.metadata(forName: rowProfile.id) + cell.imageView?.image = metadata?.logo + cell.leftText = metadata?.description ?? rowProfile.id } else { cell.imageView?.image = nil cell.leftText = rowProfile.id diff --git a/Passepartout-iOS/Scenes/Organizer/WizardProviderViewController.swift b/Passepartout-iOS/Scenes/Organizer/WizardProviderViewController.swift index 886d9451..acf4e878 100644 --- a/Passepartout-iOS/Scenes/Organizer/WizardProviderViewController.swift +++ b/Passepartout-iOS/Scenes/Organizer/WizardProviderViewController.swift @@ -58,22 +58,60 @@ class WizardProviderViewController: UITableViewController, StrongTableHost { reloadModel() } - private func next(withMetadata metadata: Infrastructure.Metadata) { + private func tryNext(withMetadata metadata: Infrastructure.Metadata) { guard ProductManager.shared.isEligible(forProvider: metadata.name) else { presentPurchaseScreen(forProduct: metadata.product) return } + // make sure that infrastructure exists locally + guard let _ = InfrastructureFactory.shared.infrastructure(forName: metadata.name) else { + let hud = HUD(view: view) + _ = InfrastructureFactory.shared.update(metadata.name, notBeforeInterval: nil) { [weak self] in + hud.hide() + guard let _ = $0 else { + self?.alertMissingInfrastructure(forName: metadata.name, error: $1) + return + } + self?.next(withMetadata: metadata) + } + return + } + + next(withMetadata: metadata) + } + + private func next(withMetadata metadata: Infrastructure.Metadata) { let profile = ProviderConnectionProfile(name: metadata.name) createdProfile = profile let accountVC = StoryboardScene.Main.accountIdentifier.instantiate() - let infrastructure = InfrastructureFactory.shared.infrastructure(forName: metadata.name) + guard let infrastructure = InfrastructureFactory.shared.infrastructure(forName: metadata.name) else { + fatalError("Moving to credentials with nil infrastructure, not downloaded properly?") + } accountVC.usernamePlaceholder = infrastructure.defaults.username accountVC.infrastructureName = infrastructure.name accountVC.delegate = self navigationController?.pushViewController(accountVC, animated: true) } + + private func alertMissingInfrastructure(forName name: Infrastructure.Name, error: Error?) { + var message = L10n.Core.Wizards.Provider.Alerts.Unavailable.message + if let error = error { + log.error("Unable to download missing \(name) infrastructure (network error): \(error.localizedDescription)") + message.append(" \(error.localizedDescription)") + } else { + log.error("Unable to download missing \(name) infrastructure (API error)") + } + + let alert = UIAlertController.asAlert(name, message) + alert.addCancelAction(L10n.Core.Global.ok) + present(alert, animated: true, completion: nil) + + if let ip = tableView.indexPathForSelectedRow { + tableView.deselectRow(at: ip, animated: true) + } + } private func finish(withCredentials credentials: Credentials) { guard let profile = createdProfile else { @@ -94,10 +132,14 @@ class WizardProviderViewController: UITableViewController, StrongTableHost { return } - ProductManager.shared.listProducts { _ in + ProductManager.shared.listProducts { (products, error) in + hud.hide() + if let error = error { + log.error("Unable to list products: \(error)") + return + } self?.reloadModel() self?.tableView.reloadData() - hud.hide() } } } @@ -153,7 +195,7 @@ extension WizardProviderViewController { switch row { case .provider: let metadata = available[indexPath.row] - next(withMetadata: metadata) + tryNext(withMetadata: metadata) case .updateList: tableView.deselectRow(at: indexPath, animated: true) diff --git a/Passepartout-iOS/Scenes/Purchase/PurchaseViewController.swift b/Passepartout-iOS/Scenes/Purchase/PurchaseViewController.swift index 43ce7e22..5903ae22 100644 --- a/Passepartout-iOS/Scenes/Purchase/PurchaseViewController.swift +++ b/Passepartout-iOS/Scenes/Purchase/PurchaseViewController.swift @@ -90,7 +90,7 @@ class PurchaseViewController: UITableViewController, StrongTableHost { super.viewDidAppear(animated) let hud = HUD(view: view) - ProductManager.shared.listProducts { [weak self] _ in + ProductManager.shared.listProducts { [weak self] (_, _) in self?.reloadModel() self?.isLoading = false self?.tableView.reloadData() diff --git a/Podfile b/Podfile index dc6dfaf8..9cd1c968 100644 --- a/Podfile +++ b/Podfile @@ -14,7 +14,7 @@ def shared_pods pod 'SSZipArchive' for spec in ['About', 'Alerts', 'Dialogs', 'InApp', 'Misc', 'Options', 'Persistence', 'Reviewer', 'Tables', 'WebServices'] do - pod "Convenience/#{spec}", :git => 'https://github.com/keeshux/convenience', :commit => '7fe7dcf' + pod "Convenience/#{spec}", :git => 'https://github.com/keeshux/convenience', :commit => '3a191e8' #pod "Convenience/#{spec}", :path => '../../personal/convenience' end end diff --git a/Podfile.lock b/Podfile.lock index a7778eea..34a6afb9 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -36,16 +36,16 @@ PODS: - TunnelKit/Core DEPENDENCIES: - - Convenience/About (from `https://github.com/keeshux/convenience`, commit `7fe7dcf`) - - Convenience/Alerts (from `https://github.com/keeshux/convenience`, commit `7fe7dcf`) - - Convenience/Dialogs (from `https://github.com/keeshux/convenience`, commit `7fe7dcf`) - - Convenience/InApp (from `https://github.com/keeshux/convenience`, commit `7fe7dcf`) - - Convenience/Misc (from `https://github.com/keeshux/convenience`, commit `7fe7dcf`) - - Convenience/Options (from `https://github.com/keeshux/convenience`, commit `7fe7dcf`) - - Convenience/Persistence (from `https://github.com/keeshux/convenience`, commit `7fe7dcf`) - - Convenience/Reviewer (from `https://github.com/keeshux/convenience`, commit `7fe7dcf`) - - Convenience/Tables (from `https://github.com/keeshux/convenience`, commit `7fe7dcf`) - - Convenience/WebServices (from `https://github.com/keeshux/convenience`, commit `7fe7dcf`) + - Convenience/About (from `https://github.com/keeshux/convenience`, commit `3a191e8`) + - Convenience/Alerts (from `https://github.com/keeshux/convenience`, commit `3a191e8`) + - Convenience/Dialogs (from `https://github.com/keeshux/convenience`, commit `3a191e8`) + - Convenience/InApp (from `https://github.com/keeshux/convenience`, commit `3a191e8`) + - Convenience/Misc (from `https://github.com/keeshux/convenience`, commit `3a191e8`) + - Convenience/Options (from `https://github.com/keeshux/convenience`, commit `3a191e8`) + - Convenience/Persistence (from `https://github.com/keeshux/convenience`, commit `3a191e8`) + - Convenience/Reviewer (from `https://github.com/keeshux/convenience`, commit `3a191e8`) + - Convenience/Tables (from `https://github.com/keeshux/convenience`, commit `3a191e8`) + - Convenience/WebServices (from `https://github.com/keeshux/convenience`, commit `3a191e8`) - Kvitto - MBProgressHUD - SSZipArchive @@ -63,7 +63,7 @@ SPEC REPOS: EXTERNAL SOURCES: Convenience: - :commit: 7fe7dcf + :commit: 3a191e8 :git: https://github.com/keeshux/convenience TunnelKit: :commit: 8b17a13 @@ -71,7 +71,7 @@ EXTERNAL SOURCES: CHECKOUT OPTIONS: Convenience: - :commit: 7fe7dcf + :commit: 3a191e8 :git: https://github.com/keeshux/convenience TunnelKit: :commit: 8b17a13 @@ -87,6 +87,6 @@ SPEC CHECKSUMS: SwiftyBeaver: 3d3e93a12d648bd400b6f2948a7ef128b5b183c7 TunnelKit: 4b70c0d8b6727b407248b4271b7613225f63204b -PODFILE CHECKSUM: 10c7cb879b6ee3d5185f541e6a2c6d14e988ff0b +PODFILE CHECKSUM: 5b0c1f2c23e4a3ffa33152e231291a97351d7165 COCOAPODS: 1.8.4 diff --git a/Submodules/Core b/Submodules/Core index 5e25f768..ad0c3922 160000 --- a/Submodules/Core +++ b/Submodules/Core @@ -1 +1 @@ -Subproject commit 5e25f768fb66832c4a539e7ff6ba7fa80d918a12 +Subproject commit ad0c3922813e0e7261e2e90e8386604abb5cd9c5