Merge branch 'dynamic-providers'

This commit is contained in:
Davide De Rosa 2019-11-28 11:52:43 +01:00
commit acf6663b26
19 changed files with 248 additions and 115 deletions

View File

@ -40,11 +40,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
override init() {
AppConstants.Log.configure()
InfrastructureFactory.shared.preload()
super.init()
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
InfrastructureFactory.shared.loadCache()
Theme.current.applyAppearance()
Reviewer.shared.eventCountBeforeRating = AppConstants.Rating.eventCount

View File

@ -77,8 +77,8 @@ class IssueReporter: NSObject {
var bodyMetadata = "--\n\n"
bodyMetadata += DebugLog(raw: "").decoratedString()
if let infrastructure = issue.infrastructure {
bodyMetadata += "Provider: \(infrastructure.name.rawValue)\n"
if let lastUpdated = InfrastructureFactory.shared.modificationDate(for: infrastructure.name) {
bodyMetadata += "Provider: \(infrastructure.name)\n"
if let lastUpdated = InfrastructureFactory.shared.modificationDate(forName: infrastructure.name) {
bodyMetadata += "Last updated: \(lastUpdated)\n"
}
bodyMetadata += "\n"

View File

@ -26,21 +26,28 @@
import Foundation
import PassepartoutCore
enum Product: String {
struct Product: RawRepresentable, Equatable, Hashable {
private static let bundle = "com.algoritmico.ios.Passepartout"
private static let donationsBundle = "\(bundle).donations"
private static let featuresBundle = "\(bundle).features"
private static let providersBundle = "\(bundle).providers"
// MARK: Donations
case tinyDonation = "com.algoritmico.ios.Passepartout.donations.Tiny"
static let tinyDonation = Product(donationDescription: "Tiny")
case smallDonation = "com.algoritmico.ios.Passepartout.donations.Small"
static let smallDonation = Product(donationDescription: "Small")
case mediumDonation = "com.algoritmico.ios.Passepartout.donations.Medium"
static let mediumDonation = Product(donationDescription: "Medium")
case bigDonation = "com.algoritmico.ios.Passepartout.donations.Big"
static let bigDonation = Product(donationDescription: "Big")
case hugeDonation = "com.algoritmico.ios.Passepartout.donations.Huge"
static let hugeDonation = Product(donationDescription: "Huge")
case maxiDonation = "com.algoritmico.ios.Passepartout.donations.Maxi"
static let maxiDonation = Product(donationDescription: "Maxi")
static let allDonations: [Product] = [
.tinyDonation,
@ -51,15 +58,19 @@ enum Product: String {
.maxiDonation
]
private init(donationDescription: String) {
self.init(rawValue: "\(Product.donationsBundle).\(donationDescription)")!
}
// MARK: Features
case unlimitedHosts = "com.algoritmico.ios.Passepartout.features.unlimited_hosts"
static let unlimitedHosts = Product(featureId: "unlimited_hosts")
case trustedNetworks = "com.algoritmico.ios.Passepartout.features.trusted_networks"
static let trustedNetworks = Product(featureId: "trusted_networks")
case siriShortcuts = "com.algoritmico.ios.Passepartout.features.siri"
static let siriShortcuts = Product(featureId: "features.siri")
case fullVersion = "com.algoritmico.ios.Passepartout.features.full_version"
static let fullVersion = Product(featureId: "full_version")
static let allFeatures: [Product] = [
.unlimitedHosts,
@ -67,55 +78,64 @@ enum Product: String {
.siriShortcuts,
.fullVersion
]
private init(featureId: String) {
self.init(rawValue: "\(Product.featuresBundle).\(featureId)")!
}
// MARK: Providers
case mullvad = "com.algoritmico.ios.Passepartout.providers.Mullvad"
case nordVPN = "com.algoritmico.ios.Passepartout.providers.NordVPN"
case pia = "com.algoritmico.ios.Passepartout.providers.PIA"
case protonVPN = "com.algoritmico.ios.Passepartout.providers.ProtonVPN"
case tunnelBear = "com.algoritmico.ios.Passepartout.providers.TunnelBear"
case vyprVPN = "com.algoritmico.ios.Passepartout.providers.VyprVPN"
case windscribe = "com.algoritmico.ios.Passepartout.providers.Windscribe"
static let allProviders: [Product] = [
.mullvad,
.nordVPN,
.pia,
.protonVPN,
.tunnelBear,
.vyprVPN,
.windscribe
]
static var allProviders: [Product] {
return InfrastructureFactory.shared.allMetadata.map {
return Product(providerId: $0.description)
}
}
fileprivate init(providerId: String) {
self.init(rawValue: "\(Product.providersBundle).\(providerId)")!
}
// MARK: All
static let all: [Product] = allDonations + allFeatures + allProviders
static var all: [Product] {
return allDonations + allFeatures + allProviders
}
var isDonation: Bool {
return Product.allDonations.contains(self)
return rawValue.hasPrefix(Product.donationsBundle)
}
var isFeature: Bool {
return Product.allFeatures.contains(self)
return rawValue.hasPrefix(Product.featuresBundle)
}
var isProvider: Bool {
return Product.allProviders.contains(self)
return rawValue.hasPrefix(Product.providersBundle)
}
// MARK: RawRepresentable
let rawValue: String
init?(rawValue: String) {
self.rawValue = rawValue
}
// MARK: Equatable
static func ==(lhs: Product, rhs: Product) -> Bool {
return lhs.rawValue == rhs.rawValue
}
// MARK: Hashable
func hash(into hasher: inout Hasher) {
rawValue.hash(into: &hasher)
}
}
extension Infrastructure.Name {
extension Infrastructure.Metadata {
var product: Product {
guard let product = Product(rawValue: "com.algoritmico.ios.Passepartout.providers.\(rawValue)") else {
fatalError("Product not found for provider \(rawValue)")
}
return product
return Product(providerId: description)
}
}

View File

@ -67,11 +67,9 @@ class ProductManager: NSObject {
}
func listProducts(completionHandler: (([SKProduct]) -> Void)?) {
guard inApp.products.isEmpty else {
completionHandler?(inApp.products)
return
}
inApp.requestProducts(withIdentifiers: Product.all) { _ in
log.debug("In-app products: \(self.inApp.products.map { $0.productIdentifier })")
completionHandler?(self.inApp.products)
}
}
@ -178,7 +176,7 @@ class ProductManager: NSObject {
return true
}
return purchasedFeatures.contains {
return $0.rawValue.hasSuffix("providers.\(name.rawValue)")
return $0.rawValue.hasSuffix("providers.\(name)")
}
}

View File

@ -284,6 +284,7 @@ internal enum Asset {
internal static let mullvad = ImageAsset(name: "mullvad")
internal static let nordvpn = ImageAsset(name: "nordvpn")
internal static let pia = ImageAsset(name: "pia")
internal static let placeholder = ImageAsset(name: "placeholder")
internal static let protonvpn = ImageAsset(name: "protonvpn")
internal static let tunnelbear = ImageAsset(name: "tunnelbear")
internal static let vyprvpn = ImageAsset(name: "vyprvpn")

View File

@ -1047,6 +1047,14 @@ internal enum L10n {
}
}
}
internal enum Provider {
internal enum Cells {
internal enum UpdateList {
/// Update list
internal static let caption = L10n.tr("Core", "wizards.provider.cells.update_list.caption")
}
}
}
}
}
}

View File

@ -189,9 +189,10 @@ extension MFMailComposeViewController {
}
}
extension Infrastructure.Name {
var logo: UIImage? {
return ImageAsset(name: rawValue.lowercased()).image
// FIXME: load from index JSON
extension Infrastructure.Metadata {
var logo: UIImage {
return ImageAsset(name: name.lowercased()).image
}
}

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "placeholder@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "placeholder@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -58,31 +58,35 @@ class AccountViewController: UIViewController, StrongTableHost {
}
private var guidanceString: String? {
guard let name = infrastructureName else {
guard let name = infrastructureName, let metadata = InfrastructureFactory.shared.metadata(forName: name) else {
return nil
}
// XXX: should make this dynamic
let V = L10n.Core.Account.Sections.Guidance.Footer.Infrastructure.self
switch name {
switch metadata.name {
case .mullvad:
return V.mullvad(name.rawValue)
return V.mullvad(metadata.description)
case .nordVPN:
return V.nordvpn(name.rawValue)
case .nordvpn:
return V.nordvpn(metadata.description)
case .pia:
return V.pia(name.rawValue)
return V.pia(metadata.description)
case .protonVPN:
return V.protonvpn(name.rawValue)
case .protonvpn:
return V.protonvpn(metadata.description)
case .tunnelBear:
return V.tunnelbear(name.rawValue)
case .tunnelbear:
return V.tunnelbear(metadata.description)
case .vyprVPN:
return V.vyprvpn(name.rawValue)
case .vyprvpn:
return V.vyprvpn(metadata.description)
case .windscribe:
return V.windscribe(name.rawValue)
return V.windscribe(metadata.description)
default:
return nil
}
}
@ -266,7 +270,7 @@ extension AccountViewController: UITableViewDataSource, UITableViewDelegate, Fie
fatalError("Sign-up shown when not a provider profile")
}
let cell = Cells.setting.dequeue(from: tableView, for: indexPath)
cell.leftText = L10n.Core.Account.Cells.Signup.caption(name.rawValue)
cell.leftText = L10n.Core.Account.Cells.Signup.caption(name)
cell.applyAction(.current)
return cell
}

View File

@ -39,8 +39,6 @@ class OrganizerViewController: UITableViewController, StrongTableHost {
private var hosts: [String] = []
private var availableProviderNames: [Infrastructure.Name]?
private var didShowSubreddit = false
// MARK: StrongTableHost
@ -176,8 +174,6 @@ class OrganizerViewController: UITableViewController, StrongTableHost {
}
vc.setProfile(selectedProfile)
} else if let providerVC = destination as? WizardProviderViewController {
providerVC.availableNames = availableProviderNames ?? []
}
}
@ -195,8 +191,7 @@ class OrganizerViewController: UITableViewController, StrongTableHost {
}
private func addNewProvider() {
let names = service.availableProviderNames()
guard !names.isEmpty else {
guard service.hasAvailableProviders() else {
let alert = UIAlertController.asAlert(
L10n.Core.Organizer.Sections.Providers.header,
L10n.Core.Organizer.Alerts.ExhaustedProviders.message
@ -205,7 +200,6 @@ class OrganizerViewController: UITableViewController, StrongTableHost {
present(alert, animated: true, completion: nil)
return
}
availableProviderNames = names
perform(segue: StoryboardSegue.Organizer.addProviderSegueIdentifier)
}
@ -479,12 +473,18 @@ extension OrganizerViewController {
case .profile:
let cell = Cells.setting.dequeue(from: tableView, for: indexPath)
let rowProfile = profileKey(at: indexPath)
if rowProfile.context == .provider, let providerName = Infrastructure.Name(rawValue: rowProfile.id) {
cell.imageView?.image = providerName.logo
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
}
} else {
cell.imageView?.image = nil
cell.leftText = rowProfile.id
}
cell.leftText = rowProfile.id
cell.rightText = service.isActiveProfile(rowProfile) ? L10n.Core.Organizer.Cells.Profile.Value.current : nil
return cell

View File

@ -25,29 +25,50 @@
import UIKit
import PassepartoutCore
import Convenience
import SwiftyBeaver
class WizardProviderViewController: UITableViewController {
var availableNames: [Infrastructure.Name] = []
private let log = SwiftyBeaver.self
class WizardProviderViewController: UITableViewController, StrongTableHost {
private var available: [Infrastructure.Metadata] = []
private var createdProfile: ProviderConnectionProfile?
// MARK: StrongTableHost
let model = StrongTableModel<SectionType, RowType>()
func reloadModel() {
available = TransientStore.shared.service.availableProviders()
model.clear()
model.add(.availableProviders)
model.add(.listActions)
model.set(.provider, count: available.count, forSection: .availableProviders)
model.set([.updateList], forSection: .listActions)
}
// MARK: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
title = L10n.Core.Organizer.Sections.Providers.header
reloadModel()
}
private func next(withName name: Infrastructure.Name) {
guard ProductManager.shared.isEligible(forProvider: name) else {
presentPurchaseScreen(forProduct: name.product)
private func next(withMetadata metadata: Infrastructure.Metadata) {
guard ProductManager.shared.isEligible(forProvider: metadata.name) else {
presentPurchaseScreen(forProduct: metadata.product)
return
}
let profile = ProviderConnectionProfile(name: name)
let profile = ProviderConnectionProfile(name: metadata.name)
createdProfile = profile
let accountVC = StoryboardScene.Main.accountIdentifier.instantiate()
let infrastructure = InfrastructureFactory.shared.get(name)
let infrastructure = InfrastructureFactory.shared.infrastructure(forName: metadata.name)
accountVC.usernamePlaceholder = infrastructure.defaults.username
accountVC.infrastructureName = infrastructure.name
accountVC.delegate = self
@ -63,6 +84,23 @@ class WizardProviderViewController: UITableViewController {
service.addOrReplaceProfile(profile, credentials: credentials)
}
}
private func updateProvidersList() {
let hud = HUD(view: view)
InfrastructureFactory.shared.updateIndex { [weak self] in
if let error = $0 {
hud.hide()
log.error("Unable to update providers list: \(error)")
return
}
ProductManager.shared.listProducts { _ in
self?.reloadModel()
self?.tableView.reloadData()
hud.hide()
}
}
}
@IBAction private func close() {
dismiss(animated: true, completion: nil)
@ -72,21 +110,55 @@ class WizardProviderViewController: UITableViewController {
// MARK: -
extension WizardProviderViewController {
enum SectionType {
case availableProviders
case listActions
}
enum RowType {
case provider
case updateList
}
override func numberOfSections(in tableView: UITableView) -> Int {
return model.numberOfSections
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return availableNames.count
return model.numberOfRows(forSection: section)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let name = availableNames[indexPath.row]
let row = model.row(at: indexPath)
let cell = Cells.setting.dequeue(from: tableView, for: indexPath)
cell.imageView?.image = name.logo
cell.leftText = name.rawValue
switch row {
case .provider:
let metadata = available[indexPath.row]
cell.apply(.current)
cell.imageView?.image = metadata.logo
cell.leftText = metadata.description
case .updateList:
cell.applyAction(.current)
cell.imageView?.image = nil
cell.leftText = L10n.Core.Wizards.Provider.Cells.UpdateList.caption
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let name = availableNames[indexPath.row]
next(withName: name)
let row = model.row(at: indexPath)
switch row {
case .provider:
let metadata = available[indexPath.row]
next(withMetadata: metadata)
case .updateList:
tableView.deselectRow(at: indexPath, animated: true)
updateProvidersList()
}
}
}

View File

@ -79,7 +79,7 @@ class ServiceViewController: UIViewController, StrongTableHost {
self.profile = profile
vpn.profile = profile
title = profile?.id
title = profile?.screenTitle
navigationItem.rightBarButtonItem = (profile?.context == .host) ? itemEdit : nil
if reloadingViews {
reloadModel()
@ -95,10 +95,9 @@ class ServiceViewController: UIViewController, StrongTableHost {
setProfile(service.activeProfile)
}
if let providerProfile = profile as? ProviderConnectionProfile {
lastInfrastructureUpdate = InfrastructureFactory.shared.modificationDate(for: providerProfile.name)
lastInfrastructureUpdate = InfrastructureFactory.shared.modificationDate(forName: providerProfile.name)
}
title = profile?.id
navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
navigationItem.leftItemsSupplementBackButton = true
@ -596,7 +595,7 @@ class ServiceViewController: UIViewController, StrongTableHost {
let alert = UIAlertController.asAlert(
L10n.Core.Service.Alerts.Download.title,
L10n.Core.Service.Alerts.Download.message(providerProfile.name.rawValue)
L10n.Core.Service.Alerts.Download.message(providerProfile.name)
)
alert.addCancelAction(L10n.Core.Global.cancel)
alert.addPreferredAction(L10n.Core.Global.ok) {

View File

@ -15,6 +15,7 @@
0E0C0729236087A100155AAC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0E0C072B236087A100155AAC /* InfoPlist.strings */; };
0E1066C920E0F84A004F98B7 /* Cells.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1066C820E0F84A004F98B7 /* Cells.swift */; };
0E158ADA20E11B0B00C85A82 /* EndpointViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E158AD920E11B0B00C85A82 /* EndpointViewController.swift */; };
0E1C0A4F238FC7A5009FC087 /* InfrastructureFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C0A4E238FC7A5009FC087 /* InfrastructureFactory.swift */; };
0E1D72B2213BFFCF00BA1586 /* ProviderPresetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1D72B1213BFFCF00BA1586 /* ProviderPresetViewController.swift */; };
0E1D72B4213C118500BA1586 /* ConfigurationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1D72B3213C118500BA1586 /* ConfigurationViewController.swift */; };
0E24273A225950450064A1A3 /* About.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E24273C225950450064A1A3 /* About.storyboard */; };
@ -38,7 +39,6 @@
0E3152C6223FA04800F61841 /* VPNProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED38AF1214177920004D387 /* VPNProvider.swift */; };
0E3152C7223FA04800F61841 /* VPNStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5E5DDE215119AF00E318A3 /* VPNStatus.swift */; };
0E3152C8223FA04D00F61841 /* Infrastructure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED31C1120CF0ABA0027975F /* Infrastructure.swift */; };
0E3152C9223FA04D00F61841 /* InfrastructureFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBE3A83213C6ADE00BFA2F5 /* InfrastructureFactory.swift */; };
0E3152CA223FA04D00F61841 /* InfrastructurePreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8D97E121388B52006FB4A0 /* InfrastructurePreset.swift */; };
0E3152CB223FA04D00F61841 /* Pool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED31C0F20CF09A30027975F /* Pool.swift */; };
0E3152CC223FA04D00F61841 /* WebServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E39BCEF214B9EF10035E9DE /* WebServices.swift */; };
@ -89,6 +89,8 @@
0E9CD7872257462800D033B4 /* Providers.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0E9CD7862257462800D033B4 /* Providers.xcassets */; };
0E9CD789225746B300D033B4 /* Flags.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0E9CD788225746B300D033B4 /* Flags.xcassets */; };
0E9CDB6723604AD5006733B4 /* ServerNetworkViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9CDB6623604AD5006733B4 /* ServerNetworkViewController.swift */; };
0EA84515238A9B5200EFC500 /* Infrastructure+Name.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA84514238A9B5100EFC500 /* Infrastructure+Name.swift */; };
0EA8451A238C2AB500EFC500 /* Infrastructure+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA84519238C2AB500EFC500 /* Infrastructure+Metadata.swift */; };
0EAAD71920E6669A0088754A /* GroupConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE8DED20C93E4C004C739C /* GroupConstants.swift */; };
0EB60FDA2111136E00AD27F3 /* UITextView+Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB60FD92111136E00AD27F3 /* UITextView+Search.swift */; };
0EB67D6B2184581E00BA6200 /* ImportedHostsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB67D6A2184581E00BA6200 /* ImportedHostsViewController.swift */; };
@ -169,6 +171,7 @@
0E0C072C236087C800155AAC /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = "<group>"; };
0E1066C820E0F84A004F98B7 /* Cells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cells.swift; sourceTree = "<group>"; };
0E158AD920E11B0B00C85A82 /* EndpointViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EndpointViewController.swift; sourceTree = "<group>"; };
0E1C0A4E238FC7A5009FC087 /* InfrastructureFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InfrastructureFactory.swift; path = Submodules/Core/Passepartout/Sources/Services/InfrastructureFactory.swift; sourceTree = SOURCE_ROOT; };
0E1D72B1213BFFCF00BA1586 /* ProviderPresetViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProviderPresetViewController.swift; sourceTree = "<group>"; };
0E1D72B3213C118500BA1586 /* ConfigurationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationViewController.swift; sourceTree = "<group>"; };
0E23B4A12298559800304C30 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
@ -258,6 +261,8 @@
0E9CD7862257462800D033B4 /* Providers.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Providers.xcassets; sourceTree = "<group>"; };
0E9CD788225746B300D033B4 /* Flags.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Flags.xcassets; sourceTree = "<group>"; };
0E9CDB6623604AD5006733B4 /* ServerNetworkViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerNetworkViewController.swift; sourceTree = "<group>"; };
0EA84514238A9B5100EFC500 /* Infrastructure+Name.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Infrastructure+Name.swift"; path = "Submodules/Core/Passepartout/Sources/Services/Infrastructure+Name.swift"; sourceTree = SOURCE_ROOT; };
0EA84519238C2AB500EFC500 /* Infrastructure+Metadata.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Infrastructure+Metadata.swift"; path = "Submodules/Core/Passepartout/Sources/Services/Infrastructure+Metadata.swift"; sourceTree = SOURCE_ROOT; };
0EB60FD92111136E00AD27F3 /* UITextView+Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextView+Search.swift"; sourceTree = "<group>"; };
0EB67D6A2184581E00BA6200 /* ImportedHostsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportedHostsViewController.swift; sourceTree = "<group>"; };
0EB9EB7223867E7F009C0A1C /* TrustedNetworksUI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrustedNetworksUI.swift; sourceTree = "<group>"; };
@ -272,7 +277,6 @@
0EBE2FD72360F89600F0D5AB /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
0EBE2FD82360F89600F0D5AB /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InfoPlist.strings; sourceTree = "<group>"; };
0EBE3A78213C4E5400BFA2F5 /* OrganizerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrganizerViewController.swift; sourceTree = "<group>"; };
0EBE3A83213C6ADE00BFA2F5 /* InfrastructureFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfrastructureFactory.swift; sourceTree = "<group>"; };
0EBE3A8F213C6F4000BFA2F5 /* TrustPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrustPolicy.swift; sourceTree = "<group>"; };
0EBE3A9E213DC1A100BFA2F5 /* ConnectionProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionProfile.swift; sourceTree = "<group>"; };
0EBE3A9F213DC1A100BFA2F5 /* ConnectionService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionService.swift; sourceTree = "<group>"; };
@ -545,7 +549,9 @@
isa = PBXGroup;
children = (
0ED31C1120CF0ABA0027975F /* Infrastructure.swift */,
0EBE3A83213C6ADE00BFA2F5 /* InfrastructureFactory.swift */,
0EA84519238C2AB500EFC500 /* Infrastructure+Metadata.swift */,
0EA84514238A9B5100EFC500 /* Infrastructure+Name.swift */,
0E1C0A4E238FC7A5009FC087 /* InfrastructureFactory.swift */,
0E8D97E121388B52006FB4A0 /* InfrastructurePreset.swift */,
0ED31C0F20CF09A30027975F /* Pool.swift */,
0E66A26F225FE25800F9C779 /* PoolCategory.swift */,
@ -969,6 +975,7 @@
0E3152C6223FA04800F61841 /* VPNProvider.swift in Sources */,
0E3152DA223FA05800F61841 /* PlaceholderConnectionProfile.swift in Sources */,
0E3152D0223FA05400F61841 /* ConnectionService+Migration.swift in Sources */,
0E1C0A4F238FC7A5009FC087 /* InfrastructureFactory.swift in Sources */,
0E3152D5223FA05400F61841 /* SessionProxy+Communication.swift in Sources */,
0E3152D7223FA05400F61841 /* TrustedNetworks.swift in Sources */,
0E3152DB223FA05800F61841 /* ProfileKey.swift in Sources */,
@ -985,17 +992,18 @@
0E3152CA223FA04D00F61841 /* InfrastructurePreset.swift in Sources */,
0E3152CE223FA05400F61841 /* ConnectionService.swift in Sources */,
0ED993B1223FF8C700B0F9C9 /* IntentDispatcher.swift in Sources */,
0EA84515238A9B5200EFC500 /* Infrastructure+Name.swift in Sources */,
0EEF23412321AC55000AEBE3 /* Issue.swift in Sources */,
0E3152C3223FA04800F61841 /* StandardVPNProvider.swift in Sources */,
0E3152D1223FA05400F61841 /* Credentials.swift in Sources */,
0E3152CD223FA05400F61841 /* ConnectionProfile.swift in Sources */,
0E3152BC223FA03D00F61841 /* ApplicationError.swift in Sources */,
0E3152C9223FA04D00F61841 /* InfrastructureFactory.swift in Sources */,
0E3152D3223FA05400F61841 /* EndpointDataSource.swift in Sources */,
0E3152D4223FA05400F61841 /* Preferences.swift in Sources */,
0EFB901822764689006405E4 /* ProfileNetworkSettings.swift in Sources */,
0E3152C0223FA03D00F61841 /* Utils.swift in Sources */,
0E3152CB223FA04D00F61841 /* Pool.swift in Sources */,
0EA8451A238C2AB500EFC500 /* Infrastructure+Metadata.swift in Sources */,
0EB9EB7323867E7F009C0A1C /* TrustedNetworksUI.swift in Sources */,
0E3CAFC0229AAE770008E5C8 /* Intents.intentdefinition in Sources */,
0E3152C7223FA04800F61841 /* VPNStatus.swift in Sources */,

View File

@ -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 => 'cfd2e57'
pod "Convenience/#{spec}", :git => 'https://github.com/keeshux/convenience', :commit => '7fe7dcf'
#pod "Convenience/#{spec}", :path => '../../personal/convenience'
end
end

View File

@ -36,16 +36,16 @@ PODS:
- TunnelKit/Core
DEPENDENCIES:
- Convenience/About (from `https://github.com/keeshux/convenience`, commit `cfd2e57`)
- Convenience/Alerts (from `https://github.com/keeshux/convenience`, commit `cfd2e57`)
- Convenience/Dialogs (from `https://github.com/keeshux/convenience`, commit `cfd2e57`)
- Convenience/InApp (from `https://github.com/keeshux/convenience`, commit `cfd2e57`)
- Convenience/Misc (from `https://github.com/keeshux/convenience`, commit `cfd2e57`)
- Convenience/Options (from `https://github.com/keeshux/convenience`, commit `cfd2e57`)
- Convenience/Persistence (from `https://github.com/keeshux/convenience`, commit `cfd2e57`)
- Convenience/Reviewer (from `https://github.com/keeshux/convenience`, commit `cfd2e57`)
- Convenience/Tables (from `https://github.com/keeshux/convenience`, commit `cfd2e57`)
- Convenience/WebServices (from `https://github.com/keeshux/convenience`, commit `cfd2e57`)
- 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`)
- Kvitto
- MBProgressHUD
- SSZipArchive
@ -63,7 +63,7 @@ SPEC REPOS:
EXTERNAL SOURCES:
Convenience:
:commit: cfd2e57
:commit: 7fe7dcf
:git: https://github.com/keeshux/convenience
TunnelKit:
:commit: 8b17a13
@ -71,7 +71,7 @@ EXTERNAL SOURCES:
CHECKOUT OPTIONS:
Convenience:
:commit: cfd2e57
:commit: 7fe7dcf
:git: https://github.com/keeshux/convenience
TunnelKit:
:commit: 8b17a13
@ -87,6 +87,6 @@ SPEC CHECKSUMS:
SwiftyBeaver: 3d3e93a12d648bd400b6f2948a7ef128b5b183c7
TunnelKit: 4b70c0d8b6727b407248b4271b7613225f63204b
PODFILE CHECKSUM: 51463b0e66ae367dd35c273e67cfc84659a41432
PODFILE CHECKSUM: 10c7cb879b6ee3d5185f541e6a2c6d14e988ff0b
COCOAPODS: 1.8.4

@ -1 +1 @@
Subproject commit 60b5c25a3cc79e0bffdd551c4593bdd18d291719
Subproject commit 72d464ab9291d7cb7521603742b04b3928d1d2c5

@ -1 +1 @@
Subproject commit 79cc4a739978b6fc98e910c65d7913431cb41915
Subproject commit 5e25f768fb66832c4a539e7ff6ba7fa80d918a12