From 16719e8d9bc74dc3275837148031d0d56a5bf43b Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 11 Apr 2024 15:05:49 +0100 Subject: [PATCH 01/13] add swipe to open tab pixel --- Core/PixelEvent.swift | 6 ++++-- DuckDuckGo/MainViewController.swift | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 1e7119aa3c..7abe96883e 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -509,7 +509,8 @@ extension Pixel { case swipeTabsUsed case swipeTabsUsedDaily - + case swipeToOpenNewTab + case bookmarksCleanupFailed case bookmarksCleanupAttemptedWhileSyncWasEnabled case favoritesCleanupFailed @@ -1120,7 +1121,8 @@ extension Pixel.Event { case .swipeTabsUsed: return "m_swipe-tabs-used" case .swipeTabsUsedDaily: return "m_swipe-tabs-used-daily" - + case .swipeToOpenNewTab: return "m_addressbar_swipe_new_tab" + case .bookmarksCleanupFailed: return "m_d_bookmarks_cleanup_failed" case .bookmarksCleanupAttemptedWhileSyncWasEnabled: return "m_d_bookmarks_cleanup_attempted_while_sync_was_enabled" case .favoritesCleanupFailed: return "m_d_favorites_cleanup_failed" diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index 49b978243b..ee0bd257cc 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -357,6 +357,7 @@ class MainViewController: UIViewController { self?.select(tabAt: $0) } newTab: { [weak self] in + Pixel.fire(pixel: .swipeToOpenNewTab) self?.newTab() } onSwipeStarted: { [weak self] in self?.hideKeyboard() From 24317881189b598533df1f6e1504ea90d80f05fd Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 11 Apr 2024 15:19:00 +0100 Subject: [PATCH 02/13] fire pixel when clicking on the address bar when on ntp --- Core/PixelEvent.swift | 5 ++++- DuckDuckGo/MainViewController.swift | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 7abe96883e..4f57f9d401 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -77,7 +77,8 @@ extension Pixel { case addressBarShare case addressBarSettings - + case addressBarClickWhileOnNTP + case shareSheetResultSuccess case shareSheetResultFail case shareSheetActivityCopy @@ -704,6 +705,8 @@ extension Pixel.Event { case .addressBarShare: return "m_addressbar_share" case .addressBarSettings: return "m_addressbar_settings" + case .addressBarClickWhileOnNTP: return "m_addressbar_click_ntp" + case .shareSheetResultSuccess: return "m_sharesheet_result_success" case .shareSheetResultFail: return "m_sharesheet_result_fail" case .shareSheetActivityCopy: return "m_sharesheet_activity_copy" diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index ee0bd257cc..da663ee2cf 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -1762,6 +1762,10 @@ extension MainViewController: OmniBarDelegate { viewCoordinator.omniBar.refreshText(forUrl: currentTab.url, forceFullURL: true) } + if homeController != nil { + Pixel.fire(pixel: .addressBarClickWhileOnNTP) + } + guard homeController == nil else { return } if !skipSERPFlow, isSERPPresented, let query = omniBar.textField.text { From f173fe69a414b74e166db4dd7be34c5cf8ae03d5 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 11 Apr 2024 15:25:14 +0100 Subject: [PATCH 03/13] fire correct pixel when on serp or website --- Core/PixelEvent.swift | 4 ++++ DuckDuckGo/MainViewController.swift | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 4f57f9d401..13a1b3b27c 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -78,6 +78,8 @@ extension Pixel { case addressBarShare case addressBarSettings case addressBarClickWhileOnNTP + case addressBarClickWhileOnWebsite + case addressBarClickWhileOnSERP case shareSheetResultSuccess case shareSheetResultFail @@ -706,6 +708,8 @@ extension Pixel.Event { case .addressBarShare: return "m_addressbar_share" case .addressBarSettings: return "m_addressbar_settings" case .addressBarClickWhileOnNTP: return "m_addressbar_click_ntp" + case .addressBarClickWhileOnWebsite: return "m_addressbar_click_website" + case .addressBarClickWhileOnSERP: return "m_addressbar_click_serp" case .shareSheetResultSuccess: return "m_sharesheet_result_success" case .shareSheetResultFail: return "m_sharesheet_result_fail" diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index da663ee2cf..8dba2a4869 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -1764,6 +1764,12 @@ extension MainViewController: OmniBarDelegate { if homeController != nil { Pixel.fire(pixel: .addressBarClickWhileOnNTP) + } else if let currentTab { + if currentTab.url?.isDuckDuckGoSearch == true { + Pixel.fire(pixel: .addressBarClickWhileOnSERP) + } else { + Pixel.fire(pixel: .addressBarClickWhileOnWebsite) + } } guard homeController == nil else { return } From 1558df308c6923aba0f82fea57aef541d6c1da04 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 11 Apr 2024 15:43:40 +0100 Subject: [PATCH 04/13] fire pixels when keyboard open and closed --- Core/PixelEvent.swift | 10 ++++++++-- DuckDuckGo/MainViewController.swift | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 13a1b3b27c..c2234dcf13 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -32,7 +32,10 @@ extension Pixel { case appLaunch case refreshPressed case pullToRefresh - + + case keyboardTriggeredOpen + case keyboardTriggeredClosed + case forgetAllPressedBrowsing case forgetAllPressedTabSwitching case forgetAllExecuted @@ -661,7 +664,10 @@ extension Pixel.Event { case .appLaunch: return "ml" case .refreshPressed: return "m_r" case .pullToRefresh: return "m_pull-to-reload" - + + case .keyboardTriggeredOpen: return "m_keyboard_triggered_open" + case .keyboardTriggeredClosed: return "m_keyboard_triggered_close" + case .forgetAllPressedBrowsing: return "mf_bp" case .forgetAllPressedTabSwitching: return "mf_tp" case .forgetAllExecuted: return "mf" diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index 8dba2a4869..9e24730a3b 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -458,6 +458,21 @@ class MainViewController: UIViewController { selector: #selector(keyboardWillChangeFrame), name: UIResponder.keyboardWillChangeFrameNotification, object: nil) + + NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow), + name: UIResponder.keyboardDidShowNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidHide), + name: UIResponder.keyboardDidHideNotification, object: nil) + } + + @objc + private func keyboardDidShow() { + Pixel.fire(pixel: .keyboardTriggeredOpen) + } + + @objc + private func keyboardDidHide() { + Pixel.fire(pixel: .keyboardTriggeredClosed) } private func registerForSyncPausedNotifications() { From 25b7b029b7afbcbf0bd217729446c483db0bff05 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 11 Apr 2024 16:10:48 +0100 Subject: [PATCH 05/13] add pixels for keyboard go, text field click and clear in various locations --- Core/PixelEvent.swift | 26 +++++++++++----- DuckDuckGo/BlankSnapshotViewController.swift | 4 +++ DuckDuckGo/MainViewController.swift | 32 ++++++++++++++------ DuckDuckGo/OmniBar.swift | 1 + DuckDuckGo/OmniBarDelegate.swift | 2 ++ 5 files changed, 48 insertions(+), 17 deletions(-) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index c2234dcf13..357714fcd7 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -35,6 +35,9 @@ extension Pixel { case keyboardTriggeredOpen case keyboardTriggeredClosed + case keyboardGoWhileOnNTP + case keyboardGoWhileOnWebsite + case keyboardGoWhileOnSERP case forgetAllPressedBrowsing case forgetAllPressedTabSwitching @@ -80,9 +83,12 @@ extension Pixel { case addressBarShare case addressBarSettings - case addressBarClickWhileOnNTP - case addressBarClickWhileOnWebsite - case addressBarClickWhileOnSERP + case addressBarClickOnNTP + case addressBarClickOnWebsite + case addressBarClickOnSERP + case addressBarClearPressedOnNTP + case addressBarClearPressedOnWebsite + case addressBarClearPressedOnSERP case shareSheetResultSuccess case shareSheetResultFail @@ -667,6 +673,9 @@ extension Pixel.Event { case .keyboardTriggeredOpen: return "m_keyboard_triggered_open" case .keyboardTriggeredClosed: return "m_keyboard_triggered_close" + case .keyboardGoWhileOnNTP: return "m_keyboard_go_click_ntp" + case .keyboardGoWhileOnWebsite: return "m_keyboard_go_click_website" + case .keyboardGoWhileOnSERP: return "m_keyboard_go_click_serp" case .forgetAllPressedBrowsing: return "mf_bp" case .forgetAllPressedTabSwitching: return "mf_tp" @@ -710,12 +719,15 @@ extension Pixel.Event { case .browsingMenuAutofill: return "m_nav_autofill_menu_item_pressed" case .browsingMenuShare: return "m_browsingmenu_share" - + case .addressBarShare: return "m_addressbar_share" case .addressBarSettings: return "m_addressbar_settings" - case .addressBarClickWhileOnNTP: return "m_addressbar_click_ntp" - case .addressBarClickWhileOnWebsite: return "m_addressbar_click_website" - case .addressBarClickWhileOnSERP: return "m_addressbar_click_serp" + case .addressBarClickOnNTP: return "m_addressbar_click_ntp" + case .addressBarClickOnWebsite: return "m_addressbar_click_website" + case .addressBarClickOnSERP: return "m_addressbar_click_serp" + case .addressBarClearPressedOnNTP: return "m_addressbar_focus_clear_entry_ntp" + case .addressBarClearPressedOnWebsite: return "m_addressbar_focus_clear_entry_website" + case .addressBarClearPressedOnSERP: return "m_addressbar_focus_clear_entry_serp" case .shareSheetResultSuccess: return "m_sharesheet_result_success" case .shareSheetResultFail: return "m_sharesheet_result_fail" diff --git a/DuckDuckGo/BlankSnapshotViewController.swift b/DuckDuckGo/BlankSnapshotViewController.swift index 2143424548..cb5752849b 100644 --- a/DuckDuckGo/BlankSnapshotViewController.swift +++ b/DuckDuckGo/BlankSnapshotViewController.swift @@ -186,6 +186,10 @@ extension BlankSnapshotViewController: OmniBarDelegate { func onEnterPressed() { userInteractionDetected() } + + func onClearPressed() { + // No-op + } } extension BlankSnapshotViewController: TabSwitcherButtonDelegate { diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index 9e24730a3b..e96964ab60 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -1736,11 +1736,25 @@ extension MainViewController: OmniBarDelegate { } func onEnterPressed() { + fireControllerAwarePixel(ntp: .keyboardGoWhileOnNTP, serp: .keyboardGoWhileOnSERP, website: .keyboardGoWhileOnWebsite) + guard !viewCoordinator.suggestionTrayContainer.isHidden else { return } suggestionTrayController?.willDismiss(with: viewCoordinator.omniBar.textField.text ?? "") } + func fireControllerAwarePixel(ntp: Pixel.Event, serp: Pixel.Event, website: Pixel.Event) { + if homeController != nil { + Pixel.fire(pixel: ntp) + } else if let currentTab { + if currentTab.url?.isDuckDuckGoSearch == true { + Pixel.fire(pixel: serp) + } else { + Pixel.fire(pixel: website) + } + } + } + func onDismissed() { dismissOmniBar() } @@ -1766,7 +1780,13 @@ extension MainViewController: OmniBarDelegate { homeController?.omniBarCancelPressed() self.showMenuHighlighterIfNeeded() } - + + func onClearPressed() { + fireControllerAwarePixel(ntp: .addressBarClearPressedOnNTP, + serp: .addressBarClearPressedOnSERP, + website: .addressBarClearPressedOnWebsite) + } + private var isSERPPresented: Bool { guard let tabURL = currentTab?.url else { return false } return tabURL.isDuckDuckGoSearch @@ -1777,15 +1797,7 @@ extension MainViewController: OmniBarDelegate { viewCoordinator.omniBar.refreshText(forUrl: currentTab.url, forceFullURL: true) } - if homeController != nil { - Pixel.fire(pixel: .addressBarClickWhileOnNTP) - } else if let currentTab { - if currentTab.url?.isDuckDuckGoSearch == true { - Pixel.fire(pixel: .addressBarClickWhileOnSERP) - } else { - Pixel.fire(pixel: .addressBarClickWhileOnWebsite) - } - } + fireControllerAwarePixel(ntp: .addressBarClickOnNTP, serp: .addressBarClickOnSERP, website: .addressBarClickOnWebsite) guard homeController == nil else { return } diff --git a/DuckDuckGo/OmniBar.swift b/DuckDuckGo/OmniBar.swift index 531133392d..8b84783ed9 100644 --- a/DuckDuckGo/OmniBar.swift +++ b/DuckDuckGo/OmniBar.swift @@ -416,6 +416,7 @@ class OmniBar: UIView { } @IBAction func onClearButtonPressed(_ sender: Any) { + omniDelegate?.onClearPressed() refreshState(state.onTextClearedState) } diff --git a/DuckDuckGo/OmniBarDelegate.swift b/DuckDuckGo/OmniBarDelegate.swift index 698b0c73c2..1763a3d6f9 100644 --- a/DuckDuckGo/OmniBarDelegate.swift +++ b/DuckDuckGo/OmniBarDelegate.swift @@ -40,6 +40,8 @@ protocol OmniBarDelegate: AnyObject { func onSettingsLongPressed() + func onClearPressed() + func onCancelPressed() func onEnterPressed() From 50a4c166dbf89a11d043b4bffdf36dd5bb7c66a3 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 11 Apr 2024 16:22:05 +0100 Subject: [PATCH 06/13] fire pixel on cancel in various places --- Core/PixelEvent.swift | 6 ++++++ DuckDuckGo/MainViewController.swift | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 357714fcd7..22597ef214 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -83,6 +83,9 @@ extension Pixel { case addressBarShare case addressBarSettings + case addressBarCancelPressedOnNTP + case addressBarCancelPressedOnWebsite + case addressBarCancelPressedOnSERP case addressBarClickOnNTP case addressBarClickOnWebsite case addressBarClickOnSERP @@ -722,6 +725,9 @@ extension Pixel.Event { case .addressBarShare: return "m_addressbar_share" case .addressBarSettings: return "m_addressbar_settings" + case .addressBarCancelPressedOnNTP: return "m_addressbar_cancel_ntp" + case .addressBarCancelPressedOnWebsite: return "m_addressbar_cancel_website" + case .addressBarCancelPressedOnSERP: return "m_addressbar_cancel_serp" case .addressBarClickOnNTP: return "m_addressbar_click_ntp" case .addressBarClickOnWebsite: return "m_addressbar_click_website" case .addressBarClickOnSERP: return "m_addressbar_click_serp" diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index e96964ab60..0101d51d69 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -1775,6 +1775,10 @@ extension MainViewController: OmniBarDelegate { } func onCancelPressed() { + fireControllerAwarePixel(ntp: .addressBarCancelPressedOnNTP, + serp: .addressBarCancelPressedOnSERP, + website: .addressBarCancelPressedOnWebsite) + dismissOmniBar() hideSuggestionTray() homeController?.omniBarCancelPressed() From 28c0998b00799a0871ec847a45d0a6b481713285 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 11 Apr 2024 20:11:47 +0100 Subject: [PATCH 07/13] handle onCancel correct and call performCancel if not clicked --- Core/PixelEvent.swift | 14 ++++++++++-- DuckDuckGo/BlankSnapshotViewController.swift | 4 ++++ .../MainViewController+KeyCommands.swift | 8 +++---- DuckDuckGo/MainViewController.swift | 22 ++++++++++++------- DuckDuckGo/OmniBar.swift | 16 ++++++++++++-- DuckDuckGo/OmniBarDelegate.swift | 2 +- DuckDuckGo/TabSwitcherViewController.swift | 2 ++ DuckDuckGo/TabViewCell.swift | 11 +++++++--- 8 files changed, 59 insertions(+), 20 deletions(-) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 22597ef214..4c6c821aaf 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -54,7 +54,12 @@ extension Pixel { case tabSwitcherNewLayoutSeen case tabSwitcherListEnabled case tabSwitcherGridEnabled - + case tabSwitcherNewTab + case tabSwitcherSwitchTabs + case tabSwitcherClickCloseTab + case tabSwitcherSwipeCloseTab + case tabSwitchLongPressNewTab + case settingsDoNotSellShown case settingsDoNotSellOn case settingsDoNotSellOff @@ -695,7 +700,12 @@ extension Pixel.Event { case .tabSwitcherNewLayoutSeen: return "m_ts_n" case .tabSwitcherListEnabled: return "m_ts_l" case .tabSwitcherGridEnabled: return "m_ts_g" - + case .tabSwitcherNewTab: return "m_tab_manager_new_tab_click" + case .tabSwitcherSwitchTabs: return "m_tab_manager_switch_tabs" + case .tabSwitcherClickCloseTab: return "m_tab_manager_close_tab_click" + case .tabSwitcherSwipeCloseTab: return "m_tab_manager_close_tab_swipe" + case .tabSwitchLongPressNewTab: return "m_tab_manager_long_press_new_tab" + case .settingsDoNotSellShown: return "ms_dns" case .settingsDoNotSellOn: return "ms_dns_on" case .settingsDoNotSellOff: return "ms_dns_off" diff --git a/DuckDuckGo/BlankSnapshotViewController.swift b/DuckDuckGo/BlankSnapshotViewController.swift index cb5752849b..83a62921b1 100644 --- a/DuckDuckGo/BlankSnapshotViewController.swift +++ b/DuckDuckGo/BlankSnapshotViewController.swift @@ -175,6 +175,10 @@ extension BlankSnapshotViewController: OmniBarDelegate { userInteractionDetected() } + func onTextFieldWillBeginEditing(_ omniBar: OmniBar, tapped: Bool) { + // No-op + } + func onTextFieldDidBeginEditing(_ omniBar: OmniBar) -> Bool { DispatchQueue.main.async { self.viewCoordinator.omniBar.resignFirstResponder() diff --git a/DuckDuckGo/MainViewController+KeyCommands.swift b/DuckDuckGo/MainViewController+KeyCommands.swift index f7fffded92..695be22846 100644 --- a/DuckDuckGo/MainViewController+KeyCommands.swift +++ b/DuckDuckGo/MainViewController+KeyCommands.swift @@ -162,7 +162,7 @@ extension MainViewController { guard tabSwitcherController == nil else { return } findInPageView.done() hideSuggestionTray() - onCancelPressed() + performCancel() } @objc func keyboardNewTab() { @@ -188,7 +188,7 @@ extension MainViewController { guard let tab = currentTab else { return } guard let index = tabManager.model.indexOf(tab: tab.tabModel) else { return } let targetTabIndex = index + 1 >= tabManager.model.count ? 0 : index + 1 - onCancelPressed() + performCancel() select(tabAt: targetTabIndex) } @@ -198,14 +198,14 @@ extension MainViewController { guard let tab = currentTab else { return } guard let index = tabManager.model.indexOf(tab: tab.tabModel) else { return } let targetTabIndex = index - 1 < 0 ? tabManager.model.count - 1 : index - 1 - onCancelPressed() + performCancel() select(tabAt: targetTabIndex) } @objc func keyboardShowAllTabs() { guard tabSwitcherController == nil else { return } - onCancelPressed() + performCancel() showTabSwitcher() } diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index 0101d51d69..1796e94055 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -1774,17 +1774,20 @@ extension MainViewController: OmniBarDelegate { } } - func onCancelPressed() { - fireControllerAwarePixel(ntp: .addressBarCancelPressedOnNTP, - serp: .addressBarCancelPressedOnSERP, - website: .addressBarCancelPressedOnWebsite) - + func performCancel() { dismissOmniBar() hideSuggestionTray() homeController?.omniBarCancelPressed() self.showMenuHighlighterIfNeeded() } + func onCancelPressed() { + fireControllerAwarePixel(ntp: .addressBarCancelPressedOnNTP, + serp: .addressBarCancelPressedOnSERP, + website: .addressBarCancelPressedOnWebsite) + performCancel() + } + func onClearPressed() { fireControllerAwarePixel(ntp: .addressBarClearPressedOnNTP, serp: .addressBarClearPressedOnSERP, @@ -1796,12 +1799,14 @@ extension MainViewController: OmniBarDelegate { return tabURL.isDuckDuckGoSearch } - func onTextFieldWillBeginEditing(_ omniBar: OmniBar) { + func onTextFieldWillBeginEditing(_ omniBar: OmniBar, tapped: Bool) { if let currentTab { viewCoordinator.omniBar.refreshText(forUrl: currentTab.url, forceFullURL: true) } - fireControllerAwarePixel(ntp: .addressBarClickOnNTP, serp: .addressBarClickOnSERP, website: .addressBarClickOnWebsite) + if tapped { + fireControllerAwarePixel(ntp: .addressBarClickOnNTP, serp: .addressBarClickOnSERP, website: .addressBarClickOnWebsite) + } guard homeController == nil else { return } @@ -2207,7 +2212,7 @@ extension MainViewController: TabDelegate { guard let index = tabManager.model.indexOf(tab: tab) else { return } select(tabAt: index) DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { - self.onCancelPressed() + self.performCancel() } } @@ -2278,6 +2283,7 @@ extension MainViewController: BookmarksDelegate { extension MainViewController: TabSwitcherButtonDelegate { func launchNewTab(_ button: TabSwitcherButton) { + Pixel.fire(pixel: .tabSwitchLongPressNewTab) newTab() } diff --git a/DuckDuckGo/OmniBar.swift b/DuckDuckGo/OmniBar.swift index 8b84783ed9..e18ff7232f 100644 --- a/DuckDuckGo/OmniBar.swift +++ b/DuckDuckGo/OmniBar.swift @@ -174,8 +174,19 @@ class OmniBar: UIView { guard let range = field.selectedTextRange else { return } UIPasteboard.general.string = field.text(in: range) } + + textField.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector( onTextFieldTapped ))) } + var textFieldTapped = false + + @objc + private func onTextFieldTapped() { + print(#function, "Pixel") + textFieldTapped = true + textField.becomeFirstResponder() + } + private func configureSeparator() { separatorHeightConstraint.constant = 1.0 / UIScreen.main.scale } @@ -488,9 +499,10 @@ extension OmniBar: UITextFieldDelegate { self.refreshState(self.state.onEditingStartedState) return true } - + func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { - omniDelegate?.onTextFieldWillBeginEditing(self) + omniDelegate?.onTextFieldWillBeginEditing(self, tapped: textFieldTapped) + textFieldTapped = false return true } diff --git a/DuckDuckGo/OmniBarDelegate.swift b/DuckDuckGo/OmniBarDelegate.swift index 1763a3d6f9..ea9f7592ff 100644 --- a/DuckDuckGo/OmniBarDelegate.swift +++ b/DuckDuckGo/OmniBarDelegate.swift @@ -56,7 +56,7 @@ protocol OmniBarDelegate: AnyObject { func onShareLongPressed() - func onTextFieldWillBeginEditing(_ omniBar: OmniBar) + func onTextFieldWillBeginEditing(_ omniBar: OmniBar, tapped: Bool) // Returns whether field should select the text or not func onTextFieldDidBeginEditing(_ omniBar: OmniBar) -> Bool diff --git a/DuckDuckGo/TabSwitcherViewController.swift b/DuckDuckGo/TabSwitcherViewController.swift index cb9b155f4e..e8354d995b 100644 --- a/DuckDuckGo/TabSwitcherViewController.swift +++ b/DuckDuckGo/TabSwitcherViewController.swift @@ -278,6 +278,7 @@ class TabSwitcherViewController: UIViewController { } @IBAction func onAddPressed(_ sender: UIBarButtonItem) { + Pixel.fire(pixel: .tabSwitcherNewTab) delegate.tabSwitcherDidRequestNewTab(tabSwitcher: self) dismiss() } @@ -416,6 +417,7 @@ extension TabSwitcherViewController: UICollectionViewDataSource { extension TabSwitcherViewController: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + Pixel.fire(pixel: .tabSwitcherSwitchTabs) currentSelection = indexPath.row markCurrentAsViewedAndDismiss() } diff --git a/DuckDuckGo/TabViewCell.swift b/DuckDuckGo/TabViewCell.swift index 0d98022045..d073d03871 100644 --- a/DuckDuckGo/TabViewCell.swift +++ b/DuckDuckGo/TabViewCell.swift @@ -128,7 +128,8 @@ class TabViewCell: UICollectionViewCell { }, completion: { _ in self.isHidden = true self.isDeleting = true - self.deleteTab() + Pixel.fire(pixel: .tabSwitcherSwipeCloseTab) + self.closeTab() }) } @@ -142,13 +143,17 @@ class TabViewCell: UICollectionViewCell { preview: UIImage?, reorderRecognizer: UIGestureRecognizer?) {} - @IBAction func deleteTab() { + func closeTab() { guard let tab = tab else { return } guard isNotReordering(with: collectionReorderRecognizer) else { return } - self.delegate?.deleteTab(tab: tab) } + @IBAction func deleteTab() { + Pixel.fire(pixel: .tabSwitcherClickCloseTab) + closeTab() + } + private func isNotReordering(with gestureRecognizer: UIGestureRecognizer?) -> Bool { guard let gestureRecognizer = gestureRecognizer else { return true } let inactiveStates: [UIGestureRecognizer.State] = [.possible, .failed, .cancelled, .ended] From 27a3234e2880e4b678d553428e645a043d5a86b6 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 11 Apr 2024 21:31:28 +0100 Subject: [PATCH 08/13] add favorite and bookmark launched pixels --- Core/PixelEvent.swift | 24 ++++++++++++++++++------ DuckDuckGo/BookmarksViewController.swift | 3 +++ DuckDuckGo/HomeViewController.swift | 2 +- DuckDuckGo/MainViewController.swift | 11 +++++++++-- 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 4c6c821aaf..57a3ea156a 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -115,10 +115,13 @@ extension Pixel { case tabBarTabSwitcherPressed case homeScreenShown - case homeScreenFavouriteLaunched case homeScreenEditFavorite case homeScreenDeleteFavorite - + + case favoriteLaunchedNTP + case favoriteLaunchedWebsite + case favoriteLaunchedWidget + case autocompleteClickPhrase case autocompleteClickWebsite case autocompleteClickBookmark @@ -155,7 +158,10 @@ extension Pixel { case voiceSearchDone case openVoiceSearch case voiceSearchCancelled - + + case bookmarkLaunchList + case bookmarkLaunchScored + case bookmarkImportSuccess case bookmarkImportFailure case bookmarkImportFailureParsingDL @@ -760,12 +766,18 @@ extension Pixel.Event { case .bookmarksButtonPressed: return "mt_bm" case .tabBarBookmarksLongPressed: return "mt_bl" case .tabBarTabSwitcherPressed: return "mt_tb" - + + case .bookmarkLaunchList: return "m_bookmark_launch_list" + case .bookmarkLaunchScored: return "m_bookmark_launch_scored" + case .homeScreenShown: return "mh" - case .homeScreenFavouriteLaunched: return "mh_fl" case .homeScreenEditFavorite: return "mh_ef" case .homeScreenDeleteFavorite: return "mh_df" - + + case .favoriteLaunchedNTP: return "m_favorite_launched_ntp" + case .favoriteLaunchedWebsite: return "m_favorite_launched_website" + case .favoriteLaunchedWidget: return "m_favorite_launched_widget" + case .autocompleteClickPhrase: return "m_autocomplete_click_phrase" case .autocompleteClickWebsite: return "m_autocomplete_click_website" case .autocompleteClickBookmark: return "m_autocomplete_click_bookmark" diff --git a/DuckDuckGo/BookmarksViewController.swift b/DuckDuckGo/BookmarksViewController.swift index 37a2f47bfe..462558224b 100644 --- a/DuckDuckGo/BookmarksViewController.swift +++ b/DuckDuckGo/BookmarksViewController.swift @@ -266,6 +266,8 @@ class BookmarksViewController: UIViewController, UITableViewDelegate { private func didSelectScoredBookmarkAtIndex(_ index: Int) { guard searchDataSource.results.indices.contains(index) else { return } dismiss() + + Pixel.fire(pixel: .bookmarkLaunchScored) delegate?.bookmarksDidSelect(url: searchDataSource.results[index].url) } @@ -826,6 +828,7 @@ class BookmarksViewController: UIViewController, UITableViewDelegate { fileprivate func select(bookmark: BookmarkEntity) { guard let url = bookmark.urlObject else { return } dismiss() + Pixel.fire(pixel: .bookmarkLaunchList) delegate?.bookmarksDidSelect(url: url) } diff --git a/DuckDuckGo/HomeViewController.swift b/DuckDuckGo/HomeViewController.swift index 255fd1fe27..4523edcc2f 100644 --- a/DuckDuckGo/HomeViewController.swift +++ b/DuckDuckGo/HomeViewController.swift @@ -376,7 +376,7 @@ extension HomeViewController: FavoritesHomeViewSectionRendererDelegate { func favoritesRenderer(_ renderer: FavoritesHomeViewSectionRenderer, didSelect favorite: BookmarkEntity) { guard let url = favorite.urlObject else { return } - Pixel.fire(pixel: .homeScreenFavouriteLaunched) + Pixel.fire(pixel: .favoriteLaunchedNTP) Favicons.shared.loadFavicon(forDomain: url.host, intoCache: .fireproof, fromCache: .tabs) delegate?.home(self, didRequestUrl: url) } diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index 1796e94055..7db3b37ec9 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -465,14 +465,20 @@ class MainViewController: UIViewController { name: UIResponder.keyboardDidHideNotification, object: nil) } + var keyboardShowing = false + @objc private func keyboardDidShow() { + keyboardShowing = true Pixel.fire(pixel: .keyboardTriggeredOpen) } @objc private func keyboardDidHide() { - Pixel.fire(pixel: .keyboardTriggeredClosed) + if keyboardShowing { + Pixel.fire(pixel: .keyboardTriggeredClosed) + } + keyboardShowing = false } private func registerForSyncPausedNotifications() { @@ -1866,7 +1872,7 @@ extension MainViewController: FavoritesOverlayDelegate { func favoritesOverlay(_ overlay: FavoritesOverlay, didSelect favorite: BookmarkEntity) { guard let url = favorite.urlObject else { return } - Pixel.fire(pixel: .homeScreenFavouriteLaunched) + Pixel.fire(pixel: .favoriteLaunchedWebsite) homeController?.chromeDelegate = nil dismissOmniBar() Favicons.shared.loadFavicon(forDomain: url.host, intoCache: .fireproof, fromCache: .tabs) @@ -2271,6 +2277,7 @@ extension MainViewController: TabSwitcherDelegate { extension MainViewController: BookmarksDelegate { func bookmarksDidSelect(url: URL) { + dismissOmniBar() if url.isBookmarklet() { executeBookmarklet(url) From 035171a207f10e76e7aa372579b34a1a0b7f72fe Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 11 Apr 2024 22:41:39 +0100 Subject: [PATCH 09/13] fire pixel on gesture --- Core/PixelEvent.swift | 8 ++++++ DuckDuckGo/AutocompleteViewController.swift | 1 + DuckDuckGo/BookmarksViewController.swift | 4 +++ DuckDuckGo/MainViewController.swift | 29 +++++++++++++++++++-- 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 57a3ea156a..9fb3a77005 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -33,6 +33,8 @@ extension Pixel { case refreshPressed case pullToRefresh + case deviceOrientationLandscape + case keyboardTriggeredOpen case keyboardTriggeredClosed case keyboardGoWhileOnNTP @@ -97,6 +99,7 @@ extension Pixel { case addressBarClearPressedOnNTP case addressBarClearPressedOnWebsite case addressBarClearPressedOnSERP + case addressBarGestureDismiss case shareSheetResultSuccess case shareSheetResultFail @@ -161,6 +164,7 @@ extension Pixel { case bookmarkLaunchList case bookmarkLaunchScored + case bookmarkAddFavorite case bookmarkImportSuccess case bookmarkImportFailure @@ -685,6 +689,8 @@ extension Pixel.Event { case .refreshPressed: return "m_r" case .pullToRefresh: return "m_pull-to-reload" + case .deviceOrientationLandscape: return "m_device_orientation_landscape" + case .keyboardTriggeredOpen: return "m_keyboard_triggered_open" case .keyboardTriggeredClosed: return "m_keyboard_triggered_close" case .keyboardGoWhileOnNTP: return "m_keyboard_go_click_ntp" @@ -750,6 +756,7 @@ extension Pixel.Event { case .addressBarClearPressedOnNTP: return "m_addressbar_focus_clear_entry_ntp" case .addressBarClearPressedOnWebsite: return "m_addressbar_focus_clear_entry_website" case .addressBarClearPressedOnSERP: return "m_addressbar_focus_clear_entry_serp" + case .addressBarGestureDismiss: return "m_addressbar_focus_dismiss_gesture" case .shareSheetResultSuccess: return "m_sharesheet_result_success" case .shareSheetResultFail: return "m_sharesheet_result_fail" @@ -769,6 +776,7 @@ extension Pixel.Event { case .bookmarkLaunchList: return "m_bookmark_launch_list" case .bookmarkLaunchScored: return "m_bookmark_launch_scored" + case .bookmarkAddFavorite: return "m_add_favorite_from_bookmark" case .homeScreenShown: return "mh" case .homeScreenEditFavorite: return "mh_ef" diff --git a/DuckDuckGo/AutocompleteViewController.swift b/DuckDuckGo/AutocompleteViewController.swift index a94516a273..de7c414104 100644 --- a/DuckDuckGo/AutocompleteViewController.swift +++ b/DuckDuckGo/AutocompleteViewController.swift @@ -230,6 +230,7 @@ class AutocompleteViewController: UIViewController { } @IBAction func onAutocompleteDismissed(_ sender: Any) { + Pixel.fire(pixel: .addressBarGestureDismiss) delegate?.autocompleteWasDismissed() } } diff --git a/DuckDuckGo/BookmarksViewController.swift b/DuckDuckGo/BookmarksViewController.swift index 462558224b..57b0d00be0 100644 --- a/DuckDuckGo/BookmarksViewController.swift +++ b/DuckDuckGo/BookmarksViewController.swift @@ -353,6 +353,10 @@ class BookmarksViewController: UIViewController, UITableViewDelegate { } private func toggleFavoriteAfterSwipe(_ bookmark: BookmarkEntity, _ indexPath: IndexPath) { + if !bookmark.isFavorite(on: viewModel.favoritesDisplayMode.displayedFolder) { + Pixel.fire(pixel: .bookmarkAddFavorite) + } + self.viewModel.toggleFavorite(bookmark) WidgetCenter.shared.reloadAllTimelines() diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index 7db3b37ec9..eba935ffa3 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -342,7 +342,7 @@ class MainViewController: UIViewController { assertionFailure() super.performSegue(withIdentifier: identifier, sender: sender) } - + private func installSwipeTabs() { guard swipeTabsCoordinator == nil else { return } @@ -459,6 +459,8 @@ class MainViewController: UIViewController { name: UIResponder.keyboardWillChangeFrameNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), + name: UIResponder.keyboardWillHideNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow), name: UIResponder.keyboardDidShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidHide), @@ -473,6 +475,13 @@ class MainViewController: UIViewController { Pixel.fire(pixel: .keyboardTriggeredOpen) } + @objc + private func keyboardWillHide() { + if homeController?.collectionView.isDragging == true { + Pixel.fire(pixel: .addressBarGestureDismiss) + } + } + @objc private func keyboardDidHide() { if keyboardShowing { @@ -1082,6 +1091,8 @@ class MainViewController: UIViewController { viewCoordinator.omniBar.forwardButton.isEnabled = viewCoordinator.toolbarForwardButton.isEnabled } + var orientationPixelWorker: DispatchWorkItem? + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) @@ -1093,11 +1104,25 @@ class MainViewController: UIViewController { coordinator.animate { _ in self.swipeTabsCoordinator?.refresh(tabsModel: self.tabManager.model, scrollToSelected: true) + + self.deferredFireOrientationPixel() } completion: { _ in ViewHighlighter.updatePositions() } } - + + private func deferredFireOrientationPixel() { + orientationPixelWorker?.cancel() + orientationPixelWorker = nil + if UIDevice.current.orientation.isLandscape { + let worker = DispatchWorkItem { + Pixel.fire(pixel: .deviceOrientationLandscape) + } + DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + 3, execute: worker) + orientationPixelWorker = worker + } + } + private func applyWidth() { if AppWidthObserver.shared.isLargeWidth { From 96fe16f53ead37e1c7d302e58d96287e0800db12 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Fri, 12 Apr 2024 11:27:06 +0100 Subject: [PATCH 10/13] pixels for managing bookmarks from the bookmarks edit screen --- Core/PixelEvent.swift | 10 ++++++++-- DuckDuckGo/AddOrEditBookmarkViewController.swift | 9 +++++++++ DuckDuckGo/BookmarksViewController.swift | 3 ++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 9fb3a77005..83701475a6 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -164,7 +164,10 @@ extension Pixel { case bookmarkLaunchList case bookmarkLaunchScored - case bookmarkAddFavorite + case bookmarkAddFavoriteFromBookmark + case bookmarkRemoveFavoriteFromBookmark + case bookmarkAddFavoriteBySwipe + case bookmarkDeletedFromBookmark case bookmarkImportSuccess case bookmarkImportFailure @@ -776,7 +779,10 @@ extension Pixel.Event { case .bookmarkLaunchList: return "m_bookmark_launch_list" case .bookmarkLaunchScored: return "m_bookmark_launch_scored" - case .bookmarkAddFavorite: return "m_add_favorite_from_bookmark" + case .bookmarkAddFavoriteFromBookmark: return "m_add_favorite_from_bookmark" + case .bookmarkRemoveFavoriteFromBookmark: return "m_remove_favorite_from_bookmark" + case .bookmarkAddFavoriteBySwipe: return "m_add_favorite_by_swipe" + case .bookmarkDeletedFromBookmark: return "m_bookmark_deleted_from_bookmark" case .homeScreenShown: return "mh" case .homeScreenEditFavorite: return "mh_ef" diff --git a/DuckDuckGo/AddOrEditBookmarkViewController.swift b/DuckDuckGo/AddOrEditBookmarkViewController.swift index 827efd99cf..06bc2f66e9 100644 --- a/DuckDuckGo/AddOrEditBookmarkViewController.swift +++ b/DuckDuckGo/AddOrEditBookmarkViewController.swift @@ -134,6 +134,15 @@ class AddOrEditBookmarkViewController: UIViewController { } func saveAndDismiss() { + let changes = viewModel.bookmark.changedValues() + if changes.contains(where: { $0.key == #keyPath(BookmarkEntity.favoriteFolders) }) { + if viewModel.bookmark.isFavorite(on: viewModel.favoritesDisplayMode.displayedFolder) { + Pixel.fire(pixel: .bookmarkAddFavoriteFromBookmark) + } else { + Pixel.fire(pixel: .bookmarkRemoveFavoriteFromBookmark) + } + } + viewModel.save() WidgetCenter.shared.reloadAllTimelines() self.delegate?.finishedEditing(self, entityID: viewModel.bookmark.objectID) diff --git a/DuckDuckGo/BookmarksViewController.swift b/DuckDuckGo/BookmarksViewController.swift index 57b0d00be0..ba753f694c 100644 --- a/DuckDuckGo/BookmarksViewController.swift +++ b/DuckDuckGo/BookmarksViewController.swift @@ -354,7 +354,7 @@ class BookmarksViewController: UIViewController, UITableViewDelegate { private func toggleFavoriteAfterSwipe(_ bookmark: BookmarkEntity, _ indexPath: IndexPath) { if !bookmark.isFavorite(on: viewModel.favoritesDisplayMode.displayedFolder) { - Pixel.fire(pixel: .bookmarkAddFavorite) + Pixel.fire(pixel: .bookmarkAddFavoriteBySwipe) } self.viewModel.toggleFavorite(bookmark) @@ -933,6 +933,7 @@ extension BookmarksViewController: AddOrEditBookmarkViewControllerDelegate { assertionFailure() return } + Pixel.fire(pixel: .bookmarkDeletedFromBookmark) showBookmarkDeletedMessage(bookmark) viewModel.softDeleteBookmark(bookmark) refreshFooterView() From 0542999ea396ee6e4fe4bc6e480c522e8ef3e0ed Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Fri, 12 Apr 2024 12:14:42 +0100 Subject: [PATCH 11/13] remove keyboard triggered pixels --- Core/PixelEvent.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 83701475a6..813e11a3e4 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -35,8 +35,6 @@ extension Pixel { case deviceOrientationLandscape - case keyboardTriggeredOpen - case keyboardTriggeredClosed case keyboardGoWhileOnNTP case keyboardGoWhileOnWebsite case keyboardGoWhileOnSERP @@ -694,8 +692,6 @@ extension Pixel.Event { case .deviceOrientationLandscape: return "m_device_orientation_landscape" - case .keyboardTriggeredOpen: return "m_keyboard_triggered_open" - case .keyboardTriggeredClosed: return "m_keyboard_triggered_close" case .keyboardGoWhileOnNTP: return "m_keyboard_go_click_ntp" case .keyboardGoWhileOnWebsite: return "m_keyboard_go_click_website" case .keyboardGoWhileOnSERP: return "m_keyboard_go_click_serp" From 5417d4cf8d2544d1a494648425f0f2320d7469cf Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Fri, 12 Apr 2024 12:15:55 +0100 Subject: [PATCH 12/13] clean up removed pixels --- DuckDuckGo/MainViewController.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index eba935ffa3..5da2afe477 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -472,21 +472,17 @@ class MainViewController: UIViewController { @objc private func keyboardDidShow() { keyboardShowing = true - Pixel.fire(pixel: .keyboardTriggeredOpen) } @objc private func keyboardWillHide() { - if homeController?.collectionView.isDragging == true { + if homeController?.collectionView.isDragging == true, keyboardShowing { Pixel.fire(pixel: .addressBarGestureDismiss) } } @objc private func keyboardDidHide() { - if keyboardShowing { - Pixel.fire(pixel: .keyboardTriggeredClosed) - } keyboardShowing = false } From 6d828f95729121982ca46d880c678cba4626167b Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Fri, 12 Apr 2024 12:19:55 +0100 Subject: [PATCH 13/13] remove print statement --- DuckDuckGo/OmniBar.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/DuckDuckGo/OmniBar.swift b/DuckDuckGo/OmniBar.swift index e18ff7232f..751a15283d 100644 --- a/DuckDuckGo/OmniBar.swift +++ b/DuckDuckGo/OmniBar.swift @@ -182,7 +182,6 @@ class OmniBar: UIView { @objc private func onTextFieldTapped() { - print(#function, "Pixel") textFieldTapped = true textField.becomeFirstResponder() }