Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Fix #8353: Add Subscription Custom Offer Codes Interaction #8354

Merged
merged 4 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions Sources/Brave/Frontend/Settings/SettingsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ class SettingsViewController: TableViewController {
case .notPurchased, .expired:
return BraveVPN.vpnState.enableVPNDestinationVC
case .purchased:
let vc = BraveVPNSettingsViewController()
let vc = BraveVPNSettingsViewController(iapObserver: BraveVPN.iapObserver)
vc.openURL = { [unowned self] url in
self.settingsDelegate?.settingsOpenURLInNewTab(url)
self.dismiss(animated: true)
Expand All @@ -623,7 +623,18 @@ class SettingsViewController: TableViewController {
}()

guard let vcToShow = vc else { return }
self.navigationController?.pushViewController(vcToShow, animated: true)

if VPNProductInfo.isComplete {
self.navigationController?.pushViewController(vcToShow, animated: true)
} else {
let alert = UIAlertController(
title: Strings.VPN.errorCantGetPricesTitle,
message: Strings.VPN.errorCantGetPricesBody,
preferredStyle: .alert)

alert.addAction(UIAlertAction(title: Strings.OKString, style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
},
image: Preferences.VPN.vpnReceiptStatus.value == BraveVPN.ReceiptResponse.Status.retryPeriod.rawValue
? UIImage(braveSystemNamed: "leo.warning.triangle-filled")?
Expand Down
15 changes: 15 additions & 0 deletions Sources/BraveStrings/BraveStrings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2820,6 +2820,11 @@ extension Strings {
value: "Manage Subscription",
comment: "Button to manage your VPN subscription")

public static let settingsRedeemOfferCode =
NSLocalizedString("vpn.settingsManageSubscription", tableName: "BraveShared", bundle: .module,
value: "Redeem Offer Code",
comment: "Button to redeem offer code subscription")

public static let settingsLinkReceipt =
NSLocalizedString("vpn.settingsLinkReceipt", tableName: "BraveShared", bundle: .module,
value: "Link purchase to your Brave account",
Expand Down Expand Up @@ -2904,6 +2909,11 @@ extension Strings {
NSLocalizedString("vpn.vpnConfigPermissionDeniedErrorTitle", tableName: "BraveShared", bundle: .module,
value: "Permission denied",
comment: "Title for an alert when the user didn't allow to install VPN profile")

public static let vpnRedeemCodeButtonActionTitle =
NSLocalizedString("vpn.vpnRedeemCodeButtonActionTitle", tableName: "BraveShared", bundle: .module,
value: "Redeem Code",
comment: "Title for a button for enabling the Redeem Code flow")

public static let vpnConfigPermissionDeniedErrorBody =
NSLocalizedString("vpn.vpnConfigPermissionDeniedErrorBody", tableName: "BraveShared", bundle: .module,
Expand All @@ -2929,6 +2939,11 @@ extension Strings {
NSLocalizedString("vpn.vpnErrorPurchaseFailedBody", tableName: "BraveShared", bundle: .module,
value: "Unable to complete purchase. Please try again, or check your payment details on Apple and try again.",
comment: "Message for error when VPN could not be purchased.")

public static let vpnErrorOfferCodeFailedBody =
NSLocalizedString("vpn.vpnErrorOfferCodeFailedBody", tableName: "BraveShared", bundle: .module,
value: "Unable to redeem offer code. Please try again, or check your offer code details and try again.",
comment: "Message for error when VPN offer code could not be redeemed.")

public static let vpnResetAlertTitle =
NSLocalizedString("vpn.vpnResetAlertTitle", tableName: "BraveShared", bundle: .module,
Expand Down
51 changes: 50 additions & 1 deletion Sources/BraveVPN/BraveVPNSettingsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ import GuardianConnect
public class BraveVPNSettingsViewController: TableViewController {

public var openURL: ((URL) -> Void)?
let iapObserver: IAPObserver

public init(iapObserver: IAPObserver) {
self.iapObserver = iapObserver

public init() {
super.init(style: .grouped)
}

Expand Down Expand Up @@ -146,6 +149,13 @@ public class BraveVPNSettingsViewController: TableViewController {
UIApplication.shared.open(url, options: [:])
}
},
cellClass: ButtonCell.self),
Row(text: Strings.VPN.settingsRedeemOfferCode,
selection: {
self.isLoading = false
// Open the redeem code sheet
SKPaymentQueue.default().presentCodeRedemptionSheet()
},
cellClass: ButtonCell.self)
] + linkReceiptRows,
footer: .title(Strings.VPN.settingsLinkReceiptFooter))
Expand Down Expand Up @@ -339,3 +349,42 @@ public class BraveVPNSettingsViewController: TableViewController {
isLoading = false
}
}

// MARK: - IAPObserverDelegate

extension BraveVPNSettingsViewController: IAPObserverDelegate {
public func purchasedOrRestoredProduct(validateReceipt: Bool) {
DispatchQueue.main.async {
self.isLoading = false
}

if validateReceipt {
BraveVPN.validateReceiptData()
}
}

public func purchaseFailed(error: IAPObserver.PurchaseError) {
// Handle Offer Code error
guard isLoading else {
return
}

handleOfferCodeError(error: error)
}

private func handleOfferCodeError(error: IAPObserver.PurchaseError) {
DispatchQueue.main.async {
self.isLoading = false

let message = Strings.VPN.vpnErrorOfferCodeFailedBody

let alert = UIAlertController(
title: Strings.VPN.vpnErrorPurchaseFailedTitle,
message: message,
preferredStyle: .alert)
let ok = UIAlertAction(title: Strings.OKString, style: .default, handler: nil)
alert.addAction(ok)
self.present(alert, animated: true)
}
}
}
34 changes: 27 additions & 7 deletions Sources/BraveVPN/BuyVPNViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ class BuyVPNViewController: VPNSetupLoadingController {
title: Strings.VPN.restorePurchases, style: .done,
target: self, action: #selector(restorePurchasesAction))

let actionTitle = Preferences.VPN.freeTrialUsed.value
let buyTitle = Preferences.VPN.freeTrialUsed.value
? Strings.VPN.activateSubscriptionAction.capitalized
: Strings.VPN.freeTrialPeriodAction.capitalized

let actionButton = BraveGradientButton(gradient: .backgroundGradient1).then {
let buyButton = BraveGradientButton(gradient: .backgroundGradient1).then {
$0.titleLabel?.font = .systemFont(ofSize: 15, weight: .bold)
$0.titleLabel?.textAlignment = .center

$0.setTitle(actionTitle, for: .normal)
$0.setTitle(buyTitle, for: .normal)

$0.snp.makeConstraints {
$0.height.equalTo(50)
Expand All @@ -66,7 +66,15 @@ class BuyVPNViewController: VPNSetupLoadingController {

$0.addTarget(self, action: #selector(startSubscriptionAction), for: .touchUpInside)
}


let redeemButton = UIButton().then {
$0.setTitle(Strings.VPN.vpnRedeemCodeButtonActionTitle, for: .normal)
$0.titleLabel?.font = .systemFont(ofSize: 13, weight: .medium)
$0.titleLabel?.textAlignment = .center

$0.addTarget(self, action: #selector(redeemOfferSubscriptionCode), for: .touchUpInside)
}

let seperator = UIView().then {
$0.backgroundColor = UIColor.white.withAlphaComponent(0.1)
$0.snp.makeConstraints { make in
Expand All @@ -76,7 +84,8 @@ class BuyVPNViewController: VPNSetupLoadingController {

view.addSubview(buyVPNView)
view.addSubview(seperator)
view.addSubview(actionButton)
view.addSubview(buyButton)
view.addSubview(redeemButton)

buyVPNView.snp.makeConstraints {
$0.leading.trailing.top.equalToSuperview()
Expand All @@ -87,9 +96,15 @@ class BuyVPNViewController: VPNSetupLoadingController {
$0.leading.trailing.equalToSuperview()
}

actionButton.snp.makeConstraints() {
buyButton.snp.makeConstraints() {
$0.top.equalTo(seperator.snp.bottom).inset(-12)
$0.leading.trailing.bottom.equalToSuperview().inset(24)
$0.leading.trailing.equalToSuperview().inset(24)
}

redeemButton.snp.makeConstraints() {
$0.top.equalTo(buyButton.snp.bottom).inset(-12)
$0.bottom.equalToSuperview().inset(24)
$0.centerX.equalToSuperview()
}

buyVPNView.monthlySubButton
Expand Down Expand Up @@ -154,6 +169,11 @@ class BuyVPNViewController: VPNSetupLoadingController {
addPaymentForSubcription(type: activeSubcriptionChoice)
}

@objc func redeemOfferSubscriptionCode() {
// Open the redeem code sheet
SKPaymentQueue.default().presentCodeRedemptionSheet()
}

private func addPaymentForSubcription(type: SubscriptionType) {
var subscriptionProduct: SKProduct?

Expand Down