Skip to content

Commit

Permalink
Add Sync feature flags (#1992)
Browse files Browse the repository at this point in the history
Task/Issue URL: https://app.asana.com/0/0/1206046777189407/f

Description:
This change add support for Sync feature in Privacy Configuration, together with
4 subfeatures defining availability of various parts of Sync experience.
DDGSyncing gets a read-only feature flag variable as well as a publisher.
PrivacyConfigurationManager is now a Sync dependency, and DDGSync takes
care internally of listening to Privacy Config changes and updating feature flags
as needed.
Feature flag responsible for actual data syncing is handled internally in DDGSync
by cancelling all pending sync operations and disabling adding new operations.
Other feature flags should be handled by client apps.
  • Loading branch information
ayoy authored Dec 20, 2023
1 parent 00e4e18 commit 17d5a92
Show file tree
Hide file tree
Showing 33 changed files with 327 additions and 120 deletions.
2 changes: 1 addition & 1 deletion DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -12942,7 +12942,7 @@
repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit";
requirement = {
kind = exactVersion;
version = 96.0.1;
version = 97.0.0;
};
};
AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/duckduckgo/BrowserServicesKit",
"state" : {
"revision" : "308abf4ebf170dc73d9f1a8a1730ed3170bed2d5",
"version" : "96.0.1"
"revision" : "d671accf1bf7097c4e7f5cd55cd1c6dfa005cf92",
"version" : "97.0.0"
}
},
{
Expand Down
9 changes: 8 additions & 1 deletion DuckDuckGo/Application/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, FileDownloadManagerDel
private(set) var syncDataProviders: SyncDataProviders!
private(set) var syncService: DDGSyncing?
private var isSyncInProgressCancellable: AnyCancellable?
private var syncFeatureFlagsCancellable: AnyCancellable?
private var screenLockedCancellable: AnyCancellable?
private var emailCancellables = Set<AnyCancellable>()
let bookmarksManager = LocalBookmarkManager.shared
Expand Down Expand Up @@ -339,7 +340,13 @@ final class AppDelegate: NSObject, NSApplicationDelegate, FileDownloadManagerDel
let environment = defaultEnvironment
#endif
let syncDataProviders = SyncDataProviders(bookmarksDatabase: BookmarkDatabase.shared.db)
let syncService = DDGSync(dataProvidersSource: syncDataProviders, errorEvents: SyncErrorHandler(), log: OSLog.sync, environment: environment)
let syncService = DDGSync(
dataProvidersSource: syncDataProviders,
errorEvents: SyncErrorHandler(),
privacyConfigurationManager: ContentBlocking.shared.privacyConfigurationManager,
log: OSLog.sync,
environment: environment
)
syncService.initializeIfNeeded()
syncDataProviders.setUpDatabaseCleaners(syncService: syncService)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import BrowserServicesKit
final class AppPrivacyConfigurationDataProvider: EmbeddedDataProvider {

public struct Constants {
public static let embeddedDataETag = "\"ca66d409eb00e5c19f3a0abae449dd1a\""
public static let embeddedDataSHA = "42f9d3064372bc85ac8ee37afe883ed4741d6a3cfcb9ce927c2f732c3f694140"
public static let embeddedDataETag = "\"8e38db3f042f4a2a5c9f7ca8d33f17c9\""
public static let embeddedDataSHA = "a9fc8ee927a37d1b5545377ff29de798f3ec3b8a757430c3af72d13a3844c258"
}

var embeddedDataEtag: String {
Expand Down
77 changes: 59 additions & 18 deletions DuckDuckGo/ContentBlocker/macos-config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"readme": "https://github.com/duckduckgo/privacy-configuration",
"version": 1702579565498,
"version": 1703003631137,
"features": {
"adClickAttribution": {
"readme": "https://help.duckduckgo.com/duckduckgo-help-pages/privacy/web-tracking-protections/#3rd-party-tracker-loading-protection",
Expand Down Expand Up @@ -245,6 +245,9 @@
{
"domain": "metro.co.uk"
},
{
"domain": "youtube.com"
},
{
"domain": "earth.google.com"
},
Expand All @@ -264,7 +267,7 @@
]
},
"state": "enabled",
"hash": "9ab9e1acdb6a8617c77109acc1e3943c"
"hash": "a1060783f1bf56f5cc661b994c9c9e56"
},
"autofill": {
"exceptions": [
Expand Down Expand Up @@ -1030,12 +1033,16 @@
{
"domain": "flysas.com",
"reason": "https://github.com/duckduckgo/privacy-configuration/issues/1347"
},
{
"domain": "facebook.com",
"reason": "https://github.com/duckduckgo/privacy-configuration/issues/1641"
}
]
},
"exceptions": [],
"state": "enabled",
"hash": "d757f6509e9a9a20140c755ed0f21ea2"
"hash": "6ed03febdd780fd845cc1f7d6ce74ecf"
},
"dbp": {
"state": "enabled",
Expand Down Expand Up @@ -2014,6 +2021,23 @@
}
]
},
{
"domain": "dexerto.com",
"rules": [
{
"selector": "#leaderboard-top-adhesion",
"type": "closest-empty"
},
{
"selector": "[data-cy='Ad']",
"type": "closest-empty"
},
{
"selector": "[data-cy='VidazooPlayer']",
"type": "closest-empty"
}
]
},
{
"domain": "dpreview.com",
"rules": [
Expand Down Expand Up @@ -3678,7 +3702,7 @@
]
},
"state": "enabled",
"hash": "c34713afaf78e090b587a923f132ed56"
"hash": "8551081ffe228a4bef49deba3fe37b19"
},
"exceptionHandler": {
"exceptions": [
Expand Down Expand Up @@ -3933,10 +3957,13 @@
},
{
"domain": "airbnb.com.br"
},
{
"domain": "zoom.us"
}
],
"state": "enabled",
"hash": "75e673ce365430652fc7cc896ed49a5f"
"hash": "82ebfddf791575ada285a49b7fdc71ca"
},
"fingerprintingScreenSize": {
"settings": {
Expand Down Expand Up @@ -4460,6 +4487,11 @@
"state": "disabled",
"hash": "5e792dd491428702bc0104240fbce0ce"
},
"sync": {
"exceptions": [],
"state": "disabled",
"hash": "728493ef7a1488e4781656d3f9db84aa"
},
"trackerAllowlist": {
"state": "enabled",
"settings": {
Expand Down Expand Up @@ -4750,8 +4782,7 @@
{
"rule": "analytics.analytics-egain.com/onetag/",
"domains": [
"landsend.com",
"support.norton.com"
"<all>"
]
}
]
Expand Down Expand Up @@ -5323,6 +5354,7 @@
"asics.com",
"brooklinen.com",
"carters.com",
"otterbox.com",
"seatosummit.com"
]
}
Expand Down Expand Up @@ -5382,6 +5414,16 @@
}
]
},
"egain.cloud": {
"rules": [
{
"rule": "egain.cloud/",
"domains": [
"<all>"
]
}
]
},
"ensighten.com": {
"rules": [
{
Expand Down Expand Up @@ -5509,8 +5551,7 @@
{
"rule": "app.five9.com",
"domains": [
"gmsdnv.com",
"machiassavings.bank"
"<all>"
]
}
]
Expand Down Expand Up @@ -5750,6 +5791,12 @@
"rawstory.com",
"usatoday.com"
]
},
{
"rule": "storage.googleapis.com/code.snapengage.com/",
"domains": [
"<all>"
]
}
]
},
Expand Down Expand Up @@ -5977,15 +6024,9 @@
"gorgias.chat": {
"rules": [
{
"rule": "config.gorgias.chat",
"rule": "gorgias.chat",
"domains": [
"help.athleticbrewing.com"
]
},
{
"rule": "assets.gorgias.chat",
"domains": [
"help.athleticbrewing.com"
"<all>"
]
}
]
Expand Down Expand Up @@ -7509,7 +7550,7 @@
"domain": "sundancecatalog.com"
}
],
"hash": "5cecb6d28193f468b28b9afdaca04da1"
"hash": "b6996e16fe1785f6d75cd6302da1f48e"
},
"trackingCookies1p": {
"settings": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ struct VPNLocationView: View {

@ViewBuilder
private func nearest(isSelected: Bool) -> some View {
PreferencePaneSection(vericalPadding: 12) {
PreferencePaneSection(verticalPadding: 12) {
Text(UserText.vpnLocationRecommendedSectionTitle)
.font(.system(size: 15))
.foregroundColor(.primary)
Expand Down Expand Up @@ -98,7 +98,7 @@ struct VPNLocationView: View {
EmptyView()
.listRowBackground(Color.clear)
case .loaded(let countryItems):
PreferencePaneSection(vericalPadding: 12) {
PreferencePaneSection(verticalPadding: 12) {
Text(UserText.vpnLocationCustomSectionTitle)
.font(.system(size: 15))
.foregroundColor(.primary)
Expand Down
4 changes: 2 additions & 2 deletions DuckDuckGo/Preferences/Model/PreferencesSection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct PreferencesSection: Hashable, Identifiable {
let panes: [PreferencePaneIdentifier]

@MainActor
static func defaultSections(includingDuckPlayer: Bool, includingVPN: Bool) -> [PreferencesSection] {
static func defaultSections(includingDuckPlayer: Bool, includingSync: Bool, includingVPN: Bool) -> [PreferencesSection] {
let regularPanes: [PreferencePaneIdentifier] = {
#if SUBSCRIPTION
var panes: [PreferencePaneIdentifier] = [.privacy, .subscription, .general, .appearance, .autofill, .downloads]
Expand All @@ -37,7 +37,7 @@ struct PreferencesSection: Hashable, Identifiable {
#else
var panes: [PreferencePaneIdentifier] = [.general, .appearance, .privacy, .autofill, .downloads]

if NSApp.delegateTyped.internalUserDecider.isInternalUser {
if includingSync {
panes.insert(.sync, at: 1)
}
#endif
Expand Down
24 changes: 19 additions & 5 deletions DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
// limitations under the License.
//

import SwiftUI
import BrowserServicesKit
import Combine
import DDGSync
import SwiftUI

final class PreferencesSidebarModel: ObservableObject {

Expand All @@ -33,20 +34,27 @@ final class PreferencesSidebarModel: ObservableObject {
init(
loadSections: @escaping () -> [PreferencesSection],
tabSwitcherTabs: [Tab.TabContent],
privacyConfigurationManager: PrivacyConfigurationManaging
privacyConfigurationManager: PrivacyConfigurationManaging,
syncService: DDGSyncing
) {
self.loadSections = loadSections
self.tabSwitcherTabs = tabSwitcherTabs

resetTabSelectionIfNeeded()
refreshSections()

privacyConfigurationManager.updatesPublisher
let duckPlayerFeatureFlagDidChange = privacyConfigurationManager.updatesPublisher
.map { [weak privacyConfigurationManager] in
privacyConfigurationManager?.privacyConfig.isEnabled(featureKey: .duckPlayer) == true
}
.removeDuplicates()
.asVoid()

let syncFeatureFlagsDidChange = syncService.featureFlagsPublisher.map { $0.contains(.userInterface) }
.removeDuplicates()
.asVoid()

Publishers.Merge(duckPlayerFeatureFlagDidChange, syncFeatureFlagsDidChange)
.receive(on: DispatchQueue.main)
.sink { [weak self] in
self?.refreshSections()
Expand All @@ -62,6 +70,7 @@ final class PreferencesSidebarModel: ObservableObject {
convenience init(
tabSwitcherTabs: [Tab.TabContent] = Tab.TabContent.displayableTabTypes,
privacyConfigurationManager: PrivacyConfigurationManaging = ContentBlocking.shared.privacyConfigurationManager,
syncService: DDGSyncing,
includeDuckPlayer: Bool
) {
let loadSections = {
Expand All @@ -71,12 +80,17 @@ final class PreferencesSidebarModel: ObservableObject {
let includingVPN = false
#endif

return PreferencesSection.defaultSections(includingDuckPlayer: includeDuckPlayer, includingVPN: includingVPN)
return PreferencesSection.defaultSections(
includingDuckPlayer: includeDuckPlayer,
includingSync: syncService.featureFlags.contains(.userInterface),
includingVPN: includingVPN
)
}

self.init(loadSections: loadSections,
tabSwitcherTabs: tabSwitcherTabs,
privacyConfigurationManager: privacyConfigurationManager)
privacyConfigurationManager: privacyConfigurationManager,
syncService: syncService)
}

// MARK: - Setup
Expand Down
Loading

0 comments on commit 17d5a92

Please sign in to comment.