Merge branch 'drop-single-features'
This commit is contained in:
commit
c3c3339878
|
@ -67,7 +67,7 @@ extension UIViewController {
|
|||
func presentPurchaseScreen(forProduct product: Product, delegate: PurchaseViewControllerDelegate? = nil) {
|
||||
let nav = StoryboardScene.Purchase.initialScene.instantiate()
|
||||
let vc = nav.topViewController as? PurchaseViewController
|
||||
vc?.feature = product
|
||||
// vc?.feature = product
|
||||
vc?.delegate = delegate
|
||||
|
||||
// enforce pre iOS 13 behavior
|
||||
|
|
|
@ -230,7 +230,7 @@ extension WizardProviderViewController: AccountViewControllerDelegate {
|
|||
// MARK: -
|
||||
|
||||
extension WizardProviderViewController: PurchaseViewControllerDelegate {
|
||||
func purchaseController(_ purchaseController: PurchaseViewController, didPurchase product: Product) {
|
||||
func purchaseController(_ purchaseController: PurchaseViewController, didPurchase product: Product?) {
|
||||
guard let metadata = selectedMetadata else {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -32,13 +32,13 @@ import Convenience
|
|||
private let log = SwiftyBeaver.self
|
||||
|
||||
protocol PurchaseViewControllerDelegate: class {
|
||||
func purchaseController(_ purchaseController: PurchaseViewController, didPurchase product: Product)
|
||||
func purchaseController(_ purchaseController: PurchaseViewController, didPurchase product: Product?)
|
||||
}
|
||||
|
||||
class PurchaseViewController: UITableViewController, StrongTableHost {
|
||||
private var isLoading = true
|
||||
|
||||
var feature: Product!
|
||||
var feature: Product?
|
||||
|
||||
weak var delegate: PurchaseViewControllerDelegate?
|
||||
|
||||
|
@ -66,29 +66,27 @@ class PurchaseViewController: UITableViewController, StrongTableHost {
|
|||
if let skPlatformVersion = pm.product(withIdentifier: .fullVersion_iOS) {
|
||||
self.skPlatformVersion = skPlatformVersion
|
||||
rows.append(.platformVersion)
|
||||
|
||||
let bullets: [String] = ProductManager.shared.featureProducts(excluding: [.fullVersion, .fullVersion_iOS, .fullVersion_macOS]).map {
|
||||
return $0.localizedTitle
|
||||
}.sortedCaseInsensitive()
|
||||
platformVersionExtra = bullets.joined(separator: "\n")
|
||||
}
|
||||
if let skFullVersion = pm.product(withIdentifier: .fullVersion) {
|
||||
if !pm.hasPurchased(.fullVersion_macOS), let skFullVersion = pm.product(withIdentifier: .fullVersion) {
|
||||
self.skFullVersion = skFullVersion
|
||||
rows.append(.fullVersion)
|
||||
|
||||
let bullets: [String] = ProductManager.shared.featureProducts(including: [.fullVersion_iOS, .fullVersion_macOS]).map {
|
||||
return $0.localizedTitle
|
||||
}.sortedCaseInsensitive()
|
||||
fullVersionExtra = bullets.joined(separator: "\n")
|
||||
}
|
||||
if let skFeature = pm.product(withIdentifier: feature) {
|
||||
if let feature = feature, let skFeature = pm.product(withIdentifier: feature) {
|
||||
self.skFeature = skFeature
|
||||
rows.append(.feature)
|
||||
}
|
||||
rows.append(.restore)
|
||||
model.set(rows, forSection: .products)
|
||||
|
||||
let platformBulletsList: [String] = ProductManager.shared.featureProducts(excluding: [.fullVersion, .fullVersion_iOS, .fullVersion_macOS]).map {
|
||||
return "- \($0.localizedTitle)"
|
||||
}.sortedCaseInsensitive()
|
||||
let platformBullets = platformBulletsList.joined(separator: "\n")
|
||||
platformVersionExtra = "- \(L10n.Core.Purchase.Cells.FullVersion.extraDescription(platformBullets))"
|
||||
|
||||
let fullBulletsList: [String] = ProductManager.shared.featureProducts(excluding: [.fullVersion, .fullVersion_iOS]).map {
|
||||
return "- \($0.localizedTitle)"
|
||||
}.sortedCaseInsensitive()
|
||||
let fullBullets = fullBulletsList.joined(separator: "\n")
|
||||
fullVersionExtra = "- \(L10n.Core.Purchase.Cells.FullVersion.extraDescription(fullBullets))"
|
||||
}
|
||||
|
||||
// MARK: UIViewController
|
||||
|
@ -96,10 +94,6 @@ class PurchaseViewController: UITableViewController, StrongTableHost {
|
|||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
guard let _ = feature else {
|
||||
fatalError("No feature set for purchase")
|
||||
}
|
||||
|
||||
title = L10n.Core.Purchase.title
|
||||
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(close))
|
||||
|
||||
|
@ -168,7 +162,7 @@ class PurchaseViewController: UITableViewController, StrongTableHost {
|
|||
guard let weakSelf = self else {
|
||||
return
|
||||
}
|
||||
let product = weakSelf.feature.matchesStoreKitProduct(skProduct) ? weakSelf.feature! : .fullVersion
|
||||
let product = Product(rawValue: skProduct.productIdentifier)
|
||||
weakSelf.delegate?.purchaseController(weakSelf, didPurchase: product)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ extension NSAlert {
|
|||
extension NSViewController {
|
||||
func presentPurchaseScreen(forProduct product: Product, delegate: PurchaseViewControllerDelegate? = nil) {
|
||||
let vc = StoryboardScene.Purchase.initialScene.instantiate()
|
||||
vc.feature = product
|
||||
// vc.feature = product
|
||||
vc.delegate = delegate
|
||||
presentAsModalWindow(vc)
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import Convenience
|
|||
private let log = SwiftyBeaver.self
|
||||
|
||||
protocol PurchaseViewControllerDelegate: class {
|
||||
func purchaseController(_ purchaseController: PurchaseViewController, didPurchase product: Product)
|
||||
func purchaseController(_ purchaseController: PurchaseViewController, didPurchase product: Product?)
|
||||
}
|
||||
|
||||
class PurchaseViewController: NSViewController {
|
||||
|
@ -52,7 +52,7 @@ class PurchaseViewController: NSViewController {
|
|||
|
||||
@IBOutlet private weak var buttonRestore: NSButton!
|
||||
|
||||
var feature: Product!
|
||||
var feature: Product?
|
||||
|
||||
weak var delegate: PurchaseViewControllerDelegate?
|
||||
|
||||
|
@ -74,27 +74,25 @@ class PurchaseViewController: NSViewController {
|
|||
if let skPlatformVersion = pm.product(withIdentifier: .fullVersion_macOS) {
|
||||
self.skPlatformVersion = skPlatformVersion
|
||||
rows.append(.platformVersion)
|
||||
|
||||
let bullets: [String] = ProductManager.shared.featureProducts(excluding: [.fullVersion, .fullVersion_iOS, .fullVersion_macOS, .siriShortcuts]).map {
|
||||
return $0.localizedTitle
|
||||
}.sortedCaseInsensitive()
|
||||
platformVersionExtra = bullets.joined(separator: "\n")
|
||||
}
|
||||
if let skFullVersion = pm.product(withIdentifier: .fullVersion) {
|
||||
if !pm.hasPurchased(.fullVersion_iOS), let skFullVersion = pm.product(withIdentifier: .fullVersion) {
|
||||
self.skFullVersion = skFullVersion
|
||||
rows.append(.fullVersion)
|
||||
|
||||
let bullets: [String] = ProductManager.shared.featureProducts(including: [.fullVersion_iOS, .fullVersion_macOS]).map {
|
||||
return $0.localizedTitle
|
||||
}.sortedCaseInsensitive()
|
||||
fullVersionExtra = bullets.joined(separator: "\n")
|
||||
}
|
||||
if let skFeature = pm.product(withIdentifier: feature) {
|
||||
if let feature = feature, let skFeature = pm.product(withIdentifier: feature) {
|
||||
self.skFeature = skFeature
|
||||
rows.append(.feature)
|
||||
}
|
||||
|
||||
let platformBulletsList: [String] = ProductManager.shared.featureProducts(excluding: [.siriShortcuts, .fullVersion, .fullVersion_iOS, .fullVersion_macOS]).map {
|
||||
return $0.localizedTitle
|
||||
}.sortedCaseInsensitive()
|
||||
let platformBullets = platformBulletsList.joined(separator: "\n")
|
||||
platformVersionExtra = L10n.Core.Purchase.Cells.FullVersion.extraDescription(platformBullets)
|
||||
|
||||
let fullBulletsList: [String] = ProductManager.shared.featureProducts(excluding: [.fullVersion, .fullVersion_macOS]).map {
|
||||
return $0.localizedTitle
|
||||
}.sortedCaseInsensitive()
|
||||
let fullBullets = fullBulletsList.joined(separator: "\n")
|
||||
fullVersionExtra = L10n.Core.Purchase.Cells.FullVersion.extraDescription(fullBullets)
|
||||
}
|
||||
|
||||
// MARK: NSViewController
|
||||
|
@ -108,10 +106,6 @@ class PurchaseViewController: NSViewController {
|
|||
buttonPurchase.title = L10n.Core.Purchase.title
|
||||
buttonRestore.title = L10n.Core.Purchase.Cells.Restore.title
|
||||
|
||||
guard let _ = feature else {
|
||||
fatalError("No feature set for purchase")
|
||||
}
|
||||
|
||||
tableView.usesAutomaticRowHeights = true
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
@ -197,7 +191,7 @@ class PurchaseViewController: NSViewController {
|
|||
guard let weakSelf = self else {
|
||||
return
|
||||
}
|
||||
let product = weakSelf.feature.matchesStoreKitProduct(skProduct) ? weakSelf.feature! : .fullVersion
|
||||
let product = Product(rawValue: skProduct.productIdentifier)
|
||||
weakSelf.delegate?.purchaseController(weakSelf, didPurchase: product)
|
||||
|
||||
self?.dismiss(nil)
|
||||
|
|
|
@ -108,7 +108,7 @@ class TrustedNetworksViewController: NSViewController, ProfileCustomization {
|
|||
|
||||
@IBAction private func toggleTrustEthernet(_ sender: Any?) {
|
||||
do {
|
||||
try ProductManager.shared.verifyEligibleForTrustedNetworks()
|
||||
try ProductManager.shared.verifyEligible(forFeature: .trustedNetworks)
|
||||
} catch {
|
||||
checkTrustEthernet.state = .off
|
||||
presentPurchaseScreen(forProduct: .trustedNetworks)
|
||||
|
@ -132,7 +132,7 @@ class TrustedNetworksViewController: NSViewController, ProfileCustomization {
|
|||
override func shouldPerformSegue(withIdentifier identifier: NSStoryboardSegue.Identifier, sender: Any?) -> Bool {
|
||||
if identifier == StoryboardSegue.Service.trustedNetworkAddSegueIdentifier.rawValue {
|
||||
do {
|
||||
try ProductManager.shared.verifyEligibleForTrustedNetworks()
|
||||
try ProductManager.shared.verifyEligible(forFeature: .trustedNetworks)
|
||||
} catch {
|
||||
presentPurchaseScreen(forProduct: .trustedNetworks)
|
||||
return false
|
||||
|
|
|
@ -554,7 +554,7 @@ public class ConnectionService: Codable {
|
|||
|
||||
var rules: [NEOnDemandRule] = []
|
||||
do {
|
||||
try ProductManager.shared.verifyEligibleForTrustedNetworks()
|
||||
try ProductManager.shared.verifyEligible(forFeature: .trustedNetworks)
|
||||
#if os(iOS)
|
||||
if profile.trustedNetworks.includesMobile {
|
||||
let rule = policyRule(for: profile)
|
||||
|
|
|
@ -66,6 +66,8 @@ public struct Product: RawRepresentable, Equatable, Hashable {
|
|||
|
||||
// MARK: Features
|
||||
|
||||
public static let allProviders = Product(featureId: "all_providers")
|
||||
|
||||
public static let trustedNetworks = Product(featureId: "trusted_networks")
|
||||
|
||||
public static let siriShortcuts = Product(featureId: "siri")
|
||||
|
@ -77,6 +79,7 @@ public struct Product: RawRepresentable, Equatable, Hashable {
|
|||
public static let fullVersion = Product(featureId: "full_multi_version")
|
||||
|
||||
public static let allFeatures: [Product] = [
|
||||
.allProviders,
|
||||
.trustedNetworks,
|
||||
.siriShortcuts,
|
||||
.fullVersion_iOS,
|
||||
|
|
|
@ -126,6 +126,21 @@ public class ProductManager: NSObject {
|
|||
return inApp.product(withIdentifier: identifier)
|
||||
}
|
||||
|
||||
public func featureProducts(including: [Product]) -> [SKProduct] {
|
||||
return inApp.products.filter {
|
||||
guard let p = Product(rawValue: $0.productIdentifier) else {
|
||||
return false
|
||||
}
|
||||
guard including.contains(p) else {
|
||||
return false
|
||||
}
|
||||
guard p.isFeature else {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public func featureProducts(excluding: [Product]) -> [SKProduct] {
|
||||
return inApp.products.filter {
|
||||
guard let p = Product(rawValue: $0.productIdentifier) else {
|
||||
|
@ -159,29 +174,30 @@ public class ProductManager: NSObject {
|
|||
|
||||
// MARK: In-app eligibility
|
||||
|
||||
public func isFullVersion() -> Bool {
|
||||
private func isCurrentPlatformVersion() -> Bool {
|
||||
#if os(iOS)
|
||||
if (isBeta && cfg.isBetaFullVersion) || purchasedFeatures.contains(.fullVersion_iOS) {
|
||||
return true
|
||||
}
|
||||
return purchasedFeatures.contains(.fullVersion_iOS)
|
||||
#else
|
||||
if (isBeta && cfg.isBetaFullVersion) || purchasedFeatures.contains(.fullVersion_macOS) {
|
||||
return purchasedFeatures.contains(.fullVersion_macOS)
|
||||
#endif
|
||||
}
|
||||
|
||||
private func isFullVersion() -> Bool {
|
||||
if isBeta && cfg.isBetaFullVersion {
|
||||
return true
|
||||
}
|
||||
if isCurrentPlatformVersion() {
|
||||
return true
|
||||
}
|
||||
#endif
|
||||
return purchasedFeatures.contains(.fullVersion)
|
||||
}
|
||||
|
||||
private func isEligible(forFeature feature: Product) -> Bool {
|
||||
#if os(iOS)
|
||||
return isFullVersion() || purchasedFeatures.contains(feature)
|
||||
}
|
||||
|
||||
private func isEligible(forProvider metadata: Infrastructure.Metadata) -> Bool {
|
||||
return isFullVersion() || purchasedFeatures.contains(metadata.product)
|
||||
}
|
||||
|
||||
private func isEligibleForTrustedNetworks() -> Bool {
|
||||
return isFullVersion() || purchasedFeatures.contains(.trustedNetworks)
|
||||
#else
|
||||
return isFullVersion()
|
||||
#endif
|
||||
}
|
||||
|
||||
public func isEligibleForFeedback() -> Bool {
|
||||
|
@ -211,23 +227,13 @@ public class ProductManager: NSObject {
|
|||
throw ProductError.beta
|
||||
}
|
||||
}
|
||||
guard isFullVersion() || purchasedFeatures.contains(metadata.product) else {
|
||||
guard isEligible(forFeature: metadata.product) else {
|
||||
throw ProductError.uneligible
|
||||
}
|
||||
}
|
||||
|
||||
public func verifyEligibleForTrustedNetworks() throws {
|
||||
if isBeta {
|
||||
if cfg.isBetaFullVersion {
|
||||
return
|
||||
}
|
||||
guard !cfg.locksBetaFeatures else {
|
||||
throw ProductError.beta
|
||||
}
|
||||
}
|
||||
guard isEligibleForTrustedNetworks() else {
|
||||
throw ProductError.uneligible
|
||||
}
|
||||
public func hasPurchased(_ product: Product) -> Bool {
|
||||
return purchasedFeatures.contains(product)
|
||||
}
|
||||
|
||||
public func isCancelledPurchase(_ product: Product) -> Bool {
|
||||
|
|
Loading…
Reference in New Issue