Skip to content

Commit

Permalink
Merge branch 'main' into dominik/xcode-16
Browse files Browse the repository at this point in the history
# By Sam Symons (5) and others
# Via GitHub
* main:
  Remove VPN test rollout pixel (#3536)
  VPN clean-up (#3502)
  add daily pixel for deleting suggestions (#3531)
  Fix VPN memory pressure monitor (#3535)
  Update Ruby to 3.3.4 (#3547)
  Onboarding Add To Dock Pixels (#3543)
  Switch to free runners for tests that run on Maestro (#3546)
  Fix email protection test (#3539)
  Update BSK for PixelKit suffix change (#3534)
  Adding app backgrounded result to rule compilation (#3533)

# Conflicts:
#	DuckDuckGo.xcodeproj/project.pbxproj
#	DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
#	DuckDuckGoTests/ContextualDaxDialogsFactoryTests.swift
  • Loading branch information
samsymons committed Nov 7, 2024
2 parents d695208 + 1f334a5 commit 737619b
Show file tree
Hide file tree
Showing 21 changed files with 461 additions and 84 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/end-to-end.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
end-to-end-tests:
name: End to end Tests
needs: build-end-to-end-tests
runs-on: macos-14-xlarge
runs-on: macos-14
timeout-minutes: 90
strategy:
matrix:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/sync-end-to-end.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
sync-end-to-end-tests:
name: Sync End To End Tests
needs: build-for-sync-end-to-end-tests
runs-on: macos-14-xlarge
runs-on: macos-14
timeout-minutes: 90
strategy:
matrix:
Expand Down
2 changes: 1 addition & 1 deletion .maestro/release_tests/emailprotection.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ tags:
- scroll
- assertVisible: Email Protection
- tapOn: Email Protection
- assertVisible: Email privacy, simplified.
- assertVisible: Email privacy, protected.
- assertVisible:
id: searchEntry
- tapOn:
Expand Down
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.0.4
3.3.4
29 changes: 19 additions & 10 deletions Core/PixelEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,15 @@ extension Pixel {
case autocompleteDisplayedLocalHistory
case autocompleteDisplayedOpenedTab
case autocompleteSwipeToDelete
case autocompleteSwipeToDeleteDaily

case feedbackPositive
case feedbackNegativePrefix(category: String)

case brokenSiteReport

// MARK: - Onboarding

case onboardingIntroShownUnique
case onboardingIntroComparisonChartShownUnique
case onboardingIntroChooseBrowserCTAPressed
Expand Down Expand Up @@ -173,6 +176,15 @@ extension Pixel {
case daxDialogsEndOfJourneyNewTabUnique
case daxDialogsEndOfJourneyDismissed

// MARK: - Onboarding Add To Dock

case onboardingAddToDockPromoImpressionsUnique
case onboardingAddToDockPromoShowTutorialCTATapped
case onboardingAddToDockPromoDismissCTATapped
case onboardingAddToDockTutorialDismissCTATapped

// MARK: - Onboarding Add To Dock

case widgetsOnboardingCTAPressed
case widgetsOnboardingDeclineOptionPressed
case widgetsOnboardingMovedToBackground
Expand Down Expand Up @@ -400,10 +412,6 @@ extension Pixel {
case networkProtectionClientFailedToParseRegisteredServersResponse
case networkProtectionClientFailedToFetchLocations
case networkProtectionClientFailedToParseLocationsResponse
case networkProtectionClientFailedToEncodeRedeemRequest
case networkProtectionClientInvalidInviteCode
case networkProtectionClientFailedToRedeemInviteCode
case networkProtectionClientFailedToParseRedeemResponse
case networkProtectionClientInvalidAuthToken

case networkProtectionKeychainErrorFailedToCastKeychainValueToData
Expand Down Expand Up @@ -458,7 +466,6 @@ extension Pixel {
case networkProtectionVPNConfigurationRemovalFailed

case networkProtectionConfigurationInvalidPayload(configuration: Configuration)
case networkProtectionConfigurationPixelTest

case networkProtectionMalformedErrorDetected

Expand Down Expand Up @@ -968,6 +975,7 @@ extension Pixel.Event {
case .autocompleteDisplayedLocalHistory: return "m_autocomplete_display_local_history"
case .autocompleteDisplayedOpenedTab: return "m_autocomplete_display_switch_to_tab"
case .autocompleteSwipeToDelete: return "m_autocomplete_result_deleted"
case .autocompleteSwipeToDeleteDaily: return "m_autocomplete_result_deleted_daily"

case .feedbackPositive: return "mfbs_positive_submit"
case .feedbackNegativePrefix(category: let category): return "mfbs_negative_\(category)"
Expand Down Expand Up @@ -1004,6 +1012,11 @@ extension Pixel.Event {
case .daxDialogsEndOfJourneyNewTabUnique: return "m_dx_end_new_tab_unique"
case .daxDialogsEndOfJourneyDismissed: return "m_dx_end_dialog_dismissed"

case .onboardingAddToDockPromoImpressionsUnique: return "m_onboarding_add_to_dock_promo_impressions_unique"
case .onboardingAddToDockPromoShowTutorialCTATapped: return "m_onboarding_add_to_dock_promo_show_tutorial_button_tapped"
case .onboardingAddToDockPromoDismissCTATapped: return "m_onboarding_add_to_dock_promo_dismiss_button_tapped"
case .onboardingAddToDockTutorialDismissCTATapped: return "m_onboarding_add_to_dock_tutorial_dismiss_button_tapped"

case .widgetsOnboardingCTAPressed: return "m_o_w_a"
case .widgetsOnboardingDeclineOptionPressed: return "m_o_w_d"
case .widgetsOnboardingMovedToBackground: return "m_o_w_b"
Expand Down Expand Up @@ -1221,10 +1234,6 @@ extension Pixel.Event {
case .networkProtectionClientFailedToFetchLocations: return "m_netp_backend_api_error_failed_to_fetch_locations"
case .networkProtectionClientFailedToParseLocationsResponse:
return "m_netp_backend_api_error_parsing_locations_response_failed"
case .networkProtectionClientFailedToEncodeRedeemRequest: return "m_netp_backend_api_error_encoding_redeem_request_body_failed"
case .networkProtectionClientInvalidInviteCode: return "m_netp_backend_api_error_invalid_invite_code"
case .networkProtectionClientFailedToRedeemInviteCode: return "m_netp_backend_api_error_failed_to_redeem_invite_code"
case .networkProtectionClientFailedToParseRedeemResponse: return "m_netp_backend_api_error_parsing_redeem_response_failed"
case .networkProtectionClientInvalidAuthToken: return "m_netp_backend_api_error_invalid_auth_token"
case .networkProtectionKeychainErrorFailedToCastKeychainValueToData: return "m_netp_keychain_error_failed_to_cast_keychain_value_to_data"
case .networkProtectionKeychainReadError: return "m_netp_keychain_error_read_failed"
Expand Down Expand Up @@ -1269,7 +1278,6 @@ extension Pixel.Event {
case .networkProtectionVPNConfigurationRemovalFailed: return "m_netp_vpn_configuration_removal_failed"

case .networkProtectionConfigurationInvalidPayload(let config): return "m_netp_vpn_configuration_\(config.rawValue)_invalid_payload"
case .networkProtectionConfigurationPixelTest: return "m_netp_vpn_configuration_pixel_test"

case .networkProtectionMalformedErrorDetected: return "m_netp_vpn_malformed_error_detected"

Expand Down Expand Up @@ -1729,6 +1737,7 @@ extension Pixel.Event {

case tabClosed = "tab_closed"
case appQuit = "app_quit"
case appBackgrounded = "app_backgrounded"
case success

}
Expand Down
1 change: 1 addition & 0 deletions DuckDuckGo/AutocompleteViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ extension AutocompleteViewController: AutocompleteViewModelDelegate {
Task {
await historyManager.deleteHistoryForURL(url)
Pixel.fire(pixel: .autocompleteSwipeToDelete)
DailyPixel.fireDaily(.autocompleteSwipeToDeleteDaily)
requestSuggestions(query: self.query)
}
default:
Expand Down
11 changes: 0 additions & 11 deletions DuckDuckGo/EventMapping+NetworkProtectionError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,6 @@ extension EventMapping where Event == NetworkProtectionError {
case .failedToParseLocationListResponse(let error):
pixelEvent = .networkProtectionClientFailedToParseLocationsResponse
pixelError = error
case .failedToEncodeRedeemRequest:
pixelEvent = .networkProtectionClientFailedToEncodeRedeemRequest
case .invalidInviteCode:
pixelEvent = .networkProtectionClientInvalidInviteCode
case .failedToRedeemInviteCode(let error):
pixelEvent = .networkProtectionClientFailedToRedeemInviteCode
pixelError = error
case .failedToParseRedeemResponse(let error):
pixelEvent = .networkProtectionClientFailedToParseRedeemResponse
pixelError = error
case .invalidAuthToken:
pixelEvent = .networkProtectionClientInvalidAuthToken
case .failedToCastKeychainValueToData(field: let field):
Expand Down Expand Up @@ -85,7 +75,6 @@ extension EventMapping where Event == NetworkProtectionError {
.wireGuardInvalidState,
.wireGuardDnsResolution,
.wireGuardSetNetworkSettings,
.failedToRetrieveAuthToken,
.failedToFetchServerStatus,
.failedToParseServerStatusResponse:
pixelEvent = .networkProtectionUnhandledError
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,20 @@ extension OnboardingView {
private var animateTitle: Binding<Bool>
private var animateMessage: Binding<Bool>
private var showContent: Binding<Bool>
private let showTutorialAction: () -> Void
private let dismissAction: (_ fromAddToDock: Bool) -> Void

init(
animateTitle: Binding<Bool> = .constant(true),
animateMessage: Binding<Bool> = .constant(true),
showContent: Binding<Bool> = .constant(false),
showTutorialAction: @escaping () -> Void,
dismissAction: @escaping (_ fromAddToDock: Bool) -> Void
) {
self.animateTitle = animateTitle
self.animateMessage = animateMessage
self.showContent = showContent
self.showTutorialAction = showTutorialAction
self.dismissAction = dismissAction
}

Expand Down Expand Up @@ -77,6 +80,7 @@ extension OnboardingView {
OnboardingCTAButton(
title: UserText.AddToDockOnboarding.Buttons.addToDockTutorial,
action: {
showTutorialAction()
showAddToDockTutorial = true
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ struct OnboardingFinalDialog: View {
let message: String
let cta: String
let canShowAddToDockTutorial: Bool
let showAddToDockTutorialAction: () -> Void
let dismissAction: (_ fromAddToDock: Bool) -> Void

@State private var showAddToDockTutorial = false
Expand Down Expand Up @@ -234,6 +235,7 @@ struct OnboardingFinalDialog: View {
OnboardingCTAButton(
title: UserText.AddToDockOnboarding.Buttons.addToDockTutorial,
action: {
showAddToDockTutorialAction()
showAddToDockTutorial = true
}
)
Expand Down Expand Up @@ -327,6 +329,7 @@ struct OnboardingAddToDockTutorialContent: View {
message: UserText.DaxOnboardingExperiment.ContextualOnboarding.onboardingFinalScreenMessage,
cta: UserText.DaxOnboardingExperiment.ContextualOnboarding.onboardingFinalScreenButton,
canShowAddToDockTutorial: false,
showAddToDockTutorialAction: {},
dismissAction: { _ in }
)
.padding()
Expand All @@ -338,6 +341,7 @@ struct OnboardingAddToDockTutorialContent: View {
message: UserText.AddToDockOnboarding.EndOfJourney.message,
cta: UserText.AddToDockOnboarding.Buttons.dismiss,
canShowAddToDockTutorial: true,
showAddToDockTutorialAction: {},
dismissAction: { _ in }
)
.padding()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,21 +110,39 @@ final class NewTabDaxDialogFactory: NewTabDaxDialogProvider {
)
}

return FadeInView {
OnboardingFinalDialog(logoPosition: .top, message: message, cta: cta, canShowAddToDockTutorial: shouldShowAddToDock) { [weak self] isDismissedFromAddToDock in
if isDismissedFromAddToDock {
Logger.onboarding.debug("Dismissed from add to dock")
} else {
Logger.onboarding.debug("Dismissed from end of Journey")
self?.onboardingPixelReporter.trackEndOfJourneyDialogCTAAction()
let showAddToDockTutorialAction: () -> Void = { [weak self] in
self?.onboardingPixelReporter.trackAddToDockPromoShowTutorialCTAAction()
}

let dismissAction = { [weak self] isDismissedFromAddToDockTutorial in
if isDismissedFromAddToDockTutorial {
self?.onboardingPixelReporter.trackAddToDockTutorialDismissCTAAction()
} else {
self?.onboardingPixelReporter.trackEndOfJourneyDialogCTAAction()
if shouldShowAddToDock {
self?.onboardingPixelReporter.trackAddToDockPromoDismissCTAAction()
}
onDismiss()
}
onDismiss()
}

return FadeInView {
OnboardingFinalDialog(
logoPosition: .top,
message: message,
cta: cta,
canShowAddToDockTutorial: shouldShowAddToDock,
showAddToDockTutorialAction: showAddToDockTutorialAction,
dismissAction: dismissAction
)
}
.onboardingContextualBackgroundStyle(background: .illustratedGradient(gradientType))
.onFirstAppear { [weak self] in
self?.contextualOnboardingLogic.setFinalOnboardingDialogSeen()
self?.onboardingPixelReporter.trackScreenImpression(event: .daxDialogsEndOfJourneyNewTabUnique)
if shouldShowAddToDock {
self?.onboardingPixelReporter.trackAddToDockPromoImpression()
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,18 +193,36 @@ final class ExperimentContextualDaxDialogsFactory: ContextualDaxDialogsFactory {
)
}

return OnboardingFinalDialog(logoPosition: .left, message: message, cta: cta, canShowAddToDockTutorial: shouldShowAddToDock, dismissAction: { [weak delegate, weak self] isDismissedFromAddToDock in
let showAddToDockTutorialAction: () -> Void = { [weak self] in
self?.contextualOnboardingPixelReporter.trackAddToDockPromoShowTutorialCTAAction()
}

let dismissAction = { [weak delegate, weak self] isDismissedFromAddToDockTutorial in
delegate?.didTapDismissContextualOnboardingAction()
if isDismissedFromAddToDock {
Logger.onboarding.debug("Dismissed from add to dock")
if isDismissedFromAddToDockTutorial {
self?.contextualOnboardingPixelReporter.trackAddToDockTutorialDismissCTAAction()
} else {
Logger.onboarding.debug("Dismissed from end of Journey")
self?.contextualOnboardingPixelReporter.trackEndOfJourneyDialogCTAAction()
if shouldShowAddToDock {
self?.contextualOnboardingPixelReporter.trackAddToDockPromoDismissCTAAction()
}
}
})
}

return OnboardingFinalDialog(
logoPosition: .left,
message: message,
cta: cta,
canShowAddToDockTutorial: shouldShowAddToDock,
showAddToDockTutorialAction: showAddToDockTutorialAction,
dismissAction: dismissAction
)
.onFirstAppear { [weak self] in
self?.contextualOnboardingLogic.setFinalOnboardingDialogSeen()
self?.contextualOnboardingPixelReporter.trackScreenImpression(event: pixelName)
if shouldShowAddToDock {
self?.contextualOnboardingPixelReporter.trackAddToDockPromoImpression()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ final class OnboardingIntroViewModel: ObservableObject {
var onCompletingOnboardingIntro: (() -> Void)?
private var introSteps: [OnboardingIntroStep]

private let pixelReporter: OnboardingIntroPixelReporting
private let pixelReporter: OnboardingIntroPixelReporting & OnboardingAddToDockReporting
private let onboardingManager: OnboardingHighlightsManaging & OnboardingAddToDockManaging
private let isIpad: Bool
private let urlOpener: URLOpener
private let appIconProvider: () -> AppIcon
private let addressBarPositionProvider: () -> AddressBarPosition

init(
pixelReporter: OnboardingIntroPixelReporting,
pixelReporter: OnboardingIntroPixelReporting & OnboardingAddToDockReporting,
onboardingManager: OnboardingHighlightsManaging & OnboardingAddToDockManaging = OnboardingManager(),
isIpad: Bool = UIDevice.current.userInterfaceIdiom == .pad,
urlOpener: URLOpener = UIApplication.shared,
Expand Down Expand Up @@ -87,8 +87,17 @@ final class OnboardingIntroViewModel: ObservableObject {
handleSetDefaultBrowserAction()
}

func addToDockContinueAction() {
func addToDockContinueAction(isShowingAddToDockTutorial: Bool) {
state = makeViewState(for: .appIconSelection)
if isShowingAddToDockTutorial {
pixelReporter.trackAddToDockTutorialDismissCTAAction()
} else {
pixelReporter.trackAddToDockPromoDismissCTAAction()
}
}

func addtoDockShowTutorialAction() {
pixelReporter.trackAddToDockPromoShowTutorialCTAAction()
}

func appIconPickerContinueAction() {
Expand Down Expand Up @@ -150,6 +159,7 @@ private extension OnboardingIntroViewModel {
func handleSetDefaultBrowserAction() {
if onboardingManager.addToDockEnabledState == .intro && onboardingManager.isOnboardingHighlightsEnabled {
state = makeViewState(for: .addToDockPromo)
pixelReporter.trackAddToDockPromoImpression()
} else if onboardingManager.isOnboardingHighlightsEnabled {
state = makeViewState(for: .appIconSelection)
pixelReporter.trackChooseAppIconImpression()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,14 @@ struct OnboardingView: View {
}

private var addToDockPromoView: some View {
AddToDockPromoContent(dismissAction: { _ in model.addToDockContinueAction()
})
AddToDockPromoContent(
showTutorialAction: {
model.addtoDockShowTutorialAction()
},
dismissAction: { fromAddToDockTutorial in
model.addToDockContinueAction(isShowingAddToDockTutorial: fromAddToDockTutorial)
}
)
}

private var appIconPickerView: some View {
Expand Down
Loading

0 comments on commit 737619b

Please sign in to comment.