Skip to content

Commit

Permalink
Add Free Trial to Leo on iOS
Browse files Browse the repository at this point in the history
  • Loading branch information
Brandon-T committed Oct 15, 2024
1 parent 87616ef commit 91551ce
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 6 deletions.
9 changes: 8 additions & 1 deletion ios/brave-ios/Sources/AIChat/AIChatStrings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ 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"
)
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,19 @@ struct AIChatPaywallView: View {
.tint(Color.white)
.padding()
} else {
Text(Strings.AIChat.paywallPurchaseActionTitle)
.font(.body.weight(.semibold))
.foregroundColor(Color(.white))
.padding()
if (selectedTierType == .monthly && isMonthlyIntroOfferAvailable)
|| (selectedTierType == .yearly && isYearlyIntroOfferAvailable)
{
Text(Strings.AIChat.paywallPurchaseActionIntroOfferTitle)
.font(.body.weight(.semibold))
.foregroundColor(Color(.white))
.padding()
} else {
Text(Strings.AIChat.paywallPurchaseActionTitle)
.font(.body.weight(.semibold))
.foregroundColor(Color(.white))
.padding()
}
}
}
.frame(maxWidth: .infinity)
Expand Down Expand Up @@ -282,6 +300,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 @@ -339,6 +339,22 @@ public class AppStoreSDK: ObservableObject {
(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
@MainActor
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
Expand Down

0 comments on commit 91551ce

Please sign in to comment.