Skip to content

Commit

Permalink
Uplift of #26001 (squashed) to release
Browse files Browse the repository at this point in the history
  • Loading branch information
brave-builds committed Oct 17, 2024
1 parent 09671aa commit 5298d38
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 24 deletions.
11 changes: 9 additions & 2 deletions ios/brave-ios/Sources/AIChat/AIChatStrings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -357,9 +357,9 @@ extension Strings {
"aichat.paywallYearlySubscriptionDescription",
tableName: "BraveLeo",
bundle: .module,
value: "SAVE UP TO 25%",
value: "BEST VALUE",
comment:
"The description indicating yearly subscription that show how much user is saving percentage"
"The description indicating how valuable the yearly subscription is, compared to purchasing monthly"
)
public static let paywallYearlyPriceDividend = NSLocalizedString(
"aichat.paywallYearlyPriceDividend",
Expand Down Expand Up @@ -397,6 +397,13 @@ extension Strings {
value: "Upgrade Now",
comment: "The title of the button for action triggering purchase"
)
public static let paywallPurchaseActionIntroOfferTitle = NSLocalizedString(
"aichat.paywallPurchaseActionIntroOfferTitle",
tableName: "BraveLeo",
bundle: .module,
value: "Try 7 Days Free",
comment: "The title of the button for action triggering purchase"
)
public static let paywallPremiumUpsellTitle = NSLocalizedString(
"aichat.paywallPremiumUpsellTitle",
tableName: "BraveLeo",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,20 @@ struct AIChatPaywallView: View {
private var selectedTierType: AIChatSubscriptionTier = .monthly

@State
private var availableTierTypes: [AIChatSubscriptionTier] = [.monthly]
private var availableTierTypes: [AIChatSubscriptionTier] = [.monthly, .yearly]

@ObservedObject
private(set) var storeSDK = BraveStoreSDK.shared

@State
private var paymentStatus: AIChatPaymentStatus = .success

@State
private var isMonthlyIntroOfferAvailable: Bool = false

@State
private var isYearlyIntroOfferAvailable: Bool = false

@State
private var isShowingPurchaseAlert = false

Expand Down Expand Up @@ -151,6 +157,9 @@ struct AIChatPaywallView: View {
.onDisappear {
iapRestoreTimer?.cancel()
}
.task {
await fetchIntroOfferStatus()
}
}

private var tierSelection: some View {
Expand Down Expand Up @@ -203,10 +212,18 @@ struct AIChatPaywallView: View {
.tint(Color.white)
.padding()
} else {
Text(Strings.AIChat.paywallPurchaseActionTitle)
.font(.body.weight(.semibold))
.foregroundColor(Color(.white))
.padding()
let isIntroOfferAvailable =
(selectedTierType == .monthly && isMonthlyIntroOfferAvailable)
|| (selectedTierType == .yearly && isYearlyIntroOfferAvailable)

Text(
isIntroOfferAvailable
? Strings.AIChat.paywallPurchaseActionIntroOfferTitle
: Strings.AIChat.paywallPurchaseActionTitle
)
.font(.body.weight(.semibold))
.foregroundColor(Color(.white))
.padding()
}
}
.frame(maxWidth: .infinity)
Expand Down Expand Up @@ -282,6 +299,20 @@ struct AIChatPaywallView: View {
isShowingPurchaseAlert = true
}
}

private func fetchIntroOfferStatus() async {
paymentStatus = .ongoing

isMonthlyIntroOfferAvailable = await storeSDK.isIntroOfferAvailable(
for: BraveStoreProduct.leoMonthly
)

isYearlyIntroOfferAvailable = await storeSDK.isIntroOfferAvailable(
for: BraveStoreProduct.leoYearly
)

paymentStatus = .success
}
}

private struct AIChatPremiumTierSelectionView: View {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,23 +326,35 @@ public class AppStoreSDK: ObservableObject {
/// Retrieves a product's renewable subscription product
/// - Parameter product: The product whose SKU to retrieve
/// - Returns: The AppStore renewable subscription product
@MainActor
public func subscription(for product: any AppStoreProduct) async -> Product? {
allProducts.autoRenewable.first(where: { $0.id == product.rawValue })
}

/// Retrieves a product's renewable subscription status
/// - Parameter product: The product whose subscription status to retrieve
/// - Returns: The renewable subscription's status
@MainActor
public func status(for product: any AppStoreProduct) async -> [Product.SubscriptionInfo.Status] {
(try? await subscription(for: product)?.subscription?.status) ?? []
}

/// Retrieves a product's renewable subscription trial status
/// - Parameter product: The product whose subscription trial status to retrieve
/// - Returns: The renewable subscription's trial status
public func isIntroOfferAvailable(for product: any AppStoreProduct) async -> Bool {
guard let subscription = await subscription(for: product)?.subscription else {
return false
}

if subscription.introductoryOffer == nil {
return false
}

return await subscription.isEligibleForIntroOffer == true
}

/// Retrieves a product's renewable subscription renewal information
/// - Parameter product: The product whose renewal to retrieve
/// - Returns: The renewable subscription's renewal information
@MainActor
public func renewalState(
for product: any AppStoreProduct
) async -> Product.SubscriptionInfo.RenewalState? {
Expand All @@ -352,7 +364,6 @@ public class AppStoreSDK: ObservableObject {
/// Retrieves a product's transaction history
/// - Parameter product: The product whose last transaction history to retrieve
/// - Returns: The product's latest transaction history
@MainActor
public func latestTransaction(for product: any AppStoreProduct) async -> Transaction? {
if let transaction = await Transaction.latest(for: product.rawValue) {
do {
Expand All @@ -370,7 +381,6 @@ public class AppStoreSDK: ObservableObject {
/// Retrieves a customer's purchase entitlement of a specified product
/// - Parameter product: The product whose current subscription to retrieve
/// - Returns: The current product entitlement/purchase. Null if the customer is not currently entitled to this product
@MainActor
public func currentTransaction(for product: any AppStoreProduct) async -> Transaction? {
if let transaction = await Transaction.currentEntitlement(for: product.rawValue) {
do {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ public enum BraveStoreProduct: String, AppStoreProduct, CaseIterable {

switch self {
case .vpnMonthly, .leoMonthly: return "\(prefix)\(productId).monthly"
case .vpnYearly, .leoYearly: return "\(prefix)\(productId).yearly"
case .vpnYearly: return "\(prefix)\(productId).yearly"
case .leoYearly: return "\(prefix)\(productId).yearly.2"
}
}
}
Expand Down
44 changes: 33 additions & 11 deletions ios/brave-ios/Sources/BraveStore/Subscription/StoreKit.storekit
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
{
"appPolicies" : {
"eula" : "",
"policies" : [
{
"locale" : "en_US",
"policyText" : "",
"policyURL" : ""
}
]
},
"identifier" : "9019C18F",
"nonRenewingSubscriptions" : [

Expand Down Expand Up @@ -89,7 +99,10 @@
"recurringSubscriptionPeriod" : "P1M",
"referenceName" : "Brave Leo Monthly",
"subscriptionGroupID" : "AD92D716",
"type" : "RecurringSubscription"
"type" : "RecurringSubscription",
"winbackOffers" : [

]
},
{
"adHocOffers" : [
Expand All @@ -98,7 +111,7 @@
"codeOffers" : [

],
"displayPrice" : "150.00",
"displayPrice" : "149.99",
"familyShareable" : false,
"groupNumber" : 1,
"internalID" : "377962C3",
Expand All @@ -110,11 +123,14 @@
"locale" : "en_US"
}
],
"productID" : "braveleo.yearly",
"productID" : "braveleo.yearly.2",
"recurringSubscriptionPeriod" : "P1Y",
"referenceName" : "Brave Leo Yearly",
"subscriptionGroupID" : "AD92D716",
"type" : "RecurringSubscription"
"type" : "RecurringSubscription",
"winbackOffers" : [

]
}
]
},
Expand All @@ -132,9 +148,9 @@
"codeOffers" : [
{
"eligibility" : [
"expired",
"existing",
"new"
"new",
"expired"
],
"internalID" : "5CF353FA",
"isStackable" : true,
Expand All @@ -146,9 +162,9 @@
{
"displayPrice" : "7.99",
"eligibility" : [
"new",
"expired",
"existing",
"new"
"existing"
],
"internalID" : "3D43C72B",
"isStackable" : true,
Expand Down Expand Up @@ -183,7 +199,10 @@
"recurringSubscriptionPeriod" : "P1M",
"referenceName" : "Brave VPN Monthly",
"subscriptionGroupID" : "E6F28F94",
"type" : "RecurringSubscription"
"type" : "RecurringSubscription",
"winbackOffers" : [

]
},
{
"adHocOffers" : [
Expand Down Expand Up @@ -217,13 +236,16 @@
"recurringSubscriptionPeriod" : "P1Y",
"referenceName" : "Brave VPN Yearly",
"subscriptionGroupID" : "E6F28F94",
"type" : "RecurringSubscription"
"type" : "RecurringSubscription",
"winbackOffers" : [

]
}
]
}
],
"version" : {
"major" : 3,
"major" : 4,
"minor" : 0
}
}

0 comments on commit 5298d38

Please sign in to comment.