Skip to content

Commit

Permalink
Contextual Onboarding - Ensure hosted SwiftUI view updates container …
Browse files Browse the repository at this point in the history
…size for for iOS < 16 (#3137)

Co-authored-by: Alessandro Boron <[email protected]>
  • Loading branch information
SabrinaTardio and alessandroboron authored Jul 25, 2024
1 parent 1bf0e26 commit 137d8b0
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ typealias ContextualOnboardingDelegate = OnboardingNavigationDelegate & Contextu
// MARK: - Contextual Dialogs Factory

protocol ContextualDaxDialogsFactory {
func makeView(for spec: DaxDialogs.BrowsingSpec, delegate: ContextualOnboardingDelegate) -> UIHostingController<AnyView>
func makeView(for spec: DaxDialogs.BrowsingSpec, delegate: ContextualOnboardingDelegate, onSizeUpdate: @escaping () -> Void) -> UIHostingController<AnyView>
}

final class ExperimentContextualDaxDialogsFactory: ContextualDaxDialogsFactory {
Expand All @@ -48,15 +48,28 @@ final class ExperimentContextualDaxDialogsFactory: ContextualDaxDialogsFactory {
self.contextualOnboardingSettings = contextualOnboardingSettings
}

func makeView(for spec: DaxDialogs.BrowsingSpec, delegate: ContextualOnboardingDelegate) -> UIHostingController<AnyView> {
func makeView(for spec: DaxDialogs.BrowsingSpec, delegate: ContextualOnboardingDelegate, onSizeUpdate: @escaping () -> Void) -> UIHostingController<AnyView> {
let rootView: AnyView
switch spec.type {
case .afterSearch:
rootView = AnyView(afterSearchDialog(shouldFollowUpToWebsiteSearch: !contextualOnboardingSettings.userHasSeenTrackersDialog, delegate: delegate))
rootView = AnyView(
afterSearchDialog(
shouldFollowUpToWebsiteSearch: !contextualOnboardingSettings.userHasSeenTrackersDialog,
delegate: delegate,
onSizeUpdate: onSizeUpdate
)
)
case .visitWebsite:
rootView = AnyView(tryVisitingSiteDialog(delegate: delegate))
case .siteIsMajorTracker, .siteOwnedByMajorTracker, .withMultipleTrackers, .withOneTracker, .withoutTrackers:
rootView = AnyView(withTrackersDialog(for: spec, shouldFollowUpToFireDialog: !contextualOnboardingSettings.userHasSeenFireDialog, delegate: delegate))
rootView = AnyView(
withTrackersDialog(
for: spec,
shouldFollowUpToFireDialog: !contextualOnboardingSettings.userHasSeenFireDialog,
delegate: delegate,
onSizeUpdate: onSizeUpdate
)
)
case .fire:
rootView = AnyView(OnboardingFireDialog())
case .final:
Expand All @@ -72,18 +85,21 @@ final class ExperimentContextualDaxDialogsFactory: ContextualDaxDialogsFactory {
return hostingController
}

private func afterSearchDialog(shouldFollowUpToWebsiteSearch: Bool, delegate: ContextualOnboardingDelegate) -> some View {
private func afterSearchDialog(shouldFollowUpToWebsiteSearch: Bool, delegate: ContextualOnboardingDelegate, onSizeUpdate: @escaping () -> Void) -> some View {
let viewModel = OnboardingSiteSuggestionsViewModel(delegate: delegate)
// If should not show websites search after searching inform the delegate that the user dimissed the dialog, otherwise let the dialog handle it.

let gotItAction: () -> Void = if shouldFollowUpToWebsiteSearch {
{ [weak delegate] in
onSizeUpdate()
delegate?.didAcknowledgeContextualOnboardingSearch()
}
} else {
{ [weak delegate] in
delegate?.didTapDismissContextualOnboardingAction()
}
}

return OnboardingFirstSearchDoneDialog(shouldFollowUp: shouldFollowUpToWebsiteSearch, viewModel: viewModel, gotItAction: gotItAction)
}

Expand All @@ -92,13 +108,14 @@ final class ExperimentContextualDaxDialogsFactory: ContextualDaxDialogsFactory {
return OnboardingTryVisitingSiteDialog(logoPosition: .left, viewModel: viewModel)
}

private func withTrackersDialog(for spec: DaxDialogs.BrowsingSpec, shouldFollowUpToFireDialog: Bool, delegate: ContextualOnboardingDelegate) -> some View {
private func withTrackersDialog(for spec: DaxDialogs.BrowsingSpec, shouldFollowUpToFireDialog: Bool, delegate: ContextualOnboardingDelegate, onSizeUpdate: @escaping () -> Void) -> some View {
let attributedMessage = spec.message.attributedStringFromMarkdown(color: ThemeManager.shared.currentTheme.daxDialogTextColor)
return OnboardingTrackersDoneDialog(shouldFollowUp: shouldFollowUpToFireDialog, message: attributedMessage, blockedTrackersCTAAction: { [weak self, weak delegate] in
// If the user has not seen the fire dialog yet proceed to the fire dialog, otherwise dismiss the dialog.
if self?.contextualOnboardingSettings.userHasSeenFireDialog == true {
delegate?.didTapDismissContextualOnboardingAction()
} else {
onSizeUpdate()
delegate?.didAcknowledgeContextualOnboardingTrackersDialog()
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,12 @@ private extension ContextualOnboardingPresenter {
)
let platformSpecificSpec = spec.withUpdatedMessage(platformSpecificMessage)
// Ask the Dax Dialogs Factory for a view for the given spec
let controller = daxDialogsFactory.makeView(for: platformSpecificSpec, delegate: vc)
let controller = daxDialogsFactory.makeView(for: platformSpecificSpec, delegate: vc, onSizeUpdate: { [weak vc] in
if #unavailable(iOS 16.0) {
// For iOS 15 and below invalidate the intrinsic content size manually so the UIKit view will re-size accordingly to SwiftUI view.
vc?.daxContextualOnboardingController?.view.invalidateIntrinsicContentSize()
}
})
controller.view.isHidden = true
controller.view.alpha = 0

Expand Down
20 changes: 10 additions & 10 deletions DuckDuckGoTests/ContextualDaxDialogsFactoryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ final class ContextualDaxDialogsFactoryTests: XCTestCase {
let spec = DaxDialogs.BrowsingSpec.afterSearch

// WHEN
let result = sut.makeView(for: spec, delegate: delegate)
let result = sut.makeView(for: spec, delegate: delegate, onSizeUpdate: {})

// THEN
let view = try XCTUnwrap(find(OnboardingFirstSearchDoneDialog.self, in: result))
Expand All @@ -59,7 +59,7 @@ final class ContextualDaxDialogsFactoryTests: XCTestCase {
// GIVEN
settingsMock.userHasSeenTrackersDialog = true
let spec = DaxDialogs.BrowsingSpec.afterSearch
let result = sut.makeView(for: spec, delegate: delegate)
let result = sut.makeView(for: spec, delegate: delegate, onSizeUpdate: {})
let view = try XCTUnwrap(find(OnboardingFirstSearchDoneDialog.self, in: result))
XCTAssertFalse(delegate.didCallDidTapDismissContextualOnboardingAction)

Expand All @@ -75,7 +75,7 @@ final class ContextualDaxDialogsFactoryTests: XCTestCase {
// GIVEN
settingsMock.userHasSeenTrackersDialog = false
let spec = DaxDialogs.BrowsingSpec.afterSearch
let result = sut.makeView(for: spec, delegate: delegate)
let result = sut.makeView(for: spec, delegate: delegate, onSizeUpdate: {})
let view = try XCTUnwrap(find(OnboardingFirstSearchDoneDialog.self, in: result))
XCTAssertFalse(delegate.didCallDidTapDismissContextualOnboardingAction)

Expand All @@ -93,7 +93,7 @@ final class ContextualDaxDialogsFactoryTests: XCTestCase {
// GIVEN
settingsMock.userHasSeenTrackersDialog = true
let spec = DaxDialogs.BrowsingSpec(message: "", cta: "", highlightAddressBar: false, pixelName: .onboardingIntroShownUnique, type: .visitWebsite)
let result = sut.makeView(for: spec, delegate: delegate)
let result = sut.makeView(for: spec, delegate: delegate, onSizeUpdate: {})
let view = try XCTUnwrap(find(OnboardingTryVisitingSiteDialog.self, in: result))
XCTAssertFalse(delegate.didCallDidTapDismissContextualOnboardingAction)

Expand All @@ -112,7 +112,7 @@ final class ContextualDaxDialogsFactoryTests: XCTestCase {
// GIVEN
try [DaxDialogs.BrowsingSpec.siteIsMajorTracker, .siteOwnedByMajorTracker, .withMultipleTrackers, .withoutTrackers, .withoutTrackers].forEach { spec in
// WHEN
let result = sut.makeView(for: spec, delegate: delegate)
let result = sut.makeView(for: spec, delegate: delegate, onSizeUpdate: {})

// THEN
let view = try XCTUnwrap(find(OnboardingTrackersDoneDialog.self, in: result))
Expand All @@ -125,7 +125,7 @@ final class ContextualDaxDialogsFactoryTests: XCTestCase {
// GIVEN
delegate = ContextualOnboardingDelegateMock()
settingsMock.userHasSeenFireDialog = false
let result = sut.makeView(for: spec, delegate: delegate)
let result = sut.makeView(for: spec, delegate: delegate, onSizeUpdate: {})
let view = try XCTUnwrap(find(OnboardingTrackersDoneDialog.self, in: result))
XCTAssertFalse(delegate.didCallDidAcknowledgeContextualOnboardingTrackersDialog)

Expand All @@ -142,7 +142,7 @@ final class ContextualDaxDialogsFactoryTests: XCTestCase {
// GIVEN
delegate = ContextualOnboardingDelegateMock()
settingsMock.userHasSeenFireDialog = true
let result = sut.makeView(for: spec, delegate: delegate)
let result = sut.makeView(for: spec, delegate: delegate, onSizeUpdate: {})
let view = try XCTUnwrap(find(OnboardingTrackersDoneDialog.self, in: result))
XCTAssertFalse(delegate.didCallDidTapDismissContextualOnboardingAction)

Expand All @@ -160,7 +160,7 @@ final class ContextualDaxDialogsFactoryTests: XCTestCase {
let spec = DaxDialogs.BrowsingSpec(message: "", cta: "", highlightAddressBar: false, pixelName: .onboardingIntroShownUnique, type: .fire)

// WHEN
let result = sut.makeView(for: spec, delegate: delegate)
let result = sut.makeView(for: spec, delegate: delegate, onSizeUpdate: {})

// THEN
let view = try XCTUnwrap(find(OnboardingFireDialog.self, in: result))
Expand All @@ -175,7 +175,7 @@ final class ContextualDaxDialogsFactoryTests: XCTestCase {
let spec = DaxDialogs.BrowsingSpec.final

// WHEN
let result = sut.makeView(for: spec, delegate: delegate)
let result = sut.makeView(for: spec, delegate: delegate, onSizeUpdate: {})

// THEN
let view = try XCTUnwrap(find(OnboardingFinalDialog.self, in: result))
Expand All @@ -185,7 +185,7 @@ final class ContextualDaxDialogsFactoryTests: XCTestCase {
func test_WhenCallActionOnOnboardingFinalDialog_ThenDidTapDismissContextualOnboardingActionOnDelegateIsCalled() throws {
// GIVEN
let spec = DaxDialogs.BrowsingSpec.final
let result = sut.makeView(for: spec, delegate: delegate)
let result = sut.makeView(for: spec, delegate: delegate, onSizeUpdate: {})
let view = try XCTUnwrap(find(OnboardingFinalDialog.self, in: result))
XCTAssertFalse(delegate.didCallDidTapDismissContextualOnboardingAction)

Expand Down

0 comments on commit 137d8b0

Please sign in to comment.