Skip to content

Commit

Permalink
Base Pixel Implementation
Browse files Browse the repository at this point in the history
Implement pixels for youtubeOverlay behavior
  • Loading branch information
afterxleep committed Nov 11, 2024
1 parent becebe9 commit 2daac15
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 241 deletions.
18 changes: 9 additions & 9 deletions DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ final class DuckPlayerNavigationHandler: NSObject {
pixelFiring: PixelFiring.Type = Pixel.self,
dailyPixelFiring: DailyPixelFiring.Type = DailyPixel.self,
tabNavigationHandler: DuckPlayerTabNavigationHandling? = nil,
duckPlayerOverlayUsagePixels: DuckPlayerOverlayPixelFiring? = nil) {
duckPlayerOverlayUsagePixels: DuckPlayerOverlayPixelFiring? = DuckPlayerOverlayUsagePixels()) {
self.duckPlayer = duckPlayer
self.featureFlagger = featureFlagger
self.appSettings = appSettings
Expand Down Expand Up @@ -575,9 +575,7 @@ final class DuckPlayerNavigationHandler: NSObject {
// Watch in YT videos always open in new tab
redirectToYouTubeVideo(url: url, webView: webView, forceNewTab: true)
}


}
}

Check failure on line 578 in DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandler.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Lines should not have trailing whitespace (trailing_whitespace)

}

Expand Down Expand Up @@ -663,9 +661,6 @@ extension DuckPlayerNavigationHandler: DuckPlayerNavigationHandling {
@MainActor
func handleURLChange(webView: WKWebView) -> DuckPlayerNavigationHandlerURLChangeResult {

// Track overlayUsagePixels
duckPlayerOverlayUsagePixels?.registerNavigation(url: webView.url)

// We want to prevent multiple simultaneous redirects
// This can be caused by Duplicate Nav events, and quick URL changes
if let lastTimestamp = lastURLChangeHandling,
Expand All @@ -676,6 +671,11 @@ extension DuckPlayerNavigationHandler: DuckPlayerNavigationHandling {
// Update the Referrer based on the first URL change detected
setReferrer(webView: webView)

// Overlay Usage Pixel handling
if let url = webView.url {
duckPlayerOverlayUsagePixels?.handleNavigationAndFirePixels(url: url, duckPlayerMode: duckPlayerMode)
}

// We don't want YouTube redirects happening while default navigation is happening
// This can be caused by Duplicate Nav events, and quick URL changes
if let lastTimestamp = lastNavigationHandling,
Expand Down Expand Up @@ -735,7 +735,7 @@ extension DuckPlayerNavigationHandler: DuckPlayerNavigationHandling {
@MainActor
func handleGoBack(webView: WKWebView) {

guard isDuckPlayerFeatureEnabled else {
guard let url = webView.url, url.isDuckPlayer, isDuckPlayerFeatureEnabled else {
webView.goBack()
return
}
Expand Down Expand Up @@ -783,7 +783,7 @@ extension DuckPlayerNavigationHandler: DuckPlayerNavigationHandling {
guard let url = webView.url else {
return
}

if url.isDuckPlayer, duckPlayerMode != .disabled {
redirectToDuckPlayerVideo(url: url, webView: webView, disableNewTab: true)
return
Expand Down
98 changes: 39 additions & 59 deletions DuckDuckGo/DuckPlayer/DuckPlayerOverlayUsagePixels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,7 @@ protocol DuckPlayerOverlayPixelFiring {
var pixelFiring: PixelFiring.Type { get set }
var navigationHistory: [URL] { get set }

func registerNavigation(url: URL?)
func navigationBack(duckPlayerMode: DuckPlayerMode)
func navigationReload(duckPlayerMode: DuckPlayerMode)
func navigationWithinYoutube(duckPlayerMode: DuckPlayerMode)
func navigationOutsideYoutube(duckPlayerMode: DuckPlayerMode)
func navigationClosed(duckPlayerMode: DuckPlayerMode)
func overlayIdle(duckPlayerMode: DuckPlayerMode)

func handleNavigationAndFirePixels(url: URL?, duckPlayerMode: DuckPlayerMode)
}

final class DuckPlayerOverlayUsagePixels: DuckPlayerOverlayPixelFiring {
Expand All @@ -55,69 +48,56 @@ final class DuckPlayerOverlayUsagePixels: DuckPlayerOverlayPixelFiring {
idleTimer = nil
}

func registerNavigation(url: URL?) {
func handleNavigationAndFirePixels(url: URL?, duckPlayerMode: DuckPlayerMode) {
guard let url = url else { return }
navigationHistory.append(url)

// Cancel and reset the idle timer whenever a new navigation occurs
resetIdleTimer()
}
let comparisonURL = url.forComparison()

func navigationBack(duckPlayerMode: DuckPlayerMode) {
guard duckPlayerMode == .alwaysAsk,
let lastURL = navigationHistory.last,
lastURL.isYoutubeWatch else { return }

pixelFiring.fire(.duckPlayerYouTubeOverlayNavigationBack, withAdditionalParameters: [:])
}
// Only append the URL if it's different from the last entry in normalized form
navigationHistory.append(comparisonURL)

func navigationReload(duckPlayerMode: DuckPlayerMode) {
guard duckPlayerMode == .alwaysAsk,
let lastURL = navigationHistory.last,
lastURL.isYoutubeWatch else { return }

pixelFiring.fire(.duckPlayerYouTubeOverlayNavigationRefresh, withAdditionalParameters: [:])
}

func navigationWithinYoutube(duckPlayerMode: DuckPlayerMode) {
// DuckPlayer is in Ask Mode, there's navigation history, and last URL is a YouTube Watch Video
guard duckPlayerMode == .alwaysAsk,
navigationHistory.count > 1,
let currentURL = navigationHistory.last,
let previousURL = navigationHistory.dropLast().last,
previousURL.isYoutubeWatch,
currentURL.isYoutube else { return }
previousURL.isYoutubeWatch else { return }

pixelFiring.fire(.duckPlayerYouTubeNavigationWithinYouTube, withAdditionalParameters: [:])
}
var isReload = false
// Check for a reload condition: when current videoID is the same as Previous
if let currentVideoID = currentURL.youtubeVideoParams?.videoID,
let previousVideoID = previousURL.youtubeVideoParams?.videoID {
isReload = currentVideoID == previousVideoID
}

func navigationOutsideYoutube(duckPlayerMode: DuckPlayerMode) {
guard duckPlayerMode == .alwaysAsk,
navigationHistory.count > 1,
let currentURL = navigationHistory.last,
let previousURL = navigationHistory.dropLast().last,
previousURL.isYoutubeWatch,
!currentURL.isYoutube else { return }
// Fire the reload pixel if this is a reload navigation
if isReload {
pixelFiring.fire(.duckPlayerYouTubeOverlayNavigationRefresh, withAdditionalParameters: [:])
} else {
// Determine if it’s a back navigation by looking further back in history
let isBackNavigation = navigationHistory.count > 2 &&
navigationHistory[navigationHistory.count - 3].forComparison() == currentURL.forComparison()

// Fire the appropriate pixel based on navigation type
if isBackNavigation {
pixelFiring.fire(.duckPlayerYouTubeOverlayNavigationBack, withAdditionalParameters: [:])
} else if previousURL.isYoutubeWatch && currentURL.isYoutube {
// Forward navigation within YouTube (including non-video URLs)
pixelFiring.fire(.duckPlayerYouTubeNavigationWithinYouTube, withAdditionalParameters: [:])
} else if previousURL.isYoutubeWatch && !currentURL.isYoutube {
// Navigation outside YouTube
pixelFiring.fire(.duckPlayerYouTubeOverlayNavigationOutsideYoutube, withAdditionalParameters: [:])
}
}

pixelFiring.fire(.duckPlayerYouTubeOverlayNavigationOutsideYoutube, withAdditionalParameters: [:])
}
// Refined truncation logic:
if let lastOccurrenceIndex = (0..<navigationHistory.count - 1).last(where: { navigationHistory[$0].forComparison() == comparisonURL }) {
// Truncate history to keep only up to the last occurrence of the current URL in normalized form
navigationHistory = Array(navigationHistory.prefix(upTo: lastOccurrenceIndex + 1))
}

func navigationClosed(duckPlayerMode: DuckPlayerMode) {

guard duckPlayerMode == .alwaysAsk,
let lastURL = navigationHistory.last,
lastURL.isYoutubeWatch else { return }

pixelFiring.fire(.duckPlayerYouTubeOverlayNavigationClosed, withAdditionalParameters: [:])

// Cancel and reset the idle timer whenever a new navigation occurs
resetIdleTimer()
}

func overlayIdle(duckPlayerMode: DuckPlayerMode) {
guard duckPlayerMode == .alwaysAsk,
let lastURL = navigationHistory.last,
lastURL.isYoutubeWatch else { return }

idleTimer = Timer.scheduledTimer(withTimeInterval: idleTimeInterval, repeats: false) { [weak self] _ in
self?.pixelFiring.fire(.duckPlayerYouTubeNavigationIdle30, withAdditionalParameters: [:])
}
}
}
2 changes: 1 addition & 1 deletion DuckDuckGo/TabViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,7 @@ class TabViewController: UIViewController {
}

if webView.canGoBack {
webView.goBack()
webView.goBack()

Check failure on line 870 in DuckDuckGo/TabViewController.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Lines should not have trailing whitespace (trailing_whitespace)
chromeDelegate?.omniBar.resignFirstResponder()
return
}
Expand Down
Loading

0 comments on commit 2daac15

Please sign in to comment.