From 0d487b360fa3079dbd2dba5dbd51fdd548b140e4 Mon Sep 17 00:00:00 2001 From: Graeme Arthur <2030310+graeme@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:34:19 +0100 Subject: [PATCH] Add Pixels --- DuckDuckGo.xcodeproj/project.pbxproj | 6 ++++++ .../Preferences/Model/SyncPreferences.swift | 14 +++++++++---- .../ViewModels/ManagementDialogModel.swift | 21 ++++++++++++------- .../SyncUI/Views/ManagementDialog.swift | 2 +- UnitTests/Sync/SyncPreferencesTests.swift | 4 ++-- 5 files changed, 33 insertions(+), 14 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 54a78969d2..ddc49819ec 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -3146,6 +3146,8 @@ EEEFA3422D142AB1006A3F8A /* CombineTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEEFA33F2D142AA6006A3F8A /* CombineTestHelpers.swift */; }; EEEFA3432D142AB1006A3F8A /* CombineTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEEFA33F2D142AA6006A3F8A /* CombineTestHelpers.swift */; }; EEEFA3442D142AB1006A3F8A /* CombineTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEEFA33F2D142AA6006A3F8A /* CombineTestHelpers.swift */; }; + EEEFA3462D145328006A3F8A /* SyncPixels.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEEFA3452D145322006A3F8A /* SyncPixels.swift */; }; + EEEFA3472D145328006A3F8A /* SyncPixels.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEEFA3452D145322006A3F8A /* SyncPixels.swift */; }; EEF12E6F2A2111880023E6BF /* MacPacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF12E6D2A2111880023E6BF /* MacPacketTunnelProvider.swift */; }; EEF53E182950CED5002D78F4 /* JSAlertViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF53E172950CED5002D78F4 /* JSAlertViewModelTests.swift */; }; F10C99422C7E20A1005568B4 /* Logger+DBPBackgroundAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = F17E7DDB2C7C7F8100907A84 /* Logger+DBPBackgroundAgent.swift */; }; @@ -4983,6 +4985,7 @@ EEE11C5D2C7F54AD000ABD7E /* AutofillLoginImportState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillLoginImportState.swift; sourceTree = ""; }; EEE50C282C38249C003DD7FF /* OptionalExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OptionalExtension.swift; sourceTree = ""; }; EEEFA33F2D142AA6006A3F8A /* CombineTestHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CombineTestHelpers.swift; sourceTree = ""; }; + EEEFA3452D145322006A3F8A /* SyncPixels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncPixels.swift; sourceTree = ""; }; EEF12E6D2A2111880023E6BF /* MacPacketTunnelProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacPacketTunnelProvider.swift; sourceTree = ""; }; EEF53E172950CED5002D78F4 /* JSAlertViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSAlertViewModelTests.swift; sourceTree = ""; }; F118EA7C2BEA2B8700F77634 /* DefaultSubscriptionFeatureAvailability+DefaultInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DefaultSubscriptionFeatureAvailability+DefaultInitializer.swift"; sourceTree = ""; }; @@ -5863,6 +5866,7 @@ 3775913429AB99DA00E26367 /* Sync */ = { isa = PBXGroup; children = ( + EEEFA3452D145322006A3F8A /* SyncPixels.swift */, C1935A162C88F9AA001AD72D /* Promotion */, 566B73672BECBF4400FF1959 /* Utilities */, 377D801A2AB47FA1002AF251 /* SettingSyncHandlers */, @@ -11390,6 +11394,7 @@ 56BA1E8B2BB1CB5B001CF69F /* CertificateTrustEvaluator.swift in Sources */, B6E1491129A5C30A00AAFBE8 /* FBProtectionTabExtension.swift in Sources */, 1EC711502D033D200009EB5C /* UserText+NetworkProtection+Shared.swift in Sources */, + EEEFA3472D145328006A3F8A /* SyncPixels.swift in Sources */, 3706FAC4293F65D500E42796 /* PrintingUserScript.swift in Sources */, 1D01A3D92B88DF8B00FE8150 /* PreferencesSyncView.swift in Sources */, 9D9AE86C2AA76D1B0026E7DC /* LoginItemsManager.swift in Sources */, @@ -13748,6 +13753,7 @@ B69B503F2726A12500758A2B /* LocalStatisticsStore.swift in Sources */, B689ECD526C247DB006FB0C5 /* BackForwardListItem.swift in Sources */, B69B50572727D16900758A2B /* AtbAndVariantCleanup.swift in Sources */, + EEEFA3462D145328006A3F8A /* SyncPixels.swift in Sources */, AA3D531527A1ED9300074EC1 /* FeedbackWindow.swift in Sources */, B6685E3F29A606190043D2EE /* WorkspaceProtocol.swift in Sources */, B6ABC5962B4861D4008343B9 /* FocusableTextField.swift in Sources */, diff --git a/DuckDuckGo/Preferences/Model/SyncPreferences.swift b/DuckDuckGo/Preferences/Model/SyncPreferences.swift index 369e2fe1fc..2193c7da59 100644 --- a/DuckDuckGo/Preferences/Model/SyncPreferences.swift +++ b/DuckDuckGo/Preferences/Model/SyncPreferences.swift @@ -762,6 +762,7 @@ extension SyncPreferences: ManagementDialogModelDelegate { private func handleAccountAlreadyExists(_ recoveryKey: SyncCode.RecoveryKey) { if devices.count > 1 { managementDialogModel.shouldShowSwitchAccountsMessage = true + PixelKit.fire(SyncSwitchAccountPixelKitEvent.syncAskUserToSwitchAccount.withoutMacPrefix) } else { switchAccounts(recoveryKey: recoveryKey) managementDialogModel.endFlow() @@ -769,7 +770,8 @@ extension SyncPreferences: ManagementDialogModelDelegate { PixelKit.fire(DebugEvent(GeneralPixel.syncLoginExistingAccountError(error: SyncError.accountAlreadyExists))) } - func switchAccounts(recoveryCode: String) { + func userConfirmedSwitchAccounts(recoveryCode: String) { + PixelKit.fire(SyncSwitchAccountPixelKitEvent.syncUserAcceptedSwitchingAccount.withoutMacPrefix) guard let recoveryKey = try? SyncCode.decodeBase64String(recoveryCode).recovery else { return } @@ -782,7 +784,7 @@ extension SyncPreferences: ManagementDialogModelDelegate { do { try await syncService.disconnect() } catch { - // TODO: Send sync_user_switched_logout_error pixel + PixelKit.fire(SyncSwitchAccountPixelKitEvent.syncUserSwitchedLogoutError.withoutMacPrefix) } do { @@ -790,9 +792,13 @@ extension SyncPreferences: ManagementDialogModelDelegate { let registeredDevices = try await syncService.login(recoveryKey, deviceName: device.name, deviceType: device.type) await mapDevices(registeredDevices) } catch { - // TODO: Send sync_user_switched_login_error pixel + PixelKit.fire(SyncSwitchAccountPixelKitEvent.syncUserSwitchedLoginError.withoutMacPrefix) } - // TODO: Send sync_user_switched_account_pixel + PixelKit.fire(SyncSwitchAccountPixelKitEvent.syncUserSwitchedAccount.withoutMacPrefix) } } + + func switchAccountsCancelled() { + PixelKit.fire(SyncSwitchAccountPixelKitEvent.syncUserCancelledSwitchingAccount.withoutMacPrefix) + } } diff --git a/LocalPackages/SyncUI/Sources/SyncUI/ViewModels/ManagementDialogModel.swift b/LocalPackages/SyncUI/Sources/SyncUI/ViewModels/ManagementDialogModel.swift index 4522ee2352..cc3d602a79 100644 --- a/LocalPackages/SyncUI/Sources/SyncUI/ViewModels/ManagementDialogModel.swift +++ b/LocalPackages/SyncUI/Sources/SyncUI/ViewModels/ManagementDialogModel.swift @@ -33,7 +33,8 @@ public protocol ManagementDialogModelDelegate: AnyObject { func enterRecoveryCodePressed() func copyCode() func openSystemPasswordSettings() - func switchAccounts(recoveryCode: String) + func userConfirmedSwitchAccounts(recoveryCode: String) + func switchAccountsCancelled() } public final class ManagementDialogModel: ObservableObject { @@ -59,16 +60,22 @@ public final class ManagementDialogModel: ObservableObject { } public func endFlow() { + if shouldShowSwitchAccountsMessage { + delegate?.switchAccountsCancelled() + } + doEndFlow() + } + + public func userConfirmedSwitchAccounts(recoveryCode: String) { + delegate?.userConfirmedSwitchAccounts(recoveryCode: recoveryCode) + doEndFlow() + } + + private func doEndFlow() { syncErrorMessage?.type.onButtonPressed(delegate: delegate) syncErrorMessage = nil currentDialog = nil } - public func switchAccounts(recoveryCode: String) { - shouldShowSwitchAccountsMessage = false - delegate?.switchAccounts(recoveryCode: recoveryCode) - endFlow() - } - private var shouldShowErrorMessageCancellable: AnyCancellable? } diff --git a/LocalPackages/SyncUI/Sources/SyncUI/Views/ManagementDialog.swift b/LocalPackages/SyncUI/Sources/SyncUI/Views/ManagementDialog.swift index 7b4a743ff1..847c9892a2 100644 --- a/LocalPackages/SyncUI/Sources/SyncUI/Views/ManagementDialog.swift +++ b/LocalPackages/SyncUI/Sources/SyncUI/Views/ManagementDialog.swift @@ -75,7 +75,7 @@ public struct ManagementDialog: View { title: Text(UserText.syncAlertSwitchAccountTitle), message: Text(UserText.syncAlertSwitchAccountMessage), primaryButton: .default(Text(UserText.syncAlertSwitchAccountButton)) { - model.switchAccounts(recoveryCode: recoveryCodeModel.recoveryCode) + model.userConfirmedSwitchAccounts(recoveryCode: recoveryCodeModel.recoveryCode) }, secondaryButton: .cancel { model.endFlow() diff --git a/UnitTests/Sync/SyncPreferencesTests.swift b/UnitTests/Sync/SyncPreferencesTests.swift index 9687421eae..9962480dcc 100644 --- a/UnitTests/Sync/SyncPreferencesTests.swift +++ b/UnitTests/Sync/SyncPreferencesTests.swift @@ -356,7 +356,7 @@ final class SyncPreferencesTests: XCTestCase { return [RegisteredDevice(id: "1", name: "iPhone", type: "iPhone"), RegisteredDevice(id: "2", name: "Macbook Pro", type: "Macbook Pro")] } - syncPreferences.switchAccounts(recoveryCode: testRecoveryCode) + syncPreferences.userConfirmedSwitchAccounts(recoveryCode: testRecoveryCode) await fulfillment(of: [loginCalledExpectation], timeout: 5.0) } @@ -368,7 +368,7 @@ final class SyncPreferencesTests: XCTestCase { return [RegisteredDevice(id: "1", name: "iPhone", type: "iPhone"), RegisteredDevice(id: "2", name: "Macbook Pro", type: "Macbook Pro")] } - syncPreferences.switchAccounts(recoveryCode: testRecoveryCode) + syncPreferences.userConfirmedSwitchAccounts(recoveryCode: testRecoveryCode) let deviceIDsPublisher = syncPreferences.$devices.map { $0.map { $0.id } } try await waitForPublisher(deviceIDsPublisher, toEmit: ["1", "2"]) }