Skip to content

Commit

Permalink
Merge branch 'main' into sam/remove-atb-from-default-pixel-parameters
Browse files Browse the repository at this point in the history
* main:
  Release 7.116.0-1 (#2761)
  Remove validator app (#2754)
  Fix crash when quickly adding/removing tabs in switcher (#2760)
  Fix settings navigation bar colors after reopening (#2758)
  Alpha ad-hoc lane (#2492)
  Keep a weak reference to UserScriptMessageBroker (#2755)
  Add refresh config cell to top of debug (#2735)
  VPN: Replace available interfaces in VPN metadata (#2750)
  Require device auth to be set in order to use Sync (#2722)
  Add new iOS pixels for measuring navigation  (#2730)
  Privacy pro metadata updates (#2747)
  Update autoconsent to v10.6.1 (#2734)
  Limit Stale actions to issues (#2745)
  Change DAU pixel for VPN to weekly (#2684)
  Support Autofill Domains with Port Number Suffixes (#2715)
  Update secure vault error pixels to fire daily (#2557)
  Subscription: Fix 'Back' button not present (#2741)
  Subscription State improvements + Remove SUBSCRIPTION Flag (#2726)
  Release 7.116.0-0 (#2739)
  Release 7.116.0-0 (#2737)
  • Loading branch information
samsymons committed Apr 18, 2024
2 parents 07b1187 + 79d3cf1 commit 6a13627
Show file tree
Hide file tree
Showing 80 changed files with 1,097 additions and 871 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/stale-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ jobs:
uses: actions/stale@v9
with:
stale-pr-message: 'This PR has been inactive for more than 7 days and will be automatically closed 7 days from now.'
days-before-stale: 7
days-before-pr-stale: 7
close-pr-message: 'This PR has been closed after 14 days of inactivity. Feel free to reopen it if you plan to continue working on it or have further discussions.'
days-before-close: 7
days-before-pr-close: 7
stale-pr-label: stale
exempt-draft-pr: true
2 changes: 1 addition & 1 deletion Configuration/Version.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1 @@
MARKETING_VERSION = 7.115.0
MARKETING_VERSION = 7.116.0
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// AccountManagerExtension.swift
// AccountManager+AppGroup.swift
// DuckDuckGo
//
// Copyright © 2024 DuckDuckGo. All rights reserved.
Expand All @@ -17,8 +17,6 @@
// limitations under the License.
//

#if SUBSCRIPTION

import Foundation
import Subscription

Expand All @@ -27,5 +25,3 @@ public extension AccountManager {
self.init(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs))
}
}

#endif
4 changes: 2 additions & 2 deletions Core/AppPrivacyConfigurationDataProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import BrowserServicesKit
final public class AppPrivacyConfigurationDataProvider: EmbeddedDataProvider {

public struct Constants {
public static let embeddedDataETag = "\"f5c95349fa08b7dd5a008deb15561c32\""
public static let embeddedDataSHA = "25ff4ebab0f843baa0878838c488cf2a7acfc8d83e58c7afb1aae13a78b5297f"
public static let embeddedDataETag = "\"04caca2ca6549201eea931ca869c5e39\""
public static let embeddedDataSHA = "ddb923e2de2a0a27bc1050e32c89276834a3f3dd61b7c8672dac6f2d93047333"
}

public var embeddedDataEtag: String {
Expand Down
49 changes: 35 additions & 14 deletions Core/DailyPixel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,28 @@ public final class DailyPixel {
private static let storage: UserDefaults = UserDefaults(suiteName: Constant.dailyPixelStorageIdentifier)!

/// Sends a given Pixel once per day.
/// This means a pixel will get sent twice the first time it is called per-day.
/// This is useful in situations where pixels receive spikes in volume, as the daily pixel can be used to determine how many users are actually affected.
/// Does not append any suffix unlike the alternative function below
public static func fire(pixel: Pixel.Event,
error: Swift.Error? = nil,
withAdditionalParameters params: [String: String] = [:],
includedParameters: [Pixel.QueryParameters] = [.appVersion],
onComplete: @escaping (Swift.Error?) -> Void = { _ in }) {
var key: String = pixel.name

if !pixel.hasBeenFiredToday(dailyPixelStorage: storage) {
if let error = error {
var errorParams: [String: String] = [:]
errorParams.appendErrorPixelParams(error: error)
key.append(":\(createSortedStringOfValues(from: errorParams))")
}

if !hasBeenFiredToday(forKey: key, dailyPixelStorage: storage) {
Pixel.fire(pixel: pixel,
withAdditionalParameters: params,
error: error,
includedParameters: includedParameters,
withAdditionalParameters: params,
onComplete: onComplete)
updatePixelLastFireDate(pixel: pixel)
updatePixelLastFireDate(forKey: key)
} else {
onComplete(Error.alreadyFired)
}
Expand All @@ -74,7 +82,9 @@ public final class DailyPixel {
includedParameters: [Pixel.QueryParameters] = [.appVersion],
onDailyComplete: @escaping (Swift.Error?) -> Void = { _ in },
onCountComplete: @escaping (Swift.Error?) -> Void = { _ in }) {
if !pixel.hasBeenFiredToday(dailyPixelStorage: storage) {
let key: String = pixel.name

if !hasBeenFiredToday(forKey: key, dailyPixelStorage: storage) {
Pixel.fire(
pixelNamed: pixel.name + "_d",
withAdditionalParameters: params,
Expand All @@ -84,7 +94,7 @@ public final class DailyPixel {
} else {
onDailyComplete(Error.alreadyFired)
}
updatePixelLastFireDate(pixel: pixel)
updatePixelLastFireDate(forKey: key)
var newParams = params
if let error {
newParams.appendErrorPixelParams(error: error)
Expand All @@ -97,19 +107,30 @@ public final class DailyPixel {
)
}

private static func updatePixelLastFireDate(pixel: Pixel.Event) {
storage.set(Date(), forKey: pixel.name)
private static func updatePixelLastFireDate(forKey key: String) {
storage.set(Date(), forKey: key)
}

}

private extension Pixel.Event {

func hasBeenFiredToday(dailyPixelStorage: UserDefaults) -> Bool {
if let lastFireDate = dailyPixelStorage.object(forKey: name) as? Date {
private static func hasBeenFiredToday(forKey key: String, dailyPixelStorage: UserDefaults) -> Bool {
if let lastFireDate = dailyPixelStorage.object(forKey: key) as? Date {
return Date().isSameDay(lastFireDate)
}
return false
}

private static func createSortedStringOfValues(from dict: [String: String], maxLength: Int = 50) -> String {
let sortedKeys = dict.keys.sorted()

let uniqueString = sortedKeys.compactMap { key -> String? in
guard let value = dict[key] else { return nil }
return value
}.joined(separator: ";")

if uniqueString.count > maxLength {
return String(uniqueString.prefix(maxLength))
}

return uniqueString
}

}
1 change: 1 addition & 0 deletions Core/Pixel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ public struct PixelParameters {
public static let function = "function"
public static let line = "line"
public static let reason = "reason"
public static let vpnCohort = "cohort"

// Return user
public static let returnUserErrorCode = "error_code"
Expand Down
93 changes: 79 additions & 14 deletions Core/PixelEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ extension Pixel {
case appLaunch
case refreshPressed
case pullToRefresh


case deviceOrientationLandscape

case keyboardGoWhileOnNTP
case keyboardGoWhileOnWebsite
case keyboardGoWhileOnSERP

case forgetAllPressedBrowsing
case forgetAllPressedTabSwitching
case forgetAllExecuted
Expand All @@ -48,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
Expand Down Expand Up @@ -77,7 +88,17 @@ extension Pixel {

case addressBarShare
case addressBarSettings

case addressBarCancelPressedOnNTP
case addressBarCancelPressedOnWebsite
case addressBarCancelPressedOnSERP
case addressBarClickOnNTP
case addressBarClickOnWebsite
case addressBarClickOnSERP
case addressBarClearPressedOnNTP
case addressBarClearPressedOnWebsite
case addressBarClearPressedOnSERP
case addressBarGestureDismiss

case shareSheetResultSuccess
case shareSheetResultFail
case shareSheetActivityCopy
Expand All @@ -95,10 +116,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
Expand Down Expand Up @@ -135,7 +159,14 @@ extension Pixel {
case voiceSearchDone
case openVoiceSearch
case voiceSearchCancelled


case bookmarkLaunchList
case bookmarkLaunchScored
case bookmarkAddFavoriteFromBookmark
case bookmarkRemoveFavoriteFromBookmark
case bookmarkAddFavoriteBySwipe
case bookmarkDeletedFromBookmark

case bookmarkImportSuccess
case bookmarkImportFailure
case bookmarkImportFailureParsingDL
Expand Down Expand Up @@ -509,7 +540,8 @@ extension Pixel {

case swipeTabsUsed
case swipeTabsUsedDaily

case swipeToOpenNewTab

case bookmarksCleanupFailed
case bookmarksCleanupAttemptedWhileSyncWasEnabled
case favoritesCleanupFailed
Expand Down Expand Up @@ -658,7 +690,13 @@ extension Pixel.Event {
case .appLaunch: return "ml"
case .refreshPressed: return "m_r"
case .pullToRefresh: return "m_pull-to-reload"


case .deviceOrientationLandscape: return "m_device_orientation_landscape"

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"
case .forgetAllExecuted: return "mf"
Expand All @@ -674,7 +712,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"
Expand All @@ -701,9 +744,20 @@ 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 .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"
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"
case .shareSheetActivityCopy: return "m_sharesheet_activity_copy"
Expand All @@ -719,12 +773,22 @@ 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 .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 .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"
Expand Down Expand Up @@ -1121,7 +1185,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"
Expand Down
27 changes: 19 additions & 8 deletions Core/UniquePixel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ public final class UniquePixel {
}

public static let storage = UserDefaults(suiteName: Constant.uniquePixelStorageIdentifier)!
private static let calendar: Calendar = {
var calendar = Calendar.current
calendar.timeZone = TimeZone(secondsFromGMT: 0)!
return calendar
}()

private static let weeksToCoalesceCohort = 6

/// Sends a unique Pixel
/// This requires the pixel name to end with `_u`
Expand All @@ -59,15 +66,19 @@ public final class UniquePixel {
}
}

public static func dateString(for date: Date?) -> String {
guard let date else { return "" }

let dateFormatter = DateFormatter()
dateFormatter.calendar = Calendar.current
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
dateFormatter.dateFormat = "yyyy-MM-dd"
public static func cohort(from cohortLocalDate: Date?) -> String {
guard let cohortLocalDate,
let baseDate = calendar.date(from: .init(year: 2023, month: 1, day: 1)),
let weeksSinceCohortAssigned = calendar.dateComponents([.weekOfYear], from: cohortLocalDate, to: Date()).weekOfYear,
let assignedCohort = calendar.dateComponents([.weekOfYear], from: baseDate, to: cohortLocalDate).weekOfYear else {
return ""
}

return dateFormatter.string(from: date)
if weeksSinceCohortAssigned > Self.weeksToCoalesceCohort {
return ""
} else {
return "week-" + String(assignedCohort + 1)
}
}
}

Expand Down
Loading

0 comments on commit 6a13627

Please sign in to comment.