Skip to content

Commit

Permalink
Update BSK ref
Browse files Browse the repository at this point in the history
  • Loading branch information
ayoy committed Oct 14, 2024
2 parents 966c1ab + 0fe6554 commit f67e7f2
Show file tree
Hide file tree
Showing 104 changed files with 6,518 additions and 4,296 deletions.
1 change: 0 additions & 1 deletion .github/workflows/end-to-end.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ jobs:

steps:
- name: Create Asana task when workflow failed
if: ${{ failure() }}
run: |
curl -s "https://app.asana.com/api/1.0/tasks" \
--header "Accept: application/json" \
Expand Down
1 change: 1 addition & 0 deletions .maestro/release_tests/bookmarks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ tags:
- assertVisible: "Privacy Test Pages - Home"
- assertVisible: "privacy-test-pages.site"
- tapOn: "Privacy Test Pages - Home"
- tapOn: "Refresh Page"

# Verify site has been bookmarked
- assertVisible: "Browsing menu"
Expand Down
10 changes: 7 additions & 3 deletions .maestro/release_tests/firebutton.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,21 @@ tags:
- inputText: "https://example.com"
- pressKey: Enter

# Check history
- longPressOn: "Tab Switcher"
# Close tab
- tapOn: "Tab Switcher"
- tapOn: "Close \"Example Domain\" at example.com"
- tapOn:
id: "Add"

# Check history
- assertVisible:
id: "searchEntry"
- tapOn:
id: "searchEntry"
- inputText: "ex"
- assertVisible: "example.com"
- assertVisible: "Example Domain"
- tapOn: "Cancel"
- tapOn: "Example Domain"

# Fire button
- tapOn: "Close Tabs and Clear Data"
Expand Down
44 changes: 44 additions & 0 deletions .maestro/release_tests/tabs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,27 @@ tags:
- assertVisible: ".*Privacy Test Pages.*"
- tapOn: "Refresh Page"

# Suggestions
- assertVisible:
id: "searchEntry"

- tapOn:
id: "searchEntry"
- inputText: "ad click"
- assertVisible: "Switch to Tab.*search-company.site"
- tapOn: "Switch to Tab.*search-company.site"
- assertVisible: ".*Ad Click Flow.*"

- tapOn:
id: "searchEntry"
- inputText: "privacy"
- assertVisible: "Switch to Tab.*privacy-test-pages.site"
- tapOn: "Switch to Tab.*privacy-test-pages.site"
- assertVisible: ".*Privacy Test Pages.*"

# Needed or else test can't see the Tab Switcher button for some reason
- tapOn: "Refresh Page"

# Close Tab
- assertVisible: Tab Switcher
- tapOn: Tab Switcher
Expand All @@ -57,3 +78,26 @@ tags:
- assertNotVisible: ".*Ad Click Flow.*"
- assertVisible: "1 Private Tab"
- tapOn: "Done"

# Switch tabs from new tab
- tapOn: "Refresh Page"
- assertVisible: Tab Switcher
- tapOn: Tab Switcher
- assertVisible: ".*Privacy Test Pages.*"
- assertVisible:
id: "Add"
- tapOn:
id: "Add"
- assertVisible:
id: "searchEntry"
- tapOn:
id: "searchEntry"
- inputText: "privacy"
- assertVisible: "Switch to Tab.*privacy-test-pages.site"
- tapOn: "Switch to Tab.*privacy-test-pages.site"
- assertVisible: ".*Privacy Test Pages.*"
- tapOn: "Refresh Page"
- assertVisible: Tab Switcher
- tapOn: Tab Switcher
- assertVisible: "1 Private Tab"

10 changes: 10 additions & 0 deletions .maestro/shared/onboarding.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,13 @@ appId: com.duckduckgo.mobile.ios
# - assertVisible: "Make DuckDuckGo your default browser."
- tapOn:
text: "Skip"

- runFlow:
when:
visible: "Which color looks best on me?"
commands:
- assertVisible: "Next"
- tapOn: "Next"
- assertVisible: "Where should I put your address bar?"
- assertVisible: "Next"
- tapOn: "Next"
2 changes: 1 addition & 1 deletion Configuration/Version.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1 @@
MARKETING_VERSION = 7.139.0
MARKETING_VERSION = 7.140.0
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 = "\"aa6acaab3804053c652b64a3568cee2b\""
public static let embeddedDataSHA = "d56a1b7ff72713333d2d17e6825a6ab8f14d3f87b4b77c2406d74840d393960b"
public static let embeddedDataETag = "\"6330c36f7ff354d26f32ee951e0a972e\""
public static let embeddedDataSHA = "40f77d6db1db544f06740b3290c5a72e5f03f706d17c9c0e05b13cd9255f2778"
}

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

public struct Constants {
public static let embeddedDataETag = "\"4f9b48a36688eee92064578bc1aebe0a\""
public static let embeddedDataSHA = "ee51cab5fd4b82e6751a3d94680c89d4e248e0d456650b443f115998e1d3bec3"
public static let embeddedDataETag = "\"f5dad10599a8d6088ec1908da3eeb3cc\""
public static let embeddedDataSHA = "bb4c80f41383971693b241b4580fa74bbec1378ca6c2f8da8745dc6044fa1af9"
}

public var embeddedDataEtag: String {
Expand Down
35 changes: 20 additions & 15 deletions Core/DailyPixel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
//

import Foundation
import Persistence

/// A variant of pixel that is fired at most once per day.
///
Expand Down Expand Up @@ -52,6 +53,8 @@ public final class DailyPixel {
error: Swift.Error? = nil,
withAdditionalParameters params: [String: String] = [:],
includedParameters: [Pixel.QueryParameters] = [.appVersion],
pixelFiring: PixelFiring.Type = Pixel.self,
dailyPixelStore: KeyValueStoring = DailyPixel.storage,
onComplete: @escaping (Swift.Error?) -> Void = { _ in }) {
var key: String = pixel.name

Expand All @@ -61,13 +64,13 @@ public final class DailyPixel {
key.append(":\(createSortedStringOfValues(from: errorParams))")
}

if !hasBeenFiredToday(forKey: key, dailyPixelStorage: storage) {
Pixel.fire(pixel: pixel,
error: error,
includedParameters: includedParameters,
withAdditionalParameters: params,
onComplete: onComplete)
updatePixelLastFireDate(forKey: key)
if !hasBeenFiredToday(forKey: key, dailyPixelStore: dailyPixelStore) {
pixelFiring.fire(pixel: pixel,
error: error,
includedParameters: includedParameters,
withAdditionalParameters: params,
onComplete: onComplete)
updatePixelLastFireDate(forKey: key, dailyPixelStore: dailyPixelStore)
} else {
onComplete(Error.alreadyFired)
}
Expand All @@ -80,12 +83,14 @@ public final class DailyPixel {
error: Swift.Error? = nil,
withAdditionalParameters params: [String: String] = [:],
includedParameters: [Pixel.QueryParameters] = [.appVersion],
pixelFiring: PixelFiring.Type = Pixel.self,
dailyPixelStore: KeyValueStoring = DailyPixel.storage,
onDailyComplete: @escaping (Swift.Error?) -> Void = { _ in },
onCountComplete: @escaping (Swift.Error?) -> Void = { _ in }) {
let key: String = pixel.name

if !hasBeenFiredToday(forKey: key, dailyPixelStorage: storage) {
Pixel.fire(
if !hasBeenFiredToday(forKey: key, dailyPixelStore: dailyPixelStore) {
pixelFiring.fire(
pixelNamed: pixel.name + "_d",
withAdditionalParameters: params,
includedParameters: includedParameters,
Expand All @@ -94,25 +99,25 @@ public final class DailyPixel {
} else {
onDailyComplete(Error.alreadyFired)
}
updatePixelLastFireDate(forKey: key)
updatePixelLastFireDate(forKey: key, dailyPixelStore: dailyPixelStore)
var newParams = params
if let error {
newParams.appendErrorPixelParams(error: error)
}
Pixel.fire(
pixelFiring.fire(
pixelNamed: pixel.name + "_c",
withAdditionalParameters: newParams,
includedParameters: includedParameters,
onComplete: onCountComplete
)
}

private static func updatePixelLastFireDate(forKey key: String) {
storage.set(Date(), forKey: key)
private static func updatePixelLastFireDate(forKey key: String, dailyPixelStore: KeyValueStoring) {
dailyPixelStore.set(Date(), forKey: key)
}

private static func hasBeenFiredToday(forKey key: String, dailyPixelStorage: UserDefaults) -> Bool {
if let lastFireDate = dailyPixelStorage.object(forKey: key) as? Date {
private static func hasBeenFiredToday(forKey key: String, dailyPixelStore: KeyValueStoring) -> Bool {
if let lastFireDate = dailyPixelStore.object(forKey: key) as? Date {
return Date().isSameDay(lastFireDate)
}
return false
Expand Down
66 changes: 66 additions & 0 deletions Core/Debouncer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// Debouncer.swift
// DuckDuckGo
//
// Copyright © 2024 DuckDuckGo. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation

/// A class that provides a debouncing mechanism.
public final class Debouncer {
private let runLoop: RunLoop
private let mode: RunLoop.Mode
private var timer: Timer?

/// Initializes a new instance of `Debouncer`.
///
/// - Parameters:
/// - runLoop: The `RunLoop` on which the debounced actions will be scheduled. Defaults to the current run loop.
///
/// - mode: The `RunLoop.Mode` in which the debounced actions will be scheduled. Defaults to `.default`.
///
/// Use `RunLoop.main` for UI-related actions to ensure they run on the main thread.
public init(runLoop: RunLoop = .current, mode: RunLoop.Mode = .default) {
self.runLoop = runLoop
self.mode = mode
}

/// Debounces the provided block of code, executing it after a specified time interval elapses.
/// - Parameters:
/// - dueTime: The time interval (in seconds) to wait before executing the block.
/// - block: The closure to execute after the due time has passed.
///
/// If `dueTime` is less than or equal to zero, the block is executed immediately.
public func debounce(for dueTime: TimeInterval, block: @escaping () -> Void) {
timer?.invalidate()

guard dueTime > 0 else { return block() }

let timer = Timer(timeInterval: dueTime, repeats: false, block: { timer in
guard timer.isValid else { return }
block()
})

runLoop.add(timer, forMode: mode)
self.timer = timer
}

/// Cancels any pending execution of the debounced block.
public func cancel() {
timer?.invalidate()
timer = nil
}
}
7 changes: 5 additions & 2 deletions Core/DefaultVariantManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ extension FeatureName {
// public static let experimentalFeature = FeatureName(rawValue: "experimentalFeature")

public static let newOnboardingIntro = FeatureName(rawValue: "newOnboardingIntro")
public static let newOnboardingIntroHighlights = FeatureName(rawValue: "newOnboardingIntroHighlights")
public static let contextualDaxDialogs = FeatureName(rawValue: "contextualDaxDialogs")
}

public struct VariantIOS: Variant {
Expand Down Expand Up @@ -56,8 +58,9 @@ public struct VariantIOS: Variant {
VariantIOS(name: "sd", weight: doNotAllocate, isIncluded: When.always, features: []),
VariantIOS(name: "se", weight: doNotAllocate, isIncluded: When.always, features: []),

VariantIOS(name: "ma", weight: 1, isIncluded: When.always, features: []),
VariantIOS(name: "mb", weight: 1, isIncluded: When.always, features: [.newOnboardingIntro]),
VariantIOS(name: "ms", weight: 1, isIncluded: When.always, features: [.newOnboardingIntro]),
VariantIOS(name: "mu", weight: 1, isIncluded: When.always, features: [.newOnboardingIntro, .contextualDaxDialogs]),
VariantIOS(name: "mx", weight: 1, isIncluded: When.always, features: [.newOnboardingIntroHighlights, .contextualDaxDialogs]),

returningUser
]
Expand Down
5 changes: 5 additions & 0 deletions Core/FeatureFlag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ public enum FeatureFlag: String {
case onboardingHighlights
case autofillSurveys
case autcompleteTabs

/// https://app.asana.com/0/72649045549333/1208231259093710/f
case networkProtectionUserTips
}

extension FeatureFlag: FeatureFlagSourceProviding {
Expand Down Expand Up @@ -92,6 +95,8 @@ extension FeatureFlag: FeatureFlagSourceProviding {
return .remoteReleasable(.feature(.autofillSurveys))
case .autcompleteTabs:
return .remoteReleasable(.feature(.autocompleteTabs))
case .networkProtectionUserTips:
return .remoteReleasable(.subfeature(NetworkProtectionSubfeature.userTips))
}
}
}
Expand Down
28 changes: 20 additions & 8 deletions Core/NSAttributedStringExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,26 @@ extension NSAttributedString {
}
}

// MARK: - AttributedString Helper Extensions

public extension String {

var attributed: NSAttributedString {
NSAttributedString(string: self)
}

var nsRange: NSRange {
NSRange(startIndex..., in: self)
}

func range(of string: String) -> NSRange {
(self as NSString).range(of: string)
}

}

// MARK: Helper Operators

/// Concatenates two `NSAttributedString` instances, returning a new `NSAttributedString`.
///
/// - Parameters:
Expand Down Expand Up @@ -115,11 +135,3 @@ public func + (lhs: NSAttributedString, rhs: String) -> NSAttributedString {
public func + (lhs: String, rhs: NSAttributedString) -> NSAttributedString {
NSAttributedString(string: lhs) + rhs
}

private extension String {

var nsRange: NSRange {
NSRange(startIndex..., in: self)
}

}
Loading

0 comments on commit f67e7f2

Please sign in to comment.