Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subscriptions: 20 - Subscription Caching #2569

Merged
merged 37 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
7d7b7f7
Entitlements caching
afterxleep Mar 7, 2024
0cd9e25
Update entitlements check
afterxleep Mar 8, 2024
201d093
Display errors on Subscription and Restore Flow
afterxleep Mar 8, 2024
23fa003
Avoid showing the back button in the root view
afterxleep Mar 8, 2024
663cc01
DIsmiss the Subscription Stack from restore (if required)
afterxleep Mar 8, 2024
f8da0bc
Remove internal BSK
afterxleep Mar 8, 2024
461aa58
Fix PIR sheet view
afterxleep Mar 8, 2024
226f4e1
Merge branch 'main' into daniel/subscriptions/19.subscription.errors
afterxleep Mar 8, 2024
4068456
Update to use AccessToken (not authToken)
afterxleep Mar 9, 2024
00ad77a
Replace accessToken with AuthToken
afterxleep Mar 9, 2024
a84c442
Use accessToken instead of authToken
afterxleep Mar 9, 2024
56f07ca
Revert Certificate match for Alpha
afterxleep Mar 9, 2024
1f1f259
Hide Back button in root Webview
afterxleep Mar 9, 2024
5502011
Display errors when WebViews Fail to load
afterxleep Mar 9, 2024
d78c038
Missin Subscription Flag
afterxleep Mar 9, 2024
85bae13
Subscription Caching
afterxleep Mar 9, 2024
0b875bd
Push canceled purchase update
afterxleep Mar 10, 2024
aad3e2d
Remove local caching from Settings
afterxleep Mar 10, 2024
486f9df
Remove manual Caching from SettingsViewModel
afterxleep Mar 10, 2024
c2ff0fd
Fix minor issue with view presentation
afterxleep Mar 10, 2024
eff5495
Remove BSK embed
afterxleep Mar 10, 2024
decda35
Fix issue with Sheet presentation for ITP and DBP
afterxleep Mar 10, 2024
bea6ad5
Revert Presentation Changes for sheets
afterxleep Mar 10, 2024
03491f8
Refresh settings on dismiss
afterxleep Mar 10, 2024
46ef260
Cleanup
afterxleep Mar 10, 2024
ddbba04
Fix linter
afterxleep Mar 10, 2024
7f90cb1
Merge branch 'daniel/subscriptions/19.subscription.errors' into danie…
afterxleep Mar 10, 2024
501b9f2
Removed unnecesary endif
afterxleep Mar 10, 2024
7848425
Removed unneded SUBSCRIPTION
afterxleep Mar 11, 2024
fce57fe
Move activeSubscriptionCache outside of compiler flag
afterxleep Mar 11, 2024
d92dd36
Move wrapped value out
afterxleep Mar 11, 2024
6fb68dd
Merge branch 'main' into daniel/subscriptions/19.subscription.errors
afterxleep Mar 11, 2024
ae5a427
Conflict merge fix
afterxleep Mar 11, 2024
00dd83a
Merge branch 'daniel/subscriptions/19.subscription.errors' into danie…
afterxleep Mar 11, 2024
9f87596
Merge branch 'main' into daniel/subscriptions/20.caching
miasma13 Mar 11, 2024
857f0be
Bump BSK
afterxleep Mar 11, 2024
e328502
Merge branch 'main' into daniel/subscriptions/20.caching
afterxleep Mar 11, 2024
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
2 changes: 1 addition & 1 deletion DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -10044,7 +10044,7 @@
repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit";
requirement = {
kind = exactVersion;
version = 122.0.0;
version = 122.1.0;
};
};
B6F997C22B8F374300476735 /* XCRemoteSwiftPackageReference "apple-toolbox" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/DuckDuckGo/BrowserServicesKit",
"state" : {
"revision" : "83bcbbf0dace717db6e518e4d867d617c846a3b5",
"version" : "122.0.0"
"revision" : "4042a8e04396584566df24fb90c7b529bbe1c661",
"version" : "122.1.0"
}
},
{
Expand Down
32 changes: 14 additions & 18 deletions DuckDuckGo/SettingsSubscriptionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ struct SettingsSubscriptionView: View {
action: { isShowingsubScriptionFlow = true },
isButton: true )

// Subscription Restore
.sheet(isPresented: $isShowingsubScriptionFlow,
onDismiss: { Task { viewModel.onAppear() } },
content: { SubscriptionFlowView(viewModel: subscriptionFlowViewModel).interactiveDismissDisabled() })

SettingsCustomCell(content: { iHaveASubscriptionView },
action: {
isShowingsubScriptionFlow = true
Expand Down Expand Up @@ -139,26 +144,29 @@ struct SettingsSubscriptionView: View {
subtitle: UserText.settingsPProDBPSubTitle,
action: { isShowingDBP.toggle() }, isButton: true)

.sheet(isPresented: $isShowingDBP) {
SubscriptionPIRView()
}

}

if viewModel.shouldShowITP {
SettingsCellView(label: UserText.settingsPProITRTitle,
subtitle: UserText.settingsPProITRSubTitle,
action: { isShowingITP.toggle() }, isButton: true)

.sheet(isPresented: $isShowingITP) {
SubscriptionITPView()
}

}

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

}
.sheet(isPresented: $isShowingDBP) {
SubscriptionPIRView()
}
.sheet(isPresented: $isShowingITP) {
SubscriptionITPView()
}

}

var body: some View {
Expand All @@ -181,18 +189,6 @@ struct SettingsSubscriptionView: View {
}

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


// Refresh subscription when dismissing the Subscription Flow
.onChange(of: isShowingsubScriptionFlow, perform: { value in
if !value {
Task { viewModel.onAppear() }
}
})

.onChange(of: viewModel.shouldNavigateToDBP, perform: { value in
if value {
Expand Down
44 changes: 18 additions & 26 deletions DuckDuckGo/SettingsViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,9 @@ extension SettingsViewModel {
// This manual (re)initialization will go away once appSettings and
// other dependencies are observable (Such as AppIcon and netP)
// and we can use subscribers (Currently called from the view onAppear)
private func initState() {
self.state = SettingsState(
@MainActor
private func initState() async {
self.state = await SettingsState(
appTheme: appSettings.currentThemeName,
appIcon: AppIconManager.shared.appIcon,
fireButtonAnimation: appSettings.currentFireButtonAnimation,
Expand All @@ -275,15 +276,6 @@ extension SettingsViewModel {

setupSubscribers()

#if SUBSCRIPTION
if #available(iOS 15, *) {
Task {
if state.subscription.enabled {
await setupSubscriptionEnvironment()
}
}
}
#endif
}

private func getNetworkProtectionState() -> SettingsState.NetworkProtection {
Expand All @@ -297,14 +289,24 @@ extension SettingsViewModel {
return SettingsState.NetworkProtection(enabled: enabled, status: "")
}

private func getSubscriptionState() -> SettingsState.Subscription {
private func getSubscriptionState() async -> SettingsState.Subscription {
var enabled = false
var canPurchase = false
let hasActiveSubscription = Self.cachedHasActiveSubscription
#if SUBSCRIPTION
var hasActiveSubscription = false

#if SUBSCRIPTION
if #available(iOS 15, *) {
enabled = featureFlagger.isFeatureOn(.subscription)
canPurchase = SubscriptionPurchaseEnvironment.canPurchase
#endif
await setupSubscriptionEnvironment()
if let token = AccountManager().accessToken {
let subscriptionResult = await SubscriptionService.getSubscription(accessToken: token)
if case .success(let subscription) = subscriptionResult {
hasActiveSubscription = subscription.isActive
}
}
}
#endif
return SettingsState.Subscription(enabled: enabled,
canPurchase: canPurchase,
hasActiveSubscription: hasActiveSubscription)
Expand Down Expand Up @@ -354,9 +356,6 @@ extension SettingsViewModel {

case .success(let subscription) where subscription.isActive:

// Cache Subscription state
cacheSubscriptionState(active: true)

// Check entitlements and update UI accordingly
let entitlements: [Entitlement.ProductName] = [.identityTheftRestoration, .dataBrokerProtection, .networkProtection]
for entitlement in entitlements {
Expand All @@ -382,18 +381,11 @@ extension SettingsViewModel {
@available(iOS 15.0, *)
private func signOutUser() {
AccountManager().signOut()
cacheSubscriptionState(active: false)
setupSubscriptionPurchaseOptions()
}

private func cacheSubscriptionState(active: Bool) {
self.state.subscription.hasActiveSubscription = active
Self.cachedHasActiveSubscription = active
}

@available(iOS 15.0, *)
private func setupSubscriptionPurchaseOptions() {
cacheSubscriptionState(active: false)
PurchaseManager.shared.$availableProducts
.receive(on: RunLoop.main)
.sink { [weak self] products in
Expand Down Expand Up @@ -470,7 +462,7 @@ extension SettingsViewModel {
extension SettingsViewModel {

func onAppear() {
initState()
Task { await initState() }
Task { await MainActor.run { navigateOnAppear() } }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature, ObservableObjec
switch error {
case .cancelledByUser:
setTransactionError(.cancelledByUser)
await pushPurchaseUpdate(originalMessage: message, purchaseUpdate: PurchaseUpdate(type: "canceled"))
return nil
case .accountCreationFailed:
setTransactionError(.accountCreationFailed)
case .activeSubscriptionAlreadyPresent:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,24 +56,16 @@ final class SubscriptionSettingsViewModel: ObservableObject {
}()

@MainActor
func fetchAndUpdateSubscriptionDetails() {
func fetchAndUpdateSubscriptionDetails(cachePolicy: SubscriptionService.CachePolicy = .returnCacheDataElseLoad) {
Task {
guard let token = accountManager.accessToken else { return }

if let cachedDate = SubscriptionService.cachedGetSubscriptionResponse?.expiresOrRenewsAt,
let cachedStatus = SubscriptionService.cachedGetSubscriptionResponse?.status,
let productID = SubscriptionService.cachedGetSubscriptionResponse?.productId {
updateSubscriptionDetails(status: cachedStatus, date: cachedDate, product: productID)
}

if case .success(let subscription) = await SubscriptionService.getSubscription(accessToken: token) {
if !subscription.isActive {
AccountManager().signOut()
shouldDismissView = true
return
} else {
updateSubscriptionDetails(status: subscription.status, date: subscription.expiresOrRenewsAt, product: subscription.productId)
}
guard let token = self.accountManager.accessToken else { return }
let subscriptionResult = await SubscriptionService.getSubscription(accessToken: token, cachePolicy: cachePolicy)
switch subscriptionResult {
case .success(let subscription):
updateSubscriptionDetails(status: subscription.status, date: subscription.expiresOrRenewsAt, product: subscription.productId)
case .failure(let error):
AccountManager().signOut()
shouldDismissView = true
}
}
}
Expand All @@ -86,11 +78,13 @@ final class SubscriptionSettingsViewModel: ObservableObject {
}
}

// Re-fetch subscription from server ignoring cache
// This ensure that if the user changed something on the Apple view, state will be updated
private func setupSubscriptionUpdater() {
subscriptionUpdateTimer = Timer.scheduledTimer(withTimeInterval: 10.0, repeats: true) { [weak self] _ in
guard let strongSelf = self else { return }
Task {
await strongSelf.fetchAndUpdateSubscriptionDetails()
await strongSelf.fetchAndUpdateSubscriptionDetails(cachePolicy: .reloadIgnoringLocalCacheData)
}
}
}
Expand All @@ -104,7 +98,7 @@ final class SubscriptionSettingsViewModel: ObservableObject {

func removeSubscription() {
AccountManager().signOut()
let messageView = ActionMessageView()
_ = ActionMessageView()
ActionMessageView.present(message: UserText.subscriptionRemovalConfirmation,
presentationLocation: .withoutBottomBar)
}
Expand Down
Loading