Skip to content

Commit

Permalink
16. Subscription: Display "Activation in progress" message (#2535)
Browse files Browse the repository at this point in the history
Description:
Display an "Activation in progress" message if there's an active subscription but no available entitlements.
  • Loading branch information
afterxleep authored Mar 5, 2024
1 parent 38d6eb2 commit 34deced
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 18 deletions.
92 changes: 76 additions & 16 deletions DuckDuckGo/SettingsSubscriptionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,19 @@ struct SettingsSubscriptionView: View {
@State var isShowingDBP = false
@State var isShowingITP = false

enum Constants {
static let purchaseDescriptionPadding = 5.0
static let topCellPadding = 3.0
static let noEntitlementsIconWidth = 20.0
static let navigationDelay = 0.3
static let infoIcon = "info-16"
}

private var subscriptionDescriptionView: some View {
VStack(alignment: .leading) {
Text(UserText.settingsPProSubscribe).daxBodyRegular()
Group {
Text(UserText.settingsPProDescription).daxFootnoteRegular().padding(.bottom, 5)
Text(UserText.settingsPProDescription).daxFootnoteRegular().padding(.bottom, Constants.purchaseDescriptionPadding)
Text(UserText.settingsPProFeatures).daxFootnoteRegular()
}.foregroundColor(Color(designSystemColor: .textSecondary))
}
Expand All @@ -53,20 +61,38 @@ struct SettingsSubscriptionView: View {
.foregroundColor(Color.init(designSystemColor: .accent))
}

@ViewBuilder
private var restorePurchaseView: some View {
let text = !viewModel.isRestoringSubscription ? UserText.subscriptionActivateAppleIDButton : UserText.subscriptionRestoringTitle
SettingsCustomCell(content: {
Text(text)
.daxBodyRegular()
.foregroundColor(Color.init(designSystemColor: .accent)) },
action: {
Task { await viewModel.restoreAccountPurchase() }
},
isButton: !viewModel.isRestoringSubscription )
.alert(isPresented: $viewModel.shouldDisplayRestoreSubscriptionError) {
Alert(
title: Text(UserText.subscriptionAppStoreErrorTitle),
message: Text(UserText.subscriptionAppStoreErrorMessage),
dismissButton: .default(Text(UserText.actionOK)) {}
)
}
}

private var manageSubscriptionView: some View {
Text(UserText.settingsPProManageSubscription)
.daxBodyRegular()
}


@ViewBuilder
private var purchaseSubscriptionView: some View {
return Group {
Group {
SettingsCustomCell(content: { subscriptionDescriptionView })
SettingsCustomCell(content: { learnMoreView },
action: { isShowingsubScriptionFlow = true },
isButton: true )
.sheet(isPresented: $isShowingsubScriptionFlow) {
SubscriptionFlowView(viewModel: subscriptionFlowViewModel).interactiveDismissDisabled()
}

SettingsCustomCell(content: { iHaveASubscriptionView },
action: {
Expand All @@ -78,8 +104,28 @@ struct SettingsSubscriptionView: View {
}
}

@ViewBuilder
private var noEntitlementsAvailableView: some View {
Group {
SettingsCustomCell(content: {
HStack(alignment: .top) {
Image(Constants.infoIcon)
.frame(width: Constants.noEntitlementsIconWidth)
.padding(.top, Constants.topCellPadding)
VStack(alignment: .leading) {
Text(UserText.settingsPProActivationPendingTitle).daxBodyRegular()
Text(UserText.settingsPProActivationPendingDescription).daxFootnoteRegular()
.padding(.bottom, Constants.purchaseDescriptionPadding)
}.foregroundColor(Color(designSystemColor: .textSecondary))
}
})
restorePurchaseView
}
}

@ViewBuilder
private var subscriptionDetailsView: some View {
return Group {
Group {
if viewModel.shouldShowNetP {
SettingsCellView(label: UserText.settingsPProVPNTitle,
subtitle: viewModel.state.networkProtection.status != "" ? viewModel.state.networkProtection.status : nil,
Expand All @@ -105,26 +151,40 @@ struct SettingsSubscriptionView: View {
SubscriptionITPView()
}
}

if viewModel.shouldShowDBP || viewModel.shouldShowITP || viewModel.shouldShowNetP {
NavigationLink(destination: SubscriptionSettingsView()) {
SettingsCustomCell(content: { manageSubscriptionView })
}

NavigationLink(destination: SubscriptionSettingsView()) {
SettingsCustomCell(content: { manageSubscriptionView })
}

}
}

var body: some View {
if viewModel.state.subscription.enabled {
Section(header: Text(UserText.settingsPProSection)) {
if viewModel.state.subscription.hasActiveSubscription {
subscriptionDetailsView

// Allow managing the subscription if we have some entitlements
if viewModel.shouldShowDBP || viewModel.shouldShowITP || viewModel.shouldShowNetP {
subscriptionDetailsView

// If no entitlements it should mean the backend is still out of sync
} else {
noEntitlementsAvailableView
}

} else {
purchaseSubscriptionView

}

}
// Subscription Restore
.sheet(isPresented: $isShowingsubScriptionFlow) {
SubscriptionFlowView(viewModel: subscriptionFlowViewModel).interactiveDismissDisabled()
}


// Refresh subscription when dismissing the Subscription Flow
.onChange(of: isShowingsubScriptionFlow, perform: { value in
if !value {
Expand All @@ -135,7 +195,7 @@ struct SettingsSubscriptionView: View {
.onChange(of: viewModel.shouldNavigateToDBP, perform: { value in
if value {
// Allow the sheet to dismiss before presenting a new one
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Constants.navigationDelay) {
isShowingDBP = true
}
}
Expand All @@ -144,7 +204,7 @@ struct SettingsSubscriptionView: View {
.onChange(of: viewModel.shouldNavigateToITP, perform: { value in
if value {
// Allow the sheet to dismiss before presenting a new one
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Constants.navigationDelay) {
isShowingITP = true
}
}
Expand Down
23 changes: 22 additions & 1 deletion DuckDuckGo/SettingsViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ final class SettingsViewModel: ObservableObject {
#if SUBSCRIPTION
private var accountManager: AccountManager
private var signOutObserver: Any?
@Published var isRestoringSubscription: Bool = false
@Published var shouldDisplayRestoreSubscriptionError: Bool = false
#endif


Expand Down Expand Up @@ -405,7 +407,26 @@ extension SettingsViewModel {
}
}

#endif
@available(iOS 15.0, *)
func restoreAccountPurchase() async {
DispatchQueue.main.async { self.isRestoringSubscription = true }
let result = await AppStoreRestoreFlow.restoreAccountFromPastPurchase()
switch result {
case .success:
DispatchQueue.main.async {
self.isRestoringSubscription = false
}
await self.setupSubscriptionEnvironment()

case .failure:
DispatchQueue.main.async {
self.isRestoringSubscription = false
self.shouldDisplayRestoreSubscriptionError = true
}
}
}

#endif // SUBSCRIPTION

#if NETWORK_PROTECTION
private func updateNetPStatus(connectionStatus: ConnectionStatus) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "info-16.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion DuckDuckGo/UserText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -999,7 +999,11 @@ But if you *do* want a peek under the hood, you can find more information about
public static let settingsPProDBPSubTitle = NSLocalizedString("settings.subscription.DBP.subtitle", value: "Remove your info from sites that sell it", comment: "Data Broker protection cell subtitle for privacy pro")
public static let settingsPProITRTitle = NSLocalizedString("settings.subscription.ITR.title", value: "Identity Theft Restoration", comment: "Identity theft restoration cell title for privacy pro")
public static let settingsPProITRSubTitle = NSLocalizedString("settings.subscription.ITR.subtitle", value: "If your identity is stolen, we'll help restore it", comment: "Identity theft restoration cell subtitle for privacy pro")


public static let settingsPProActivationPendingTitle = NSLocalizedString("settings.subscription.activation.pending.title", value: "Your Subscription is Being Activated", comment: "Subscription activation pending title")
public static let settingsPProActivationPendingDescription = NSLocalizedString("settings.subscription.activation.pending.description", value: "This is taking longer than usual, please check back later.", comment: "Subscription activation pending description")


// Customize Section
public static let settingsCustomizeSection = NSLocalizedString("settings.customize", value: "Customize", comment: "Settings title for the customize section")
public static let settingsKeyboard = NSLocalizedString("settings.keyboard", value: "Keyboard", comment: "Settings screen cell for Keyboard")
Expand Down
6 changes: 6 additions & 0 deletions DuckDuckGo/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1855,6 +1855,12 @@ But if you *do* want a peek under the hood, you can find more information about
/* Settings title for the privacy section */
"settings.privacy" = "Privacy";

/* Subscription activation pending description */
"settings.subscription.activation.pending.description" = "This is taking longer than usual, please check back later.";

/* Subscription activation pending title */
"settings.subscription.activation.pending.title" = "Your Subscription is Being Activated";

/* Data Broker protection cell subtitle for privacy pro */
"settings.subscription.DBP.subtitle" = "Remove your info from sites that sell it";

Expand Down

0 comments on commit 34deced

Please sign in to comment.