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

SwiftUI Home - Analytics #1101

Merged
merged 5 commits into from
Nov 4, 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
15 changes: 15 additions & 0 deletions PocketKit/Sources/Analytics/AppEvents/Collection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,21 @@ public extension Events.Collection {
}

// MARK: Tracking Story
// story card viewed
static func storyImpression(url: String, positionInList: Int) -> Impression {
return Impression(
component: .card,
requirement: .viewable,
uiEntity: UiEntity(
.card,
identifier: "collection.story.impression",
index: positionInList
),
extraEntities: [
ContentEntity(url: url)
]
)
}
/**
* Fired when a user clicks a card on a collection
*/
Expand Down
12 changes: 6 additions & 6 deletions PocketKit/Sources/Analytics/AppEvents/ExpandedSlate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public extension Events.ExpandedSlate {
/**
Fired when a user views a slate in detail
*/
static func SlateExpanded(slateId: String, slateRequestId: String, slateExperimentId: String, slateIndex: Int, slateLineupId: String, slateLineupRequestId: String, slateLineupExperimentId: String) -> Impression {
static func slateExpanded(slateId: String, slateRequestId: String, slateExperimentId: String, slateIndex: Int, slateLineupId: String, slateLineupRequestId: String, slateLineupExperimentId: String) -> Impression {
return Impression(
component: .screen,
requirement: .viewable,
Expand All @@ -30,7 +30,7 @@ public extension Events.ExpandedSlate {
/**
Fired when a user clicks a card on Home using the /discover API
*/
static func SlateArticleContentOpen(url: String, positionInList: Int, recommendationId: String, destination: ContentOpen.Destination) -> ContentOpen {
static func slateArticleContentOpen(url: String, positionInList: Int, recommendationId: String, destination: ContentOpen.Destination) -> ContentOpen {
return ContentOpen(
destination: destination,
contentEntity:
Expand All @@ -50,7 +50,7 @@ public extension Events.ExpandedSlate {
/**
Fired when a user sees a card on Home using the /discover API
*/
static func SlateArticleImpression(url: String, positionInList: Int, recommendationId: String) -> Impression {
static func slateArticleImpression(url: String, positionInList: Int, recommendationId: String) -> Impression {
return Impression(
component: .card,
requirement: .viewable,
Expand All @@ -69,7 +69,7 @@ public extension Events.ExpandedSlate {
/**
Fired when a user saves a card on Home using the /discover API
*/
static func SlateArticleSave(url: String, positionInList: Int, recommendationId: String) -> Engagement {
static func slateArticleSave(url: String, positionInList: Int?, recommendationId: String) -> Engagement {
return Engagement(
.save(
contentEntity: ContentEntity(url: url)
Expand All @@ -89,7 +89,7 @@ public extension Events.ExpandedSlate {
/**
Fired when a user archives a card on Home using the /discover API
*/
static func SlateArticleArchive(url: String, positionInList: Int, recommendationId: String) -> Engagement {
static func slateArticleArchive(url: String, positionInList: Int, recommendationId: String) -> Engagement {
return Engagement(
.general,
uiEntity: UiEntity(
Expand All @@ -107,7 +107,7 @@ public extension Events.ExpandedSlate {
/**
Fired when a user shares a card on Home using the /discover API
*/
static func SlateArticleShare(url: String, positionInList: Int, recommendationId: String) -> Engagement {
static func slateArticleShare(url: String, positionInList: Int, recommendationId: String) -> Engagement {
return Engagement(
.general,
uiEntity: UiEntity(
Expand Down
54 changes: 40 additions & 14 deletions PocketKit/Sources/Analytics/AppEvents/Home.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public extension Events.Home {
/**
Fired when a card in the `Recent Saves` section scrolls into view
*/
static func RecentSavesCardImpression(url: String, positionInList: Int) -> Impression {
static func recentSavesCardImpression(url: String, positionInList: Int) -> Impression {
return Impression(
component: .card,
requirement: .viewable,
Expand All @@ -29,7 +29,7 @@ public extension Events.Home {
/**
Fired when a card in the `Recent Saves` section is shared
*/
static func RecentSavesCardShare(url: String, positionInList: Int) -> Engagement {
static func recentSavesCardShare(url: String, positionInList: Int) -> Engagement {
return Engagement(
uiEntity: UiEntity(
.button,
Expand All @@ -45,7 +45,7 @@ public extension Events.Home {
/**
Fired when a card in the `Recent Saves` section is deleted
*/
static func RecentSavesCardDelete(url: String, positionInList: Int) -> Engagement {
static func recentSavesCardDelete(url: String, positionInList: Int) -> Engagement {
return Engagement(
uiEntity: UiEntity(
.button,
Expand All @@ -61,7 +61,7 @@ public extension Events.Home {
/**
Fired when a card in the `Recent Saves` section is archived
*/
static func RecentSavesCardArchive(url: String, positionInList: Int) -> Engagement {
static func recentSavesCardArchive(url: String, positionInList: Int) -> Engagement {
return Engagement(
uiEntity: UiEntity(
.button,
Expand All @@ -74,10 +74,36 @@ public extension Events.Home {
)
}

static func recentSavesCardFavorite(url: String, positionInList: Int) -> Engagement {
return Engagement(
uiEntity: UiEntity(
.button,
identifier: "home.recent.favorite",
index: positionInList
),
extraEntities: [
ContentEntity(url: url)
]
)
}

static func recentSavesCardUnfavorite(url: String, positionInList: Int) -> Engagement {
return Engagement(
uiEntity: UiEntity(
.button,
identifier: "home.recent.unfavorite",
index: positionInList
),
extraEntities: [
ContentEntity(url: url)
]
)
}

/**
Fired when a user clicks a card in the `Recent Saves` section
*/
static func RecentSavesCardContentOpen(url: String, positionInList: Int?) -> ContentOpen {
static func recentSavesCardContentOpen(url: String, positionInList: Int?) -> ContentOpen {
return ContentOpen(
contentEntity:
ContentEntity(url: url),
Expand All @@ -92,7 +118,7 @@ public extension Events.Home {
/**
Fired when a user clicks a card on Home using the homeSlateLineup API
*/
static func SlateArticleContentOpen(url: String, positionInList: Int?, recommendationId: String, destination: ContentOpen.Destination) -> ContentOpen {
static func slateArticleContentOpen(url: String, positionInList: Int?, recommendationId: String, destination: ContentOpen.Destination) -> ContentOpen {
return ContentOpen(
destination: destination,
contentEntity:
Expand All @@ -112,7 +138,7 @@ public extension Events.Home {
/**
Fired when a user sees a card on Home using the homeSlateLineup API
*/
static func SlateArticleImpression(url: String, positionInList: Int, recommendationId: String) -> Impression {
static func slateArticleImpression(url: String, positionInList: Int, recommendationId: String) -> Impression {
return Impression(
component: .card,
requirement: .viewable,
Expand All @@ -131,7 +157,7 @@ public extension Events.Home {
/**
Fired when a user saves a card on Home using the homeSlateLineup API
*/
static func SlateArticleSave(url: String, positionInList: Int, recommendationId: String) -> Engagement {
static func slateArticleSave(url: String, positionInList: Int, recommendationId: String) -> Engagement {
return Engagement(
.save(
contentEntity: ContentEntity(url: url)
Expand All @@ -150,7 +176,7 @@ public extension Events.Home {
/**
Fired when a user archives a card on Home using the /discover API
*/
static func SlateArticleArchive(url: String, positionInList: Int, recommendationId: String) -> Engagement {
static func slateArticleArchive(url: String, positionInList: Int, recommendationId: String) -> Engagement {
return Engagement(
.general,
uiEntity: UiEntity(
Expand All @@ -168,7 +194,7 @@ public extension Events.Home {
/**
Fired when a user shares a card on Home using the /discover API
*/
static func SlateArticleShare(url: String, positionInList: Int, recommendationId: String) -> Engagement {
static func slateArticleShare(url: String, positionInList: Int, recommendationId: String) -> Engagement {
return Engagement(
.general,
uiEntity: UiEntity(
Expand All @@ -186,7 +212,7 @@ public extension Events.Home {
/**
Fired when a user selects the report action on Home using the /discover API
*/
static func SlateArticleReport(url: String, reason: ReportEntity.Reason, recommendationId: String, comment: String?) -> Engagement {
static func slateArticleReport(url: String, reason: ReportEntity.Reason, recommendationId: String, comment: String?) -> Engagement {
return Engagement(
.report(
reportEntity: ReportEntity(reason: reason, comment: comment),
Expand All @@ -204,7 +230,7 @@ public extension Events.Home {

// MARK: Shared With You
/// Shared With You card viewed
static func sharedWithYouCardImpression(url: String, positionInList: Int) -> Impression {
static func sharedWithYouCardImpression(url: String, positionInList: Int?) -> Impression {
return Impression(
component: .card,
requirement: .viewable,
Expand Down Expand Up @@ -233,7 +259,7 @@ public extension Events.Home {
}

/// Shared With You Item saved
static func sharedWithYouItemSave(url: String, positionInList: Int) -> Engagement {
static func sharedWithYouItemSave(url: String, positionInList: Int?) -> Engagement {
return Engagement(
uiEntity: UiEntity(
.button,
Expand All @@ -247,7 +273,7 @@ public extension Events.Home {
}

/// Shared With You item unsaved
static func sharedWithYouItemArchive(url: String, positionInList: Int) -> Engagement {
static func sharedWithYouItemArchive(url: String, positionInList: Int?) -> Engagement {
return Engagement(
uiEntity: UiEntity(
.button,
Expand Down
20 changes: 10 additions & 10 deletions PocketKit/Sources/PocketKit/Home/HomeViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ extension HomeViewModel {
) {
switch source {
case .app:
tracker.track(event: Events.Home.SlateArticleContentOpen(
tracker.track(event: Events.Home.slateArticleContentOpen(
url: url,
positionInList: positionInList,
recommendationId: recommendationId,
Expand Down Expand Up @@ -598,7 +598,7 @@ extension HomeViewModel {
private func trackRecentSavesOpen(url: String, positionInList: Int?, source: ReadableSource) {
switch source {
case .app:
tracker.track(event: Events.Home.RecentSavesCardContentOpen(url: url, positionInList: positionInList))
tracker.track(event: Events.Home.recentSavesCardContentOpen(url: url, positionInList: positionInList))
case .external:
tracker.track(event: Events.Deeplinks.deeplinkArticleContentOpen(url: url, destination: .internal))
case .widget:
Expand Down Expand Up @@ -731,7 +731,7 @@ extension HomeViewModel {

private func delete(item: CDSavedItem, indexPath: IndexPath) {
presentedAlert = nil
tracker.track(event: Events.Home.RecentSavesCardDelete(url: item.url, positionInList: indexPath.item))
tracker.track(event: Events.Home.recentSavesCardDelete(url: item.url, positionInList: indexPath.item))
source.delete(item: item)
}
}
Expand Down Expand Up @@ -856,15 +856,15 @@ extension HomeViewModel {
// This view model is used within the context of a view that is presented within Saves
let shareableUrl = await shareableUrl(recommendation.item) ?? recommendation.item.bestURL
self.sharedActivity = PocketItemActivity.fromHome(url: shareableUrl, sender: sender)
tracker.track(event: Events.Home.SlateArticleShare(url: shareableUrl, positionInList: indexPath.item, recommendationId: recommendation.analyticsID))
tracker.track(event: Events.Home.slateArticleShare(url: shareableUrl, positionInList: indexPath.item, recommendationId: recommendation.analyticsID))
}

private func share(_ savedItem: CDSavedItem, at indexPath: IndexPath, with sender: Any?) async {
// This view model is used within the context of a view that is presented within Home, but
// within the context of "Recent Saves"
let shareableUrl = await shareableUrl(savedItem.item) ?? savedItem.url
self.sharedActivity = PocketItemActivity.fromSaves(url: shareableUrl, sender: sender)
tracker.track(event: Events.Home.RecentSavesCardShare(url: shareableUrl, positionInList: indexPath.item))
tracker.track(event: Events.Home.recentSavesCardShare(url: shareableUrl, positionInList: indexPath.item))
}

private func share(_ sharedWithYouItem: CDSharedWithYouItem, at indexPath: IndexPath, with sender: Any?) async {
Expand All @@ -889,18 +889,18 @@ extension HomeViewModel {
private func save(_ recommendation: CDRecommendation, at indexPath: IndexPath) {
source.save(recommendation: recommendation)
let givenURL = recommendation.item.givenURL
tracker.track(event: Events.Home.SlateArticleSave(url: givenURL, positionInList: indexPath.item, recommendationId: recommendation.analyticsID))
tracker.track(event: Events.Home.slateArticleSave(url: givenURL, positionInList: indexPath.item, recommendationId: recommendation.analyticsID))
}

private func archive(_ recommendation: CDRecommendation, at indexPath: IndexPath) {
source.archive(recommendation: recommendation)
let givenURL = recommendation.item.givenURL
tracker.track(event: Events.Home.SlateArticleArchive(url: givenURL, positionInList: indexPath.item, recommendationId: recommendation.analyticsID))
tracker.track(event: Events.Home.slateArticleArchive(url: givenURL, positionInList: indexPath.item, recommendationId: recommendation.analyticsID))
}

private func archive(_ savedItem: CDSavedItem, at indexPath: IndexPath) {
self.source.archive(item: savedItem)
tracker.track(event: Events.Home.RecentSavesCardArchive(url: savedItem.url, positionInList: indexPath.item))
tracker.track(event: Events.Home.recentSavesCardArchive(url: savedItem.url, positionInList: indexPath.item))
}
}

Expand All @@ -919,7 +919,7 @@ extension HomeViewModel {
guard let savedItem = source.viewObject(id: objectID) as? CDSavedItem else {
return
}
tracker.track(event: Events.Home.RecentSavesCardImpression(url: savedItem.url, positionInList: indexPath.item))
tracker.track(event: Events.Home.recentSavesCardImpression(url: savedItem.url, positionInList: indexPath.item))
return
case .recommendationHero(let objectID), .recommendationCarousel(let objectID):
guard let recommendation = source.viewObject(id: objectID) as? CDRecommendation else {
Expand All @@ -931,7 +931,7 @@ extension HomeViewModel {
}

let givenURL = item.givenURL
tracker.track(event: Events.Home.SlateArticleImpression(url: givenURL, positionInList: indexPath.item, recommendationId: recommendation.analyticsID))
tracker.track(event: Events.Home.slateArticleImpression(url: givenURL, positionInList: indexPath.item, recommendationId: recommendation.analyticsID))
case .singinBanner:
tracker.track(event: Events.SignedOut.signinBannerImpression())
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class SlateDetailViewModel {
Log.capture(message: "Tried to display slate without slatelineup, not logging analytics")
return
}
tracker.track(event: Events.ExpandedSlate.SlateExpanded(slateId: slate.remoteID, slateRequestId: slate.requestID, slateExperimentId: slate.experimentID, slateIndex: slateIndex, slateLineupId: slateLineup.remoteID, slateLineupRequestId: slateLineup.requestID, slateLineupExperimentId: slateLineup.experimentID))
tracker.track(event: Events.ExpandedSlate.slateExpanded(slateId: slate.remoteID, slateRequestId: slate.requestID, slateExperimentId: slate.experimentID, slateIndex: slateIndex, slateLineupId: slateLineup.remoteID, slateLineupRequestId: slateLineup.requestID, slateLineupExperimentId: slateLineup.experimentID))
}

func fetch() {
Expand Down Expand Up @@ -116,7 +116,7 @@ class SlateDetailViewModel {
}

let givenURL = item.givenURL
tracker.track(event: Events.ExpandedSlate.SlateArticleImpression(url: givenURL, positionInList: indexPath.item, recommendationId: recommendation.analyticsID))
tracker.track(event: Events.ExpandedSlate.slateArticleImpression(url: givenURL, positionInList: indexPath.item, recommendationId: recommendation.analyticsID))
}
}
}
Expand Down Expand Up @@ -177,7 +177,7 @@ extension SlateDetailViewModel {
}

let givenURL = item.givenURL
tracker.track(event: Events.ExpandedSlate.SlateArticleContentOpen(url: givenURL, positionInList: indexPath.item, recommendationId: recommendation.analyticsID, destination: destination))
tracker.track(event: Events.ExpandedSlate.slateArticleContentOpen(url: givenURL, positionInList: indexPath.item, recommendationId: recommendation.analyticsID, destination: destination))
}
}

Expand Down Expand Up @@ -232,13 +232,13 @@ extension SlateDetailViewModel {
private func save(_ recommendation: CDRecommendation, at indexPath: IndexPath) {
source.save(recommendation: recommendation)
let givenURL = recommendation.item.givenURL
tracker.track(event: Events.ExpandedSlate.SlateArticleSave(url: givenURL, positionInList: indexPath.item, recommendationId: recommendation.analyticsID))
tracker.track(event: Events.ExpandedSlate.slateArticleSave(url: givenURL, positionInList: indexPath.item, recommendationId: recommendation.analyticsID))
}

private func archive(_ recommendation: CDRecommendation, at indexPath: IndexPath) {
source.archive(recommendation: recommendation)
let givenURL = recommendation.item.givenURL
tracker.track(event: Events.ExpandedSlate.SlateArticleArchive(url: givenURL, positionInList: indexPath.item, recommendationId: recommendation.analyticsID))
tracker.track(event: Events.ExpandedSlate.slateArticleArchive(url: givenURL, positionInList: indexPath.item, recommendationId: recommendation.analyticsID))
}

private func report(_ recommendation: CDRecommendation, at indexPath: IndexPath) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

/// Set of info to send along actions for analytics purposes
struct AnalyticsInfo {
let type: CardType
let url: String
let index: Int
let recommendationID: String?
let externalDestination: Bool

init(type: CardType, url: String, index: Int = 0, recommendationID: String? = nil, externalDestination: Bool = false) {
self.type = type
self.url = url
self.index = index
self.recommendationID = recommendationID
self.externalDestination = externalDestination
}
}
14 changes: 14 additions & 0 deletions PocketKit/Sources/PocketKit/Home/SwiftUI/Models/CardType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

/// Identifies the type of a card for analytics purposes
enum CardType {
case recentSave
case recommendation
case sharedWithYou
case collection // This is not a card per se, but contains the same operations as a card
case collectionStory
case slateDetail
case sharedWithYouDetail
}
Loading