Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding impression pixels for duckplayer in landscape mode #3493

Merged
merged 2 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Core/PixelEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,7 @@ extension Pixel {
case duckPlayerViewFromSERP
case duckPlayerViewFromOther
case duckPlayerOverlayYoutubeImpressions
case duckPlayerLandscapeLayoutImpressions
case duckPlayerOverlayYoutubeWatchHere
case duckPlayerSettingAlwaysDuckPlayer
case duckPlayerSettingAlwaysSettings
Expand Down Expand Up @@ -1654,6 +1655,9 @@ extension Pixel.Event {

// MARK: - WebView Error Page shown
case .webViewErrorPageShown: return "m_errorpageshown"

// MARK: - DuckPlayer FE Application Telemetry
case .duckPlayerLandscapeLayoutImpressions: return "duckplayer_landscape_layout_impressions"
}
}
}
Expand Down
64 changes: 63 additions & 1 deletion DuckDuckGo/DuckPlayer/DuckPlayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,50 @@ public enum DuckPlayerReferrer {
}
}

// Wrapper to allow sibling properties on each event in the future.
struct TelemetryEvent: Decodable {
let attributes: Attributes
}

// This is the first example of a new telemetry event
struct ImpressionAttributes: Decodable {
enum Layout: String, Decodable {
case landscape = "landscape-layout"
}

let name: String
let value: Layout
}

// Designed to represent the discriminated union used by the FE (where all events are schema-driven)
enum Attributes: Decodable {

// more events can be added here later, without needing a new handler
case impression(ImpressionAttributes)

private enum CodingKeys: String, CodingKey {
case name
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let name = try container.decode(String.self, forKey: .name)

switch name {
case "impression":
let attributes = try ImpressionAttributes(from: decoder)
self = .impression(attributes)

default:
throw DecodingError.dataCorruptedError(
forKey: .name,
in: container,
debugDescription: "Unknown name value: \(name)"
)
}
}
}

protocol DuckPlayerProtocol: AnyObject {

var settings: DuckPlayerSettings { get }
Expand All @@ -104,7 +148,8 @@ protocol DuckPlayerProtocol: AnyObject {
func openVideoInDuckPlayer(url: URL, webView: WKWebView)
func openDuckPlayerSettings(params: Any, message: WKScriptMessage) async -> Encodable?
func openDuckPlayerInfo(params: Any, message: WKScriptMessage) async -> Encodable?

func telemetryEvent(params: Any, message: WKScriptMessage) async -> Encodable?

func initialSetupPlayer(params: Any, message: WKScriptMessage) async -> Encodable?
func initialSetupOverlay(params: Any, message: WKScriptMessage) async -> Encodable?

Expand Down Expand Up @@ -239,6 +284,23 @@ final class DuckPlayer: DuckPlayerProtocol {
return nil
}

@MainActor
public func telemetryEvent(params: Any, message: WKScriptMessage) async -> Encodable? {
guard let event: TelemetryEvent = DecodableHelper.decode(from: params) else {
return nil
}

switch event.attributes {
case .impression(let attrs):
switch attrs.value {
case .landscape:
Pixel.fire(pixel: .duckPlayerLandscapeLayoutImpressions)
}
}

return nil
}

private func encodeUserValues() -> UserValues {
return UserValues(
duckPlayerMode: featureFlagger.isFeatureOn(.duckPlayer) ? settings.mode : .disabled,
Expand Down
3 changes: 3 additions & 0 deletions DuckDuckGo/DuckPlayer/YoutubePlayerUserScript.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ final class YoutubePlayerUserScript: NSObject, Subfeature {
static let initialSetup = "initialSetup"
static let openSettings = "openSettings"
static let openInfo = "openInfo"
static let telemetryEvent = "telemetryEvent"
}

init(duckPlayer: DuckPlayerProtocol) {
Expand Down Expand Up @@ -79,6 +80,8 @@ final class YoutubePlayerUserScript: NSObject, Subfeature {
return duckPlayer.openDuckPlayerSettings
case Handlers.openInfo:
return duckPlayer.openDuckPlayerInfo
case Handlers.telemetryEvent:
return duckPlayer.telemetryEvent
default:
assertionFailure("YoutubePlayerUserScript: Failed to parse User Script message: \(methodName)")
return nil
Expand Down
5 changes: 5 additions & 0 deletions DuckDuckGoTests/DuckPlayerMocks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ final class MockDuckPlayerSettings: DuckPlayerSettings {

final class MockDuckPlayer: DuckPlayerProtocol {

func telemetryEvent(params: Any, message: WKScriptMessage) async -> (any Encodable)? {
nil
}


var hostView: UIViewController?

func openDuckPlayerSettings(params: Any, message: WKScriptMessage) async -> (any Encodable)? {
Expand Down
Loading