Skip to content

Commit

Permalink
Subscriptions: 19. Error handling and minor updates (#2567)
Browse files Browse the repository at this point in the history
  • Loading branch information
afterxleep authored Mar 11, 2024
1 parent 576c98f commit bbacdd7
Show file tree
Hide file tree
Showing 18 changed files with 187 additions and 40 deletions.
14 changes: 8 additions & 6 deletions DuckDuckGo/SettingsSubscriptionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -138,25 +138,27 @@ struct SettingsSubscriptionView: View {
SettingsCellView(label: UserText.settingsPProDBPTitle,
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 Down
18 changes: 9 additions & 9 deletions DuckDuckGo/SettingsViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import Common
import Combine
import SyncUI


#if SUBSCRIPTION
import Subscription
#endif
Expand All @@ -47,12 +48,20 @@ final class SettingsViewModel: ObservableObject {
private var legacyViewProvider: SettingsLegacyViewProvider
private lazy var versionProvider: AppVersion = AppVersion.shared
private let voiceSearchHelper: VoiceSearchHelperProtocol

#if SUBSCRIPTION
private var accountManager: AccountManager
private var signOutObserver: Any?

// Sheet Presentation & Navigation
@Published var isRestoringSubscription: Bool = false
@Published var shouldDisplayRestoreSubscriptionError: Bool = false
@Published var shouldShowNetP = false
@Published var shouldShowDBP = false
@Published var shouldShowITP = false
#endif
@UserDefaultsWrapper(key: .subscriptionIsActive, defaultValue: false)
static private var cachedHasActiveSubscription: Bool


#if NETWORK_PROTECTION
Expand All @@ -63,10 +72,6 @@ final class SettingsViewModel: ObservableObject {
private lazy var isPad = UIDevice.current.userInterfaceIdiom == .pad
private var cancellables = Set<AnyCancellable>()

// Defaults
@UserDefaultsWrapper(key: .subscriptionIsActive, defaultValue: false)
static private var cachedHasActiveSubscription: Bool

// Closures to interact with legacy view controllers through the container
var onRequestPushLegacyView: ((UIViewController) -> Void)?
var onRequestPresentLegacyView: ((UIViewController, _ modal: Bool) -> Void)?
Expand All @@ -78,10 +83,6 @@ final class SettingsViewModel: ObservableObject {
@Published var shouldNavigateToDBP = false
@Published var shouldNavigateToITP = false
@Published var shouldNavigateToSubscriptionFlow = false

@Published var shouldShowNetP = false
@Published var shouldShowDBP = false
@Published var shouldShowITP = false

// Our View State
@Published private(set) var state: SettingsState
Expand Down Expand Up @@ -372,7 +373,6 @@ extension SettingsViewModel {
}
}
}

default:
// Account is active but there's not a valid subscription / entitlements
signOutUser()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ struct AsyncHeadlessWebView: View {
onContentType: { value in
viewModel.contentType = value
},
onNavigationError: { value in
viewModel.navigationError = value
},
navigationCoordinator: viewModel.navigationCoordinator
)
.frame(width: geometry.size.width, height: geometry.size.height)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ final class AsyncHeadlessWebViewViewModel: ObservableObject {
@Published var canGoBack: Bool = false
@Published var canGoForward: Bool = false
@Published var contentType: String = ""
@Published var navigationError: Error?
@Published var allowedDomains: [String]?

var navigationCoordinator = HeadlessWebViewNavCoordinator(webView: nil)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct HeadlessWebView: UIViewRepresentable {
var onCanGoBack: ((Bool) -> Void)?
var onCanGoForward: ((Bool) -> Void)?
var onContentType: ((String) -> Void)?
var onNavigationError: ((Error?) -> Void)?
var navigationCoordinator: HeadlessWebViewNavCoordinator

func makeUIView(context: Context) -> WKWebView {
Expand Down Expand Up @@ -73,6 +74,7 @@ struct HeadlessWebView: UIViewRepresentable {
onCanGoBack: onCanGoBack,
onCanGoForward: onCanGoForward,
onContentType: onContentType,
onNavigationError: onNavigationError,
settings: settings
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ final class HeadlessWebViewCoordinator: NSObject {
var onCanGoBack: ((Bool) -> Void)?
var onCanGoForward: ((Bool) -> Void)?
var onContentType: ((String) -> Void)?
var onNavigationError: ((Error?) -> Void)?
var settings: AsyncHeadlessWebViewSettings

var size: CGSize = .zero
Expand All @@ -52,6 +53,7 @@ final class HeadlessWebViewCoordinator: NSObject {
onCanGoBack: ((Bool) -> Void)?,
onCanGoForward: ((Bool) -> Void)?,
onContentType: ((String) -> Void)?,
onNavigationError: ((Error?) -> Void)?,
allowedDomains: [String]? = nil,
settings: AsyncHeadlessWebViewSettings = AsyncHeadlessWebViewSettings()) {
self.parent = parent
Expand All @@ -60,6 +62,7 @@ final class HeadlessWebViewCoordinator: NSObject {
self.onURLChange = onURLChange
self.onCanGoBack = onCanGoBack
self.onCanGoForward = onCanGoForward
self.onNavigationError = onNavigationError
self.onContentType = onContentType
self.settings = settings
}
Expand Down Expand Up @@ -106,6 +109,7 @@ final class HeadlessWebViewCoordinator: NSObject {
onCanGoBack = nil
onCanGoForward = nil
onContentType = nil
onNavigationError = nil
}

}
Expand All @@ -128,6 +132,7 @@ extension HeadlessWebViewCoordinator: WKNavigationDelegate {
}

func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
onNavigationError?(nil)
if let url = webView.url, url != lastURL {
onURLChange?(url)
lastURL = url
Expand Down Expand Up @@ -182,8 +187,12 @@ extension HeadlessWebViewCoordinator: WKNavigationDelegate {
decisionHandler(.allow)
}

func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: any Error) {
onNavigationError?(error)
}

func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
// NOOP
onNavigationError?(error)
}

// Javascript Confirm dialogs Delegate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,13 @@ final class IdentityTheftRestorationPagesFeature: Subfeature, ObservableObject {
return nil
}
}

func getAccessToken(params: Any, original: WKScriptMessage) async throws -> Encodable? {
let authToken = AccountManager().authToken ?? ""
return [Constants.token: authToken]
if let accessToken = AccountManager().accessToken {
return [Constants.token: accessToken]
} else {
return [String: String]()
}
}

deinit {
Expand Down
12 changes: 12 additions & 0 deletions DuckDuckGo/Subscription/ViewModel/SubscriptionEmailViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ final class SubscriptionEmailViewModel: ObservableObject {
@Published var activateSubscription = false
@Published var managingSubscriptionEmail = false
@Published var transactionError: SubscriptionRestoreError?
@Published var navigationError: Bool = false
@Published var shouldDisplayInactiveError: Bool = false
var webViewModel: AsyncHeadlessWebViewViewModel

Expand Down Expand Up @@ -101,6 +102,17 @@ final class SubscriptionEmailViewModel: ObservableObject {
}
}
.store(in: &cancellables)

webViewModel.$navigationError
.receive(on: DispatchQueue.main)
.sink { [weak self] error in
guard let strongSelf = self else { return }
DispatchQueue.main.async {
strongSelf.navigationError = error != nil ? true : false
}

}
.store(in: &cancellables)
}

private func handleTransactionError(error: SubscriptionPagesUseSubscriptionFeature.UseSubscriptionError) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,24 @@ final class SubscriptionFlowViewModel: ObservableObject {
}
.store(in: &cancellables)

webViewModel.$navigationError
.receive(on: DispatchQueue.main)
.sink { [weak self] error in
guard let strongSelf = self else { return }
DispatchQueue.main.async {
strongSelf.transactionError = error != nil ? .generalError : nil
}

}
.store(in: &cancellables)

canGoBackCancellable = webViewModel.$canGoBack
.receive(on: DispatchQueue.main)
.sink { [weak self] value in
self?.canNavigateBack = value
guard let strongSelf = self else { return }

let shouldNavigateBack = value && (strongSelf.webViewModel.url?.lastPathComponent != URL.subscriptionBaseURL.lastPathComponent)
strongSelf.canNavigateBack = shouldNavigateBack
}
}

Expand All @@ -242,6 +256,12 @@ final class SubscriptionFlowViewModel: ObservableObject {
canNavigateBack = false
}

private func urlRemovingQueryParams(_ url: URL) -> URL? {
var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false)
urlComponents?.query = nil // Remove the query string
return urlComponents?.url
}

func initializeViewData() async {
await self.setupTransactionObserver()
await self .setupWebViewObservers()
Expand All @@ -257,6 +277,7 @@ final class SubscriptionFlowViewModel: ObservableObject {
userTappedRestoreButton = false
shouldShowNavigationBar = false
selectedFeature = nil
transactionError = nil
canNavigateBack = false
shouldDismissView = true
subFeature.cleanup()
Expand Down
15 changes: 14 additions & 1 deletion DuckDuckGo/Subscription/ViewModel/SubscriptionITPViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ final class SubscriptionITPViewModel: ObservableObject {
@Published var isDownloadableContent: Bool = false
@Published var activityItems: [Any] = []
@Published var attachmentURL: URL?
@Published var navigationError: Bool = false
var webViewModel: AsyncHeadlessWebViewViewModel

@Published var shouldNavigateToExternalURL: URL?
Expand Down Expand Up @@ -81,9 +82,20 @@ final class SubscriptionITPViewModel: ObservableObject {
settings: webViewSettings)
}

// Observe transaction status
// swiftlint:disable function_body_length
private func setupSubscribers() async {

webViewModel.$navigationError
.receive(on: DispatchQueue.main)
.sink { [weak self] error in
guard let strongSelf = self else { return }
DispatchQueue.main.async {
strongSelf.navigationError = error != nil ? true : false
}

}
.store(in: &cancellables)

webViewModel.$scrollPosition
.receive(on: DispatchQueue.main)
.throttle(for: .milliseconds(100), scheduler: DispatchQueue.main, latest: true)
Expand Down Expand Up @@ -134,6 +146,7 @@ final class SubscriptionITPViewModel: ObservableObject {
self?.canNavigateBack = value
}
}
// swiftlint:enable function_body_length

func initializeView() {
webViewModel.navigationCoordinator.navigateTo(url: manageITPURL )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ final class SubscriptionRestoreViewModel: ObservableObject {
private func handleRestoreError(error: SubscriptionPagesUseSubscriptionFeature.UseSubscriptionError) {
switch error {
case .failedToRestorePastPurchase:
activationResult = .notFound
activationResult = .error
case .subscriptionExpired:
activationResult = .expired
case .subscriptionNotFound:
Expand Down
9 changes: 9 additions & 0 deletions DuckDuckGo/Subscription/Views/SubscriptionEmailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ struct SubscriptionEmailView: View {
)
}

.alert(isPresented: $viewModel.navigationError) {
Alert(
title: Text(UserText.subscriptionBackendErrorTitle),
message: Text(UserText.subscriptionBackendErrorMessage),
dismissButton: .cancel(Text(UserText.subscriptionBackendErrorButton)) {
dismiss()
})
}

.onAppear {
viewModel.loadURL()
}
Expand Down
Loading

0 comments on commit bbacdd7

Please sign in to comment.