From d0f5dfd195700f43db2ca0bc937e521ed7220ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20=C5=9Apiewak?= Date: Tue, 24 Sep 2024 11:41:43 +0200 Subject: [PATCH 01/13] Trigger add-task-to-project when PR marked ready for review (#3376) Task/Issue URL: https://app.asana.com/0/414235014887631/1207931637636063/f Tech Design URL: CC: **Description**: Trigger add-task-to-project when PR marked ready for review. Counterpart of https://github.com/duckduckgo/macos-browser/pull/3273. **Steps to test this PR**: * Create a copy of this branch and open a draft PR. * Mark as ready for review and check if the "Add Task to App Board Project" action is successful. **Definition of Done (Internal Only)**: * [ ] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- .github/workflows/pr-task-url.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-task-url.yml b/.github/workflows/pr-task-url.yml index dad73e8220..7f130fe540 100644 --- a/.github/workflows/pr-task-url.yml +++ b/.github/workflows/pr-task-url.yml @@ -2,7 +2,7 @@ name: Asana PR Task URL on: pull_request: - types: [opened, edited, closed, synchronize, review_requested] + types: [opened, edited, closed, synchronize, review_requested, ready_for_review] jobs: @@ -14,6 +14,8 @@ jobs: runs-on: ubuntu-latest + if: ${{ !github.event.pull_request.draft }} + outputs: task_id: ${{ steps.get-task-id.outputs.task_id }} task_in_project: ${{ steps.check-board-membership.outputs.task_in_project }} @@ -47,7 +49,7 @@ jobs: - name: Add Task to the App Board Project id: add-task-to-project - if: ${{ github.event.action == 'opened' && steps.check-board-membership.outputs.task_in_project == '0' }} + if: ${{ (github.event.action == 'opened' || github.event.action == 'ready_for_review') && steps.check-board-membership.outputs.task_in_project == '0' }} env: ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }} ASANA_PROJECT_ID: ${{ vars.IOS_APP_BOARD_ASANA_PROJECT_ID }} From 2d9ec00309ad2e1a4adb19680f9faea76d63a6ef Mon Sep 17 00:00:00 2001 From: Christopher Brind Date: Tue, 24 Sep 2024 11:56:12 +0100 Subject: [PATCH 02/13] fix return user segmentation (#3387) Task/Issue URL: https://app.asana.com/0/414709148257752/1208380046395184/f Tech Design URL: CC: **Description**: Fix usage segmentation for return users. **Steps to test this PR**: 1. Reset the simulator `xcrun simctl erase all` 2. Add the following lines to the start of the `load` func of `StatisticsLoader`: statisticsStore.variant = "ru" statisticsStore.atb = "v446-1" statisticsStore.appRetentionAtb = "v447-1" statisticsStore.searchRetentionAtb = "v447-2" 4. Run the app and check for a pixel like this: Pixel fired m.retention.segments ["count_as_mau_n": "tttt", "new_set_atb": "v448-7", "count_as_wau": "true", "segments_today": "first_month,reactivated_wau,reinstaller", "activity_type": "app_use"] 5. Ensure that `reinstaller` and `"activity_type": "app_use"` are in the parameters as above 6. Get through onboarding and do a search 7. Check for a similar pixel ensuring that `reinstaller` and `"activity_type": "search"` are in the parameters **Definition of Done (Internal Only)**: * [x] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? --- Core/ReturnUserMeasurement.swift | 4 +++ Core/StatisticsLoader.swift | 7 +++--- DuckDuckGoTests/StatisticsLoaderTests.swift | 28 +++++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/Core/ReturnUserMeasurement.swift b/Core/ReturnUserMeasurement.swift index ba33d836ab..67b619677b 100644 --- a/Core/ReturnUserMeasurement.swift +++ b/Core/ReturnUserMeasurement.swift @@ -20,8 +20,12 @@ import Foundation import BrowserServicesKit +/// This is only intended to be used during the install (first run after downloading from the app store). protocol ReturnUserMeasurement { + /// Based on the value in the keychain, so if you use this after the install process it will return true. + /// If you really want to know if the user is "returning" then look at the variant in the `StatisticsStore` + /// which will be set to `ru`. var isReturningUser: Bool { get } func installCompletedWithATB(_ atb: Atb) func updateStoredATB(_ atb: Atb) diff --git a/Core/StatisticsLoader.swift b/Core/StatisticsLoader.swift index dd8a624685..38255c9097 100644 --- a/Core/StatisticsLoader.swift +++ b/Core/StatisticsLoader.swift @@ -155,9 +155,10 @@ public class StatisticsLoader { private func processUsageSegmentation(atb: Atb?, activityType: UsageActivityType) { guard let installAtbValue = statisticsStore.atb else { return } - let installAtb = Atb(version: installAtbValue, updateVersion: nil) - let actualAtb = atb ?? installAtb - self.usageSegmentation.processATB(actualAtb, withInstallAtb: installAtb, andActivityType: activityType) + let installAtb = Atb(version: installAtbValue + (statisticsStore.variant ?? ""), updateVersion: nil) + let usageAtb = atb ?? installAtb + + self.usageSegmentation.processATB(usageAtb, withInstallAtb: installAtb, andActivityType: activityType) } private func updateUsageSegmentationWithAtb(_ atb: Atb, activityType: UsageActivityType) { diff --git a/DuckDuckGoTests/StatisticsLoaderTests.swift b/DuckDuckGoTests/StatisticsLoaderTests.swift index 063425f707..64dca2b495 100644 --- a/DuckDuckGoTests/StatisticsLoaderTests.swift +++ b/DuckDuckGoTests/StatisticsLoaderTests.swift @@ -42,6 +42,34 @@ class StatisticsLoaderTests: XCTestCase { super.tearDown() } + func testWhenAppRefreshHappensButNotInstalledAndReturningUser_ThenRetentionSegmentationNotified() { + mockStatisticsStore.variant = "ru" + mockStatisticsStore.atb = "v101-1" + + loadSuccessfulExiStub() + + let testExpectation = expectation(description: "refresh complete") + testee.refreshAppRetentionAtb { + testExpectation.fulfill() + } + wait(for: [testExpectation], timeout: 5.0) + XCTAssertTrue(mockUsageSegmentation.atbs[0].installAtb.isReturningUser) + } + + func testWhenReturnUser_ThenSegmentationIncludesCorrectVariant() { + mockStatisticsStore.variant = "ru" + mockStatisticsStore.atb = "v101-1" + mockStatisticsStore.searchRetentionAtb = "v101-2" + loadSuccessfulAtbStub() + + let testExpectation = expectation(description: "refresh complete") + testee.refreshSearchRetentionAtb { + testExpectation.fulfill() + } + wait(for: [testExpectation], timeout: 5.0) + XCTAssertTrue(mockUsageSegmentation.atbs[0].installAtb.isReturningUser) + } + func testWhenSearchRefreshHappensButNotInstalled_ThenRetentionSegmentationNotified() { loadSuccessfulExiStub() From 8a8a8df816c754f40ae0169e0056fb0f3e80d83f Mon Sep 17 00:00:00 2001 From: Christopher Brind Date: Tue, 24 Sep 2024 12:12:04 +0100 Subject: [PATCH 03/13] Release 7.138.1-0 (#3388) --- Configuration/Version.xcconfig | 2 +- DuckDuckGo.xcodeproj/project.pbxproj | 56 +++++++++++++-------------- DuckDuckGo/Settings.bundle/Root.plist | 2 +- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/Configuration/Version.xcconfig b/Configuration/Version.xcconfig index c1d3187e3c..cff94a52b6 100644 --- a/Configuration/Version.xcconfig +++ b/Configuration/Version.xcconfig @@ -1 +1 @@ -MARKETING_VERSION = 7.138.0 +MARKETING_VERSION = 7.138.1 diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 2686c74017..18e8d0eb00 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -9100,7 +9100,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProvider.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -9137,7 +9137,7 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9227,7 +9227,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9254,7 +9254,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9403,7 +9403,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9428,7 +9428,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; INFOPLIST_FILE = DuckDuckGo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9497,7 +9497,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -9531,7 +9531,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9564,7 +9564,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9594,7 +9594,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9904,7 +9904,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9935,7 +9935,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9963,7 +9963,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9996,7 +9996,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -10026,7 +10026,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProviderAlpha.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -10059,11 +10059,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 3; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10296,7 +10296,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10323,7 +10323,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10355,7 +10355,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10392,7 +10392,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10427,7 +10427,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10462,11 +10462,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 3; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10639,11 +10639,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 3; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10672,10 +10672,10 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 0; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 3; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; diff --git a/DuckDuckGo/Settings.bundle/Root.plist b/DuckDuckGo/Settings.bundle/Root.plist index 4aebc33710..2a94a4826f 100644 --- a/DuckDuckGo/Settings.bundle/Root.plist +++ b/DuckDuckGo/Settings.bundle/Root.plist @@ -6,7 +6,7 @@ DefaultValue - 7.138.0 + 7.138.1 Key version Title From fd5804a39f5a22f48fa072f95ab74171def54806 Mon Sep 17 00:00:00 2001 From: Fernando Bunn Date: Tue, 24 Sep 2024 14:22:30 +0100 Subject: [PATCH 04/13] Add origin to /apps URL (#3378) Task/Issue URL: https://app.asana.com/0/414235014887631/1208314251851762/f **Description**: Add origin to /apps URL --- Core/AppURLs.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/AppURLs.swift b/Core/AppURLs.swift index e07d771f2a..56542c2066 100644 --- a/Core/AppURLs.swift +++ b/Core/AppURLs.swift @@ -35,7 +35,7 @@ public extension URL { static let emailProtectionSupportLink = URL(string: AppDeepLinkSchemes.quickLink.appending("\(ddg.host!)/email/settings/support"))! static let emailProtectionHelpPageLink = URL(string: AppDeepLinkSchemes.quickLink.appending("\(ddg.host!)/duckduckgo-help-pages/email-protection/what-is-duckduckgo-email-protection/"))! static let aboutLink = URL(string: AppDeepLinkSchemes.quickLink.appending("\(ddg.host!)/about"))! - static let apps = URL(string: AppDeepLinkSchemes.quickLink.appending("\(ddg.host!)/apps"))! + static let apps = URL(string: AppDeepLinkSchemes.quickLink.appending("\(ddg.host!)/apps?origin=funnel_app_ios"))! static let searchSettings = URL(string: AppDeepLinkSchemes.quickLink.appending("\(ddg.host!)/settings"))! static let autofillHelpPageLink = URL(string: AppDeepLinkSchemes.quickLink.appending("\(ddg.host!)/duckduckgo-help-pages/sync-and-backup/password-manager-security/"))! From d7731d466264e5dde2253e7807c0600518434c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20=C5=9Apiewak?= Date: Wed, 25 Sep 2024 12:42:34 +0200 Subject: [PATCH 05/13] Remove Favorites section header from NTP (#3381) Task/Issue URL: https://app.asana.com/0/0/1208244619690577/f Tech Design URL: CC: **Description**: Removes Favorites header when no favorites present. This allowed to removed whole EmptyStateView. Leftover function was incorporated into `FavoritesViewModel`, allowing to remove the generic type from `NewTabPageView`. **Steps to test this PR**: 1. Open NTP without having any favorites, make sure there's an add button and placeholders are visible. 2. Rotate to landscape. Verify whole row is filled up with placeholders. 3. Pixel should be fired when any placeholder is tapped. **Definition of Done (Internal Only)**: * [x] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? **Orientation Testing**: * [x] Portrait * [x] Landscape --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- Core/PixelEvent.swift | 2 - DuckDuckGo.xcodeproj/project.pbxproj | 44 +--- ...emView.swift => FavoriteAddItemView.swift} | 6 +- DuckDuckGo/FavoriteItem.swift | 5 +- ...wift => FavoritePlaceholderItemView.swift} | 6 +- DuckDuckGo/FavoritesDefaultViewModel.swift | 218 ------------------ DuckDuckGo/FavoritesEmptyStateView.swift | 78 ------- DuckDuckGo/FavoritesPreviewDataSource.swift | 2 +- DuckDuckGo/FavoritesSectionHeader.swift | 49 ---- DuckDuckGo/FavoritesView.swift | 11 +- DuckDuckGo/FavoritesViewModel.swift | 207 +++++++++++++++-- DuckDuckGo/NewTabPageView.swift | 32 +-- DuckDuckGo/NewTabPageViewController.swift | 8 +- DuckDuckGo/UserText.swift | 2 - DuckDuckGo/bg.lproj/Localizable.strings | 3 - DuckDuckGo/cs.lproj/Localizable.strings | 3 - DuckDuckGo/da.lproj/Localizable.strings | 3 - DuckDuckGo/de.lproj/Localizable.strings | 3 - DuckDuckGo/el.lproj/Localizable.strings | 3 - DuckDuckGo/en.lproj/Localizable.strings | 3 - DuckDuckGo/es.lproj/Localizable.strings | 3 - DuckDuckGo/et.lproj/Localizable.strings | 3 - DuckDuckGo/fi.lproj/Localizable.strings | 3 - DuckDuckGo/fr.lproj/Localizable.strings | 3 - DuckDuckGo/hr.lproj/Localizable.strings | 3 - DuckDuckGo/hu.lproj/Localizable.strings | 3 - DuckDuckGo/it.lproj/Localizable.strings | 3 - DuckDuckGo/lt.lproj/Localizable.strings | 3 - DuckDuckGo/lv.lproj/Localizable.strings | 3 - DuckDuckGo/nb.lproj/Localizable.strings | 3 - DuckDuckGo/nl.lproj/Localizable.strings | 3 - DuckDuckGo/pl.lproj/Localizable.strings | 3 - DuckDuckGo/pt.lproj/Localizable.strings | 3 - DuckDuckGo/ro.lproj/Localizable.strings | 3 - DuckDuckGo/ru.lproj/Localizable.strings | 3 - DuckDuckGo/sk.lproj/Localizable.strings | 3 - DuckDuckGo/sl.lproj/Localizable.strings | 3 - DuckDuckGo/sv.lproj/Localizable.strings | 3 - DuckDuckGo/tr.lproj/Localizable.strings | 3 - .../NewTabPageFavoritesModelTests.swift | 55 ++++- 40 files changed, 278 insertions(+), 522 deletions(-) rename DuckDuckGo/{AddFavoritePlaceholderItemView.swift => FavoriteAddItemView.swift} (89%) rename DuckDuckGo/{FavoriteEmptyStateItem.swift => FavoritePlaceholderItemView.swift} (89%) delete mode 100644 DuckDuckGo/FavoritesDefaultViewModel.swift delete mode 100644 DuckDuckGo/FavoritesEmptyStateView.swift delete mode 100644 DuckDuckGo/FavoritesSectionHeader.swift diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index d7ff07905b..5f450c2359 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -766,7 +766,6 @@ extension Pixel { case newTabPageMessageDismissed case newTabPageFavoritesPlaceholderTapped - case newTabPageFavoritesInfoTooltip case newTabPageFavoritesSeeMore case newTabPageFavoritesSeeLess @@ -1581,7 +1580,6 @@ extension Pixel.Event { case .newTabPageMessageDismissed: return "m_new_tab_page_message_dismissed" case .newTabPageFavoritesPlaceholderTapped: return "m_new_tab_page_favorites_placeholder_click" - case .newTabPageFavoritesInfoTooltip: return "m_new_tab_page_favorites_info_tooltip" case .newTabPageFavoritesSeeMore: return "m_new_tab_page_favorites_see_more" case .newTabPageFavoritesSeeLess: return "m_new_tab_page_favorites_see_less" diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 93737696aa..a45ae4e43d 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -326,10 +326,9 @@ 6FABAA692C6116FD003762EC /* NewTabPageShortcutsSettingsStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FABAA682C6116FD003762EC /* NewTabPageShortcutsSettingsStorageTests.swift */; }; 6FB1FE9E2C24D41D0075B68B /* NewTabPageSectionsDebugView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB1FE9D2C24D41D0075B68B /* NewTabPageSectionsDebugView.swift */; }; 6FB1FEA22C256ACD0075B68B /* NewTabPageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB1FEA12C256ACD0075B68B /* NewTabPageManager.swift */; }; - 6FB2A67A2C2C5BAE004D20C8 /* FavoriteEmptyStateItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB2A6792C2C5BAE004D20C8 /* FavoriteEmptyStateItem.swift */; }; - 6FB2A67C2C2D9DF0004D20C8 /* FavoritesEmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB2A67B2C2D9DF0004D20C8 /* FavoritesEmptyStateView.swift */; }; + 6FB2A67A2C2C5BAE004D20C8 /* FavoritePlaceholderItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB2A6792C2C5BAE004D20C8 /* FavoritePlaceholderItemView.swift */; }; 6FB2A67E2C2DAFB4004D20C8 /* NewTabPageGridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB2A67D2C2DAFB4004D20C8 /* NewTabPageGridView.swift */; }; - 6FB2A6802C2EA950004D20C8 /* FavoritesDefaultViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB2A67F2C2EA950004D20C8 /* FavoritesDefaultViewModel.swift */; }; + 6FB2A6802C2EA950004D20C8 /* FavoritesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB2A67F2C2EA950004D20C8 /* FavoritesViewModel.swift */; }; 6FBF0F8B2BD7C0A900136CF0 /* AllProtectedCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FBF0F8A2BD7C0A900136CF0 /* AllProtectedCell.swift */; }; 6FD0C41F2C5BF097000561C9 /* NewTabPageIntroMessageSetupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FD0C41E2C5BF097000561C9 /* NewTabPageIntroMessageSetupTests.swift */; }; 6FD0C4212C5BF774000561C9 /* NewTabPageViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FD0C4202C5BF774000561C9 /* NewTabPageViewModelTests.swift */; }; @@ -338,7 +337,6 @@ 6FD1BAE62B87A107000C475C /* AdAttributionFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FD1BAE32B87A107000C475C /* AdAttributionFetcher.swift */; }; 6FD3AEE32B8F4EEB0060FCCC /* AdAttributionPixelReporterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FD3AEE12B8DFBB80060FCCC /* AdAttributionPixelReporterTests.swift */; }; 6FD3F80F2C3EF4F000DA5797 /* DeviceOrientationEnvironmentValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FD3F80E2C3EF4F000DA5797 /* DeviceOrientationEnvironmentValue.swift */; }; - 6FD3F8112C3EFCDB00DA5797 /* FavoritesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FD3F8102C3EFCDB00DA5797 /* FavoritesViewModel.swift */; }; 6FD3F8132C3EFDA200DA5797 /* FavoritesPreviewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FD3F8122C3EFDA200DA5797 /* FavoritesPreviewDataSource.swift */; }; 6FD3F8192C41252900DA5797 /* NewTabPageControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FD3F8182C41252900DA5797 /* NewTabPageControllerDelegate.swift */; }; 6FD8E51E2C5B84DE00345670 /* NewTabPageIntroMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FD8E51D2C5B84DE00345670 /* NewTabPageIntroMessageView.swift */; }; @@ -347,8 +345,7 @@ 6FDA1FB32B59584400AC962A /* AddressDisplayHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDA1FB22B59584400AC962A /* AddressDisplayHelper.swift */; }; 6FDC64012C92F4A300DB71B3 /* NewTabPageIntroDataStoring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDC64002C92F4A300DB71B3 /* NewTabPageIntroDataStoring.swift */; }; 6FDC64032C92F4D600DB71B3 /* NewTabPageSettingsPersistentStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDC64022C92F4D600DB71B3 /* NewTabPageSettingsPersistentStore.swift */; }; - 6FDC64052C98515E00DB71B3 /* AddFavoritePlaceholderItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDC64042C98515E00DB71B3 /* AddFavoritePlaceholderItemView.swift */; }; - 6FE018402C25CB3F001F680D /* FavoritesSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FE0183F2C25CB3F001F680D /* FavoritesSectionHeader.swift */; }; + 6FDC64052C98515E00DB71B3 /* FavoriteAddItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FDC64042C98515E00DB71B3 /* FavoriteAddItemView.swift */; }; 6FE095D82BD90AFB00490FF8 /* UniversalOmniBarState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FE095D72BD90AFB00490FF8 /* UniversalOmniBarState.swift */; }; 6FE127382C20492500EB5724 /* NewTabPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FE127372C20492500EB5724 /* NewTabPage.swift */; }; 6FE1273A2C204BD000EB5724 /* NewTabPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FE127392C204BD000EB5724 /* NewTabPageView.swift */; }; @@ -1606,10 +1603,9 @@ 6FB030C7234331B400A10DB9 /* Configuration.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Configuration.xcconfig; path = Configuration/Configuration.xcconfig; sourceTree = ""; }; 6FB1FE9D2C24D41D0075B68B /* NewTabPageSectionsDebugView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageSectionsDebugView.swift; sourceTree = ""; }; 6FB1FEA12C256ACD0075B68B /* NewTabPageManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageManager.swift; sourceTree = ""; }; - 6FB2A6792C2C5BAE004D20C8 /* FavoriteEmptyStateItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteEmptyStateItem.swift; sourceTree = ""; }; - 6FB2A67B2C2D9DF0004D20C8 /* FavoritesEmptyStateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesEmptyStateView.swift; sourceTree = ""; }; + 6FB2A6792C2C5BAE004D20C8 /* FavoritePlaceholderItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritePlaceholderItemView.swift; sourceTree = ""; }; 6FB2A67D2C2DAFB4004D20C8 /* NewTabPageGridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageGridView.swift; sourceTree = ""; }; - 6FB2A67F2C2EA950004D20C8 /* FavoritesDefaultViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesDefaultViewModel.swift; sourceTree = ""; }; + 6FB2A67F2C2EA950004D20C8 /* FavoritesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesViewModel.swift; sourceTree = ""; }; 6FBF0F8A2BD7C0A900136CF0 /* AllProtectedCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllProtectedCell.swift; sourceTree = ""; }; 6FD0C41E2C5BF097000561C9 /* NewTabPageIntroMessageSetupTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageIntroMessageSetupTests.swift; sourceTree = ""; }; 6FD0C4202C5BF774000561C9 /* NewTabPageViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageViewModelTests.swift; sourceTree = ""; }; @@ -1618,7 +1614,6 @@ 6FD1BAE32B87A107000C475C /* AdAttributionFetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AdAttributionFetcher.swift; path = AdAttribution/AdAttributionFetcher.swift; sourceTree = ""; }; 6FD3AEE12B8DFBB80060FCCC /* AdAttributionPixelReporterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdAttributionPixelReporterTests.swift; sourceTree = ""; }; 6FD3F80E2C3EF4F000DA5797 /* DeviceOrientationEnvironmentValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceOrientationEnvironmentValue.swift; sourceTree = ""; }; - 6FD3F8102C3EFCDB00DA5797 /* FavoritesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesViewModel.swift; sourceTree = ""; }; 6FD3F8122C3EFDA200DA5797 /* FavoritesPreviewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesPreviewDataSource.swift; sourceTree = ""; }; 6FD3F8182C41252900DA5797 /* NewTabPageControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageControllerDelegate.swift; sourceTree = ""; }; 6FD8E51D2C5B84DE00345670 /* NewTabPageIntroMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageIntroMessageView.swift; sourceTree = ""; }; @@ -1627,8 +1622,7 @@ 6FDA1FB22B59584400AC962A /* AddressDisplayHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressDisplayHelper.swift; sourceTree = ""; }; 6FDC64002C92F4A300DB71B3 /* NewTabPageIntroDataStoring.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageIntroDataStoring.swift; sourceTree = ""; }; 6FDC64022C92F4D600DB71B3 /* NewTabPageSettingsPersistentStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageSettingsPersistentStore.swift; sourceTree = ""; }; - 6FDC64042C98515E00DB71B3 /* AddFavoritePlaceholderItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFavoritePlaceholderItemView.swift; sourceTree = ""; }; - 6FE0183F2C25CB3F001F680D /* FavoritesSectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesSectionHeader.swift; sourceTree = ""; }; + 6FDC64042C98515E00DB71B3 /* FavoriteAddItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteAddItemView.swift; sourceTree = ""; }; 6FE095D72BD90AFB00490FF8 /* UniversalOmniBarState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalOmniBarState.swift; sourceTree = ""; }; 6FE127372C20492500EB5724 /* NewTabPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPage.swift; sourceTree = ""; }; 6FE127392C204BD000EB5724 /* NewTabPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageView.swift; sourceTree = ""; }; @@ -3893,10 +3887,9 @@ 6FA3438D2C3D3BB800470677 /* Model */ = { isa = PBXGroup; children = ( - 6FB2A67F2C2EA950004D20C8 /* FavoritesDefaultViewModel.swift */, + 6FB2A67F2C2EA950004D20C8 /* FavoritesViewModel.swift */, 6F64AA522C47E92600CF4489 /* FavoritesFaviconLoader.swift */, 6FD3F8122C3EFDA200DA5797 /* FavoritesPreviewDataSource.swift */, - 6FD3F8102C3EFCDB00DA5797 /* FavoritesViewModel.swift */, 6FA3438E2C3D3BC300470677 /* Favorite.swift */, 6FEC0B842C999352006B4F6E /* FavoriteItem.swift */, 6FEC0B872C999961006B4F6E /* FavoriteDataSource.swift */, @@ -3909,7 +3902,8 @@ children = ( 6FE127422C204DF700EB5724 /* FavoriteItemView.swift */, 6FA343912C3D3C3B00470677 /* FavoriteIconView.swift */, - 6FDC64042C98515E00DB71B3 /* AddFavoritePlaceholderItemView.swift */, + 6FB2A6792C2C5BAE004D20C8 /* FavoritePlaceholderItemView.swift */, + 6FDC64042C98515E00DB71B3 /* FavoriteAddItemView.swift */, ); name = Item; sourceTree = ""; @@ -3922,16 +3916,6 @@ name = NewTabPageSectionsDebugView; sourceTree = ""; }; - 6FB2A6782C2C5B9E004D20C8 /* EmptyState */ = { - isa = PBXGroup; - children = ( - 6FE0183F2C25CB3F001F680D /* FavoritesSectionHeader.swift */, - 6FB2A6792C2C5BAE004D20C8 /* FavoriteEmptyStateItem.swift */, - 6FB2A67B2C2D9DF0004D20C8 /* FavoritesEmptyStateView.swift */, - ); - name = EmptyState; - sourceTree = ""; - }; 6FD1BAE02B87A0E8000C475C /* AdAttribution */ = { isa = PBXGroup; children = ( @@ -3989,7 +3973,6 @@ 6F691CC82C4979DD002E9553 /* Tooltip */, 6FA343902C3D3C2500470677 /* Item */, 6FA3438D2C3D3BB800470677 /* Model */, - 6FB2A6782C2C5B9E004D20C8 /* EmptyState */, 6FE1273C2C204C2500EB5724 /* FavoritesView.swift */, ); name = Favorites; @@ -7344,7 +7327,6 @@ 4BBBBA922B03291700D965DA /* VPNWaitlistUserText.swift in Sources */, 6F0FEF6D2C52639E0090CDE4 /* ReorderableForEach.swift in Sources */, F4E1936625AF722F001D2666 /* HighlightCutOutView.swift in Sources */, - 6FB2A67C2C2D9DF0004D20C8 /* FavoritesEmptyStateView.swift in Sources */, 1E162605296840D80004127F /* Triangle.swift in Sources */, 6FDC64012C92F4A300DB71B3 /* NewTabPageIntroDataStoring.swift in Sources */, B609D5522862EAFF0088CAC2 /* InlineWKDownloadDelegate.swift in Sources */, @@ -7424,7 +7406,7 @@ 6F9FFE302C57B34800A238BE /* NewTabPageSectionsSettingsModel.swift in Sources */, 986B16C425E92DF0007D23E8 /* BrowsingMenuViewController.swift in Sources */, 988AC355257E47C100793C64 /* RequeryLogic.swift in Sources */, - 6FB2A67A2C2C5BAE004D20C8 /* FavoriteEmptyStateItem.swift in Sources */, + 6FB2A67A2C2C5BAE004D20C8 /* FavoritePlaceholderItemView.swift in Sources */, 6FBF0F8B2BD7C0A900136CF0 /* AllProtectedCell.swift in Sources */, 9F4CC5242C4A4F0D006A96EB /* SwiftUITestUtilities.swift in Sources */, 6FDC64032C92F4D600DB71B3 /* NewTabPageSettingsPersistentStore.swift in Sources */, @@ -7576,7 +7558,6 @@ 31B2F11F287846320040427A /* NoMicPermissionAlert.swift in Sources */, 310C4B45281B5A9A00BA79A9 /* AutofillLoginDetailsView.swift in Sources */, 6F9FFE2D2C57AE8F00A238BE /* NewTabPageShortcutsSettingsModel.swift in Sources */, - 6FD3F8112C3EFCDB00DA5797 /* FavoritesViewModel.swift in Sources */, D62EC3C22C248AF800FC9D04 /* DuckPlayerNavigationHandling.swift in Sources */, 9FB027142C252E0C009EA190 /* OnboardingView+BrowsersComparisonContent.swift in Sources */, D664C7B62B289AA200CBFA76 /* SubscriptionFlowViewModel.swift in Sources */, @@ -7607,7 +7588,7 @@ D6E83C662B23936F006C8AFB /* SettingsDebugView.swift in Sources */, C1641EB12BC2F52B0012607A /* ImportPasswordsView.swift in Sources */, CBFCB30E2B2CD47800253E9E /* ConfigurationURLDebugViewController.swift in Sources */, - 6FDC64052C98515E00DB71B3 /* AddFavoritePlaceholderItemView.swift in Sources */, + 6FDC64052C98515E00DB71B3 /* FavoriteAddItemView.swift in Sources */, 982686AD2600C0850011A8D6 /* ActionMessageView.swift in Sources */, F446B9B5251150AC00324016 /* HomeMessageViewSectionRenderer.swift in Sources */, D6E0C1852B7A2B9400D5E1E9 /* DesktopDownloadPlatformConstants.swift in Sources */, @@ -7697,7 +7678,7 @@ 9FDEC7BC2C91204900C7A692 /* AppIconPickerViewModel.swift in Sources */, F1FDC9352BF51E41006B1435 /* VPNSettings+Environment.swift in Sources */, 850ABD012AC3961100A733DF /* MainViewController+Segues.swift in Sources */, - 6FB2A6802C2EA950004D20C8 /* FavoritesDefaultViewModel.swift in Sources */, + 6FB2A6802C2EA950004D20C8 /* FavoritesViewModel.swift in Sources */, 9817C9C321EF594700884F65 /* AutoClear.swift in Sources */, 9FE05CEE2C36424E00D9046B /* OnboardingPixelReporter.swift in Sources */, 9821234E2B6D0A6300F08C57 /* UserAuthenticator.swift in Sources */, @@ -7859,7 +7840,6 @@ D6E0C1892B7A2E0D00D5E1E9 /* DesktopDownloadViewModel.swift in Sources */, 8524CC9A246DA81700E59D45 /* FullscreenDaxDialogViewController.swift in Sources */, 9F23B8012C2BC94400950875 /* OnboardingBackground.swift in Sources */, - 6FE018402C25CB3F001F680D /* FavoritesSectionHeader.swift in Sources */, 9FE08BD32C2A5B88001D5EBC /* OnboardingTextStyles.swift in Sources */, F17669D71E43401C003D3222 /* MainViewController.swift in Sources */, 6FE127462C2054A900EB5724 /* NewTabPageViewController.swift in Sources */, diff --git a/DuckDuckGo/AddFavoritePlaceholderItemView.swift b/DuckDuckGo/FavoriteAddItemView.swift similarity index 89% rename from DuckDuckGo/AddFavoritePlaceholderItemView.swift rename to DuckDuckGo/FavoriteAddItemView.swift index 09b11802c0..85d9b92c1d 100644 --- a/DuckDuckGo/AddFavoritePlaceholderItemView.swift +++ b/DuckDuckGo/FavoriteAddItemView.swift @@ -1,5 +1,5 @@ // -// AddFavoritePlaceholderItemView.swift +// FavoriteAddItemView.swift // DuckDuckGo // // Copyright © 2024 DuckDuckGo. All rights reserved. @@ -20,7 +20,7 @@ import SwiftUI import DesignResourcesKit -struct AddFavoritePlaceholderItemView: View { +struct FavoriteAddItemView: View { var body: some View { RoundedRectangle(cornerRadius: 8, style: .continuous) .fill(.clear) @@ -33,6 +33,6 @@ struct AddFavoritePlaceholderItemView: View { } #Preview { - AddFavoritePlaceholderItemView() + FavoriteAddItemView() .frame(width: 100) } diff --git a/DuckDuckGo/FavoriteItem.swift b/DuckDuckGo/FavoriteItem.swift index 9e6c433d53..0edefc1147 100644 --- a/DuckDuckGo/FavoriteItem.swift +++ b/DuckDuckGo/FavoriteItem.swift @@ -23,6 +23,7 @@ import UniformTypeIdentifiers enum FavoriteItem { case favorite(Favorite) case addFavorite + case placeholder(_ id: String) } extension FavoriteItem: Identifiable { @@ -32,6 +33,8 @@ extension FavoriteItem: Identifiable { return favorite.id case .addFavorite: return "addFavorite" + case .placeholder(let id): + return id } } } @@ -43,7 +46,7 @@ extension FavoriteItem: Reorderable { let itemProvider = NSItemProvider(object: (favorite.urlObject?.absoluteString ?? "") as NSString) let metadata = MoveMetadata(itemProvider: itemProvider, type: .plainText) return .movable(metadata) - case .addFavorite: + case .addFavorite, .placeholder: return .stationary } } diff --git a/DuckDuckGo/FavoriteEmptyStateItem.swift b/DuckDuckGo/FavoritePlaceholderItemView.swift similarity index 89% rename from DuckDuckGo/FavoriteEmptyStateItem.swift rename to DuckDuckGo/FavoritePlaceholderItemView.swift index e5b69afd8f..d009558b07 100644 --- a/DuckDuckGo/FavoriteEmptyStateItem.swift +++ b/DuckDuckGo/FavoritePlaceholderItemView.swift @@ -1,5 +1,5 @@ // -// FavoriteEmptyStateItem.swift +// FavoritePlaceholderItemView.swift // DuckDuckGo // // Copyright © 2024 DuckDuckGo. All rights reserved. @@ -19,7 +19,7 @@ import SwiftUI -struct FavoriteEmptyStateItem: View { +struct FavoritePlaceholderItemView: View { var body: some View { RoundedRectangle(cornerRadius: 8, style: .continuous) .stroke(Color(designSystemColor: .lines), @@ -29,5 +29,5 @@ struct FavoriteEmptyStateItem: View { } #Preview { - FavoriteEmptyStateItem() + FavoritePlaceholderItemView() } diff --git a/DuckDuckGo/FavoritesDefaultViewModel.swift b/DuckDuckGo/FavoritesDefaultViewModel.swift deleted file mode 100644 index c9088dc5e7..0000000000 --- a/DuckDuckGo/FavoritesDefaultViewModel.swift +++ /dev/null @@ -1,218 +0,0 @@ -// -// FavoritesDefaultViewModel.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 -import Bookmarks -import Combine -import SwiftUI -import Core -import WidgetKit - -protocol NewTabPageFavoriteDataSource { - var externalUpdates: AnyPublisher { get } - var favorites: [Favorite] { get } - - func moveFavorite(_ favorite: Favorite, - fromIndex: Int, - toIndex: Int) - - func bookmarkEntity(for favorite: Favorite) -> BookmarkEntity? - func favorite(at index: Int) throws -> Favorite? - func removeFavorite(_ favorite: Favorite) -} - -class FavoritesDefaultViewModel: FavoritesViewModel, FavoritesEmptyStateModel { - - @Published private(set) var allFavorites: [FavoriteItem] = [] - @Published private(set) var isCollapsed: Bool = true - @Published private(set) var isShowingTooltip: Bool = false - - private(set) var faviconLoader: FavoritesFaviconLoading? - - private var cancellables = Set() - - private let favoriteDataSource: NewTabPageFavoriteDataSource - private let pixelFiring: PixelFiring.Type - private let dailyPixelFiring: DailyPixelFiring.Type - - var isEmpty: Bool { - allFavorites.filter(\.isFavorite).isEmpty - } - - init(favoriteDataSource: NewTabPageFavoriteDataSource, - faviconLoader: FavoritesFaviconLoading, - pixelFiring: PixelFiring.Type = Pixel.self, - dailyPixelFiring: DailyPixelFiring.Type = DailyPixel.self) { - self.favoriteDataSource = favoriteDataSource - self.pixelFiring = pixelFiring - self.dailyPixelFiring = dailyPixelFiring - self.faviconLoader = MissingFaviconWrapper(loader: faviconLoader, onFaviconMissing: { [weak self] in - guard let self else { return } - - await MainActor.run { - self.faviconMissing() - } - }) - - - favoriteDataSource.externalUpdates.sink { [weak self] _ in - self?.updateData() - }.store(in: &cancellables) - - updateData() - } - - func toggleCollapse() { - isCollapsed.toggle() - - if isCollapsed { - pixelFiring.fire(.newTabPageFavoritesSeeLess, withAdditionalParameters: [:]) - } else { - pixelFiring.fire(.newTabPageFavoritesSeeMore, withAdditionalParameters: [:]) - } - } - - func prefixedFavorites(for columnsCount: Int) -> FavoritesSlice { - let maxCollapsedItemsCount = columnsCount * 2 - let favorites = isCollapsed ? Array(allFavorites.prefix(maxCollapsedItemsCount)) : allFavorites - let isCollapsible = allFavorites.count > maxCollapsedItemsCount - - return .init(items: favorites, isCollapsible: isCollapsible) - } - - // MARK: - External actions - - var onFaviconMissing: () -> Void = {} - func faviconMissing() { - onFaviconMissing() - } - - var onFavoriteURLSelected: ((URL) -> Void)? - func favoriteSelected(_ favorite: Favorite) { - guard let url = favorite.urlObject else { return } - - pixelFiring.fire(.favoriteLaunchedNTP, withAdditionalParameters: [:]) - dailyPixelFiring.fireDaily(.favoriteLaunchedNTPDaily) - Favicons.shared.loadFavicon(forDomain: url.host, intoCache: .fireproof, fromCache: .tabs) - - onFavoriteURLSelected?(url) - } - - var onFavoriteDeleted: ((BookmarkEntity) -> Void)? - func deleteFavorite(_ favorite: Favorite) { - guard let entity = favoriteDataSource.bookmarkEntity(for: favorite) else { return } - - pixelFiring.fire(.homeScreenDeleteFavorite, withAdditionalParameters: [:]) - - favoriteDataSource.removeFavorite(favorite) - - WidgetCenter.shared.reloadAllTimelines() - updateData() - - onFavoriteDeleted?(entity) - } - - var onFavoriteEdit: ((BookmarkEntity) -> Void)? - func editFavorite(_ favorite: Favorite) { - guard let entity = favoriteDataSource.bookmarkEntity(for: favorite) else { return } - - pixelFiring.fire(.homeScreenEditFavorite, withAdditionalParameters: [:]) - - onFavoriteEdit?(entity) - } - - func moveFavorites(from indexSet: IndexSet, to index: Int) { - guard indexSet.count == 1, - let fromIndex = indexSet.first else { return } - - let favoriteItem = allFavorites[fromIndex] - guard case let .favorite(favorite) = favoriteItem else { return } - - favoriteDataSource.moveFavorite(favorite, fromIndex: fromIndex, toIndex: index) - allFavorites.move(fromOffsets: IndexSet(integer: fromIndex), toOffset: index) - } - - // MARK: - Empty state model - - func placeholderTapped() { - pixelFiring.fire(.newTabPageFavoritesPlaceholderTapped, withAdditionalParameters: [:]) - } - - func toggleTooltip() { - isShowingTooltip.toggle() - if isShowingTooltip { - pixelFiring.fire(.newTabPageFavoritesInfoTooltip, withAdditionalParameters: [:]) - } - } - - // MARK: - - - private func updateData() { - var allFavorites = favoriteDataSource.favorites.map { - FavoriteItem.favorite($0) - } - allFavorites.append(.addFavorite) - - self.allFavorites = allFavorites - } -} - -enum FavoriteMappingError: Error { - case missingUUID -} - -private final class MissingFaviconWrapper: FavoritesFaviconLoading { - let loader: FavoritesFaviconLoading - - private(set) var onFaviconMissing: (() async -> Void) - - init(loader: FavoritesFaviconLoading, onFaviconMissing: @escaping (() async -> Void)) { - self.onFaviconMissing = onFaviconMissing - self.loader = loader - } - - func loadFavicon(for favorite: Favorite, size: CGFloat) async -> Favicon? { - let favicon = await loader.loadFavicon(for: favorite, size: size) - - if favicon == nil { - await onFaviconMissing() - } - - return favicon - } - - func fakeFavicon(for favorite: Favorite, size: CGFloat) -> Favicon { - loader.fakeFavicon(for: favorite, size: size) - } - - func existingFavicon(for favorite: Favorite, size: CGFloat) -> Favicon? { - loader.existingFavicon(for: favorite, size: size) - } -} - -private extension FavoriteItem { - var isFavorite: Bool { - switch self { - case .favorite: - return true - case .addFavorite: - return false - } - } -} diff --git a/DuckDuckGo/FavoritesEmptyStateView.swift b/DuckDuckGo/FavoritesEmptyStateView.swift deleted file mode 100644 index 8c81ce6765..0000000000 --- a/DuckDuckGo/FavoritesEmptyStateView.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// FavoritesEmptyStateView.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 SwiftUI -import DuckUI - -struct FavoritesEmptyStateView: View { - @ObservedObject var model: Model - @Binding var isAddingFavorite: Bool - - let geometry: GeometryProxy? - - var body: some View { - ZStack(alignment: .topTrailing) { - VStack(spacing: 16) { - FavoritesSectionHeader(model: model) - - NewTabPageGridView(geometry: geometry) { placeholdersCount in - Button(action: { - isAddingFavorite = true - }, label: { - AddFavoritePlaceholderItemView() - }) - .buttonStyle(SecondaryFillButtonStyle(isFreeform: true)) - .frame(width: NewTabPageGrid.Item.edgeSize) - - let placeholders = Array(0..: View { .frame(width: NewTabPageGrid.Item.edgeSize) .previewShape() .transition(.opacity) - case .addFavorite: + case .addFavorite, .placeholder: EmptyView() } } @@ -110,10 +110,17 @@ struct FavoritesView: View { Button(action: { isAddingFavorite = true }, label: { - AddFavoritePlaceholderItemView() + FavoriteAddItemView() }) .buttonStyle(SecondaryFillButtonStyle(isFreeform: true)) .frame(width: NewTabPageGrid.Item.edgeSize) + case .placeholder: + FavoritePlaceholderItemView() + .frame(width: NewTabPageGrid.Item.edgeSize, height: NewTabPageGrid.Item.edgeSize) + .contentShape(.rect) + .onTapGesture { + model.placeholderTapped() + } } } } diff --git a/DuckDuckGo/FavoritesViewModel.swift b/DuckDuckGo/FavoritesViewModel.swift index 624186edb6..781d77a044 100644 --- a/DuckDuckGo/FavoritesViewModel.swift +++ b/DuckDuckGo/FavoritesViewModel.swift @@ -18,37 +18,204 @@ // import Foundation +import Bookmarks +import Combine +import SwiftUI +import Core +import WidgetKit -protocol FavoritesViewModel: AnyObject, ObservableObject { - var allFavorites: [FavoriteItem] { get } - var faviconLoader: FavoritesFaviconLoading? { get } +protocol NewTabPageFavoriteDataSource { + var externalUpdates: AnyPublisher { get } + var favorites: [Favorite] { get } - var isEmpty: Bool { get } - var isCollapsed: Bool { get } + func moveFavorite(_ favorite: Favorite, + fromIndex: Int, + toIndex: Int) - func prefixedFavorites(for columnsCount: Int) -> FavoritesSlice + func bookmarkEntity(for favorite: Favorite) -> BookmarkEntity? + func favorite(at index: Int) throws -> Favorite? + func removeFavorite(_ favorite: Favorite) +} + +struct FavoritesSlice { + let items: [FavoriteItem] + let isCollapsible: Bool +} + +class FavoritesViewModel: ObservableObject { + + @Published private(set) var allFavorites: [FavoriteItem] = [] + @Published private(set) var isCollapsed: Bool = true + + private(set) var faviconLoader: FavoritesFaviconLoading? + + private var cancellables = Set() + + private let favoriteDataSource: NewTabPageFavoriteDataSource + private let pixelFiring: PixelFiring.Type + private let dailyPixelFiring: DailyPixelFiring.Type + + var isEmpty: Bool { + allFavorites.filter(\.isFavorite).isEmpty + } + + init(favoriteDataSource: NewTabPageFavoriteDataSource, + faviconLoader: FavoritesFaviconLoading, + pixelFiring: PixelFiring.Type = Pixel.self, + dailyPixelFiring: DailyPixelFiring.Type = DailyPixel.self) { + self.favoriteDataSource = favoriteDataSource + self.pixelFiring = pixelFiring + self.dailyPixelFiring = dailyPixelFiring + self.faviconLoader = MissingFaviconWrapper(loader: faviconLoader, onFaviconMissing: { [weak self] in + guard let self else { return } + + await MainActor.run { + self.faviconMissing() + } + }) + + + favoriteDataSource.externalUpdates.sink { [weak self] _ in + self?.updateData() + }.store(in: &cancellables) + + updateData() + } + + func toggleCollapse() { + isCollapsed.toggle() + + if isCollapsed { + pixelFiring.fire(.newTabPageFavoritesSeeLess, withAdditionalParameters: [:]) + } else { + pixelFiring.fire(.newTabPageFavoritesSeeMore, withAdditionalParameters: [:]) + } + } + + func prefixedFavorites(for columnsCount: Int) -> FavoritesSlice { + let hasFavorites = allFavorites.contains(where: \.isFavorite) + let maxCollapsedItemsCount = hasFavorites ? columnsCount * 2 : columnsCount + let isCollapsible = allFavorites.count > maxCollapsedItemsCount + + var favorites = isCollapsed ? Array(allFavorites.prefix(maxCollapsedItemsCount)) : allFavorites + + if !hasFavorites { + for _ in favorites.count ..< maxCollapsedItemsCount { + favorites.append(.placeholder(UUID().uuidString)) + } + } + + return .init(items: favorites, isCollapsible: isCollapsible) + } + + // MARK: - External actions + + var onFaviconMissing: () -> Void = {} + func faviconMissing() { + onFaviconMissing() + } - func faviconMissing() + var onFavoriteURLSelected: ((URL) -> Void)? + func favoriteSelected(_ favorite: Favorite) { + guard let url = favorite.urlObject else { return } - // MARK: - Interactions + pixelFiring.fire(.favoriteLaunchedNTP, withAdditionalParameters: [:]) + dailyPixelFiring.fireDaily(.favoriteLaunchedNTPDaily) + Favicons.shared.loadFavicon(forDomain: url.host, intoCache: .fireproof, fromCache: .tabs) - func toggleCollapse() + onFavoriteURLSelected?(url) + } - func favoriteSelected(_ favorite: Favorite) - func editFavorite(_ favorite: Favorite) - func deleteFavorite(_ favorite: Favorite) - func moveFavorites(from indexSet: IndexSet, to index: Int) + var onFavoriteDeleted: ((BookmarkEntity) -> Void)? + func deleteFavorite(_ favorite: Favorite) { + guard let entity = favoriteDataSource.bookmarkEntity(for: favorite) else { return } + + pixelFiring.fire(.homeScreenDeleteFavorite, withAdditionalParameters: [:]) + + favoriteDataSource.removeFavorite(favorite) + + WidgetCenter.shared.reloadAllTimelines() + updateData() + + onFavoriteDeleted?(entity) + } + + var onFavoriteEdit: ((BookmarkEntity) -> Void)? + func editFavorite(_ favorite: Favorite) { + guard let entity = favoriteDataSource.bookmarkEntity(for: favorite) else { return } + + pixelFiring.fire(.homeScreenEditFavorite, withAdditionalParameters: [:]) + + onFavoriteEdit?(entity) + } + + func moveFavorites(from indexSet: IndexSet, to index: Int) { + guard indexSet.count == 1, + let fromIndex = indexSet.first else { return } + + let favoriteItem = allFavorites[fromIndex] + guard case let .favorite(favorite) = favoriteItem else { return } + + favoriteDataSource.moveFavorite(favorite, fromIndex: fromIndex, toIndex: index) + allFavorites.move(fromOffsets: IndexSet(integer: fromIndex), toOffset: index) + } + + func placeholderTapped() { + pixelFiring.fire(.newTabPageFavoritesPlaceholderTapped, withAdditionalParameters: [:]) + } + + // MARK: - + + private func updateData() { + var allFavorites = favoriteDataSource.favorites.map { + FavoriteItem.favorite($0) + } + allFavorites.append(.addFavorite) + + self.allFavorites = allFavorites + } +} + +enum FavoriteMappingError: Error { + case missingUUID } -protocol FavoritesEmptyStateModel: AnyObject, ObservableObject { +private final class MissingFaviconWrapper: FavoritesFaviconLoading { + let loader: FavoritesFaviconLoading + + private(set) var onFaviconMissing: (() async -> Void) + + init(loader: FavoritesFaviconLoading, onFaviconMissing: @escaping (() async -> Void)) { + self.onFaviconMissing = onFaviconMissing + self.loader = loader + } - var isShowingTooltip: Bool { get } + func loadFavicon(for favorite: Favorite, size: CGFloat) async -> Favicon? { + let favicon = await loader.loadFavicon(for: favorite, size: size) - func placeholderTapped() - func toggleTooltip() + if favicon == nil { + await onFaviconMissing() + } + + return favicon + } + + func fakeFavicon(for favorite: Favorite, size: CGFloat) -> Favicon { + loader.fakeFavicon(for: favorite, size: size) + } + + func existingFavicon(for favorite: Favorite, size: CGFloat) -> Favicon? { + loader.existingFavicon(for: favorite, size: size) + } } -struct FavoritesSlice { - let items: [FavoriteItem] - let isCollapsible: Bool +private extension FavoriteItem { + var isFavorite: Bool { + switch self { + case .favorite: + return true + case .addFavorite, .placeholder: + return false + } + } } diff --git a/DuckDuckGo/NewTabPageView.swift b/DuckDuckGo/NewTabPageView.swift index 14d97ce3e2..aaed282ca5 100644 --- a/DuckDuckGo/NewTabPageView.swift +++ b/DuckDuckGo/NewTabPageView.swift @@ -21,12 +21,12 @@ import SwiftUI import DuckUI import RemoteMessaging -struct NewTabPageView: View { +struct NewTabPageView: View { @Environment(\.horizontalSizeClass) var horizontalSizeClass @ObservedObject private var viewModel: NewTabPageViewModel @ObservedObject private var messagesModel: NewTabPageMessagesModel - @ObservedObject private var favoritesModel: FavoritesModelType + @ObservedObject private var favoritesViewModel: FavoritesViewModel @ObservedObject private var shortcutsModel: ShortcutsModel @ObservedObject private var shortcutsSettingsModel: NewTabPageShortcutsSettingsModel @ObservedObject private var sectionsSettingsModel: NewTabPageSectionsSettingsModel @@ -36,13 +36,13 @@ struct NewTabPageView some View { - Group { - if favoritesModel.isEmpty { - FavoritesEmptyStateView(model: favoritesModel, - isAddingFavorite: $isAddingFavorite, - geometry: proxy) - .padding(.top, Metrics.nonGridSectionTopPadding) - } else { - FavoritesView(model: favoritesModel, + FavoritesView(model: favoritesViewModel, isAddingFavorite: $isAddingFavorite, geometry: proxy) - } - } } @ViewBuilder @@ -274,7 +260,7 @@ private struct CustomizeButtonPrefKey: PreferenceKey { homeMessages: [] ) ), - favoritesModel: FavoritesPreviewModel(), + favoritesViewModel: FavoritesPreviewModel(), shortcutsModel: ShortcutsModel(), shortcutsSettingsModel: NewTabPageShortcutsSettingsModel(), sectionsSettingsModel: NewTabPageSectionsSettingsModel() @@ -299,7 +285,7 @@ private struct CustomizeButtonPrefKey: PreferenceKey { ] ) ), - favoritesModel: FavoritesPreviewModel(), + favoritesViewModel: FavoritesPreviewModel(), shortcutsModel: ShortcutsModel(), shortcutsSettingsModel: NewTabPageShortcutsSettingsModel(), sectionsSettingsModel: NewTabPageSectionsSettingsModel() @@ -314,7 +300,7 @@ private struct CustomizeButtonPrefKey: PreferenceKey { homeMessages: [] ) ), - favoritesModel: FavoritesPreviewModel(favorites: []), + favoritesViewModel: FavoritesPreviewModel(favorites: []), shortcutsModel: ShortcutsModel(), shortcutsSettingsModel: NewTabPageShortcutsSettingsModel(), sectionsSettingsModel: NewTabPageSectionsSettingsModel() @@ -329,7 +315,7 @@ private struct CustomizeButtonPrefKey: PreferenceKey { homeMessages: [] ) ), - favoritesModel: FavoritesPreviewModel(), + favoritesViewModel: FavoritesPreviewModel(), shortcutsModel: ShortcutsModel(), shortcutsSettingsModel: NewTabPageShortcutsSettingsModel(), sectionsSettingsModel: NewTabPageSectionsSettingsModel(storage: .emptyStorage()) diff --git a/DuckDuckGo/NewTabPageViewController.swift b/DuckDuckGo/NewTabPageViewController.swift index fabd1ee3ed..22a238bc23 100644 --- a/DuckDuckGo/NewTabPageViewController.swift +++ b/DuckDuckGo/NewTabPageViewController.swift @@ -23,7 +23,7 @@ import Bookmarks import BrowserServicesKit import Core -final class NewTabPageViewController: UIHostingController>, NewTabPage { +final class NewTabPageViewController: UIHostingController, NewTabPage { private let syncService: DDGSyncing private let syncBookmarksAdapter: SyncBookmarksAdapter @@ -35,7 +35,7 @@ final class NewTabPageViewController: UIHostingController FavoritesDefaultViewModel { - FavoritesDefaultViewModel(favoriteDataSource: favoriteDataSource, - faviconLoader: FavoritesFaviconLoader(), - pixelFiring: PixelFiringMock.self, - dailyPixelFiring: PixelFiringMock.self) + func testPrefixFavoritesLimitsToTwoRows() { + favoriteDataSource.favorites.append(contentsOf: Array(repeating: Favorite.stub(), count: 10)) + let sut = createSUT() + + let slice = sut.prefixedFavorites(for: 4) + + XCTAssertEqual(slice.items.count, 8) + XCTAssertTrue(slice.isCollapsible) + } + + func testAddItemIsLastWhenFavoritesPresent() throws { + favoriteDataSource.favorites.append(contentsOf: Array(repeating: Favorite.stub(), count: 10)) + let sut = createSUT() + + let lastItem = try XCTUnwrap(sut.allFavorites.last) + + XCTAssertTrue(lastItem == .addFavorite) + } + + func testAddItemIsFirstWhenFavoritesEmpty() throws { + let sut = createSUT() + + let firstItem = try XCTUnwrap(sut.allFavorites.first) + + XCTAssertTrue(firstItem == .addFavorite) + } + + private func createSUT() -> FavoritesViewModel { + FavoritesViewModel(favoriteDataSource: favoriteDataSource, + faviconLoader: FavoritesFaviconLoader(), + pixelFiring: PixelFiringMock.self, + dailyPixelFiring: PixelFiringMock.self) } } @@ -129,3 +157,12 @@ private extension Favorite { Favorite(id: UUID().uuidString, title: "foo", domain: "bar") } } + +private extension FavoriteItem { + var isPlaceholder: Bool { + switch self { + case .placeholder: return true + case .favorite, .addFavorite: return false + } + } +} From ad720edb56ad4a6a8e6e60f702bf98b352b60292 Mon Sep 17 00:00:00 2001 From: Daniel Bernal Date: Wed, 25 Sep 2024 17:49:41 +0200 Subject: [PATCH 06/13] Bump C.S.S --- DuckDuckGo.xcodeproj/project.pbxproj | 4 ++-- .../xcshareddata/swiftpm/Package.resolved | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index a45ae4e43d..fb96a2dc14 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -10918,8 +10918,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { - kind = exactVersion; - version = 198.0.1; + branch = daniel/bump.css; + kind = branch; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 4febefbd6a..90d5c69c48 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "cc3629fa16880e410e588a27a6b2426dcc140009", - "version" : "198.0.1" + "branch" : "daniel/bump.css", + "revision" : "09289dbd827cd14559713cd4a2f314d6cfb753c5" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/content-scope-scripts", "state" : { - "revision" : "4f0d109f13beec7e8beaf0bd5c0e2c1d528677f8", - "version" : "6.16.0" + "revision" : "2bed9e2963b2a9232452911d0773fac8b56416a1", + "version" : "6.17.0" } }, { From 0669c36b287f2841aa7c41993e5057fcf1e36fcc Mon Sep 17 00:00:00 2001 From: Daniel Bernal Date: Wed, 25 Sep 2024 17:52:22 +0200 Subject: [PATCH 07/13] Revert "Bump C.S.S" This reverts commit ad720edb56ad4a6a8e6e60f702bf98b352b60292. --- DuckDuckGo.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index fb96a2dc14..a45ae4e43d 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -10918,8 +10918,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { - branch = daniel/bump.css; - kind = branch; + kind = exactVersion; + version = 198.0.1; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { From 31eca1e98de53ff0817addfb09367b943291b380 Mon Sep 17 00:00:00 2001 From: Daniel Bernal Date: Wed, 25 Sep 2024 21:39:54 +0200 Subject: [PATCH 08/13] Rever BSK branch --- .../xcshareddata/swiftpm/Package.resolved | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 90d5c69c48..4febefbd6a 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "branch" : "daniel/bump.css", - "revision" : "09289dbd827cd14559713cd4a2f314d6cfb753c5" + "revision" : "cc3629fa16880e410e588a27a6b2426dcc140009", + "version" : "198.0.1" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/content-scope-scripts", "state" : { - "revision" : "2bed9e2963b2a9232452911d0773fac8b56416a1", - "version" : "6.17.0" + "revision" : "4f0d109f13beec7e8beaf0bd5c0e2c1d528677f8", + "version" : "6.16.0" } }, { From b7e0c626ce4be29bf52820bd69b5bf9e301f8e3f Mon Sep 17 00:00:00 2001 From: Daniel Bernal Date: Wed, 25 Sep 2024 23:25:59 +0200 Subject: [PATCH 09/13] Bump BSK which includes C.S.S 6.17 (#3395) Task/Issue URL: https://app.asana.com/0/414235014887631/1208399924957022/f **Description**: - Bumps C.S.S. --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index a45ae4e43d..67e79b0a99 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -10919,7 +10919,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 198.0.1; + version = 198.1.0; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 4febefbd6a..d8b3ac6978 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "cc3629fa16880e410e588a27a6b2426dcc140009", - "version" : "198.0.1" + "revision" : "4db50292abf1180d66da55cf83f75d37395df1f9", + "version" : "198.1.0" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/content-scope-scripts", "state" : { - "revision" : "4f0d109f13beec7e8beaf0bd5c0e2c1d528677f8", - "version" : "6.16.0" + "revision" : "2bed9e2963b2a9232452911d0773fac8b56416a1", + "version" : "6.17.0" } }, { From 63a18b721a332072afd7b32c264300f84c0bab6c Mon Sep 17 00:00:00 2001 From: Christopher Brind Date: Thu, 26 Sep 2024 00:06:04 +0100 Subject: [PATCH 10/13] add assertions for tabs in suggestions (#3394) Task/Issue URL: https://app.asana.com/0/392891325557410/1208350972189287/f Tech Design URL: CC: @ayoy **Description**: Adds assertions that validate tabs in suggestions and switching tabs Fixes failure check for sending notification in the workflow **Steps to test this PR**: 1. Check this test run passes: https://github.com/duckduckgo/iOS/actions/runs/11037282165 (However End to End tests have not passed for some time so as long as tabs.yaml passes that is the main thing) 3. Run the release/tabs.yaml test locally --- .github/workflows/end-to-end.yml | 1 - .maestro/release_tests/tabs.yaml | 44 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/.github/workflows/end-to-end.yml b/.github/workflows/end-to-end.yml index 3576b629c8..3e6b9b658b 100644 --- a/.github/workflows/end-to-end.yml +++ b/.github/workflows/end-to-end.yml @@ -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" \ diff --git a/.maestro/release_tests/tabs.yaml b/.maestro/release_tests/tabs.yaml index 40ae909d64..72618da2e2 100644 --- a/.maestro/release_tests/tabs.yaml +++ b/.maestro/release_tests/tabs.yaml @@ -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 @@ -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" + From e17d889b306f087c1b745bbfd8550bdf3f223c2b Mon Sep 17 00:00:00 2001 From: David Harbage Date: Thu, 26 Sep 2024 11:45:58 -0400 Subject: [PATCH 11/13] Bump BSK to pull in C-S-S 6.19.0 (#3396) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/72649045549333/1207836782368194/f Tech Design URL: https://app.asana.com/0/72649045549333/1207836782368196/f Corresponding BSK PR: https://github.com/duckduckgo/BrowserServicesKit/pull/1006 Corresponding macOS PR: https://github.com/duckduckgo/macos-browser/pull/3347 CC: @jonathanKingston **Description**: This PR bumps the BSK pin to pull in the changes from https://github.com/duckduckgo/content-scope-scripts/pull/1026. **Steps to test this PR**: 1. Navigate to any old [MSN article page](https://www.msn.com/en-us/sports/nfl/how-saquon-barkley-gave-eagles-coach-a-hard-lesson-in-accountability-while-saving-season/ar-AA1qPl89?ocid=hpmsn&cvid=81d6bc9eb97e442ba7de62c248189b23&ei=12) and refresh the page two or more times. See that the Expand Article button persists across reloads. **Definition of Done (Internal Only)**: * [ ] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? **Copy Testing**: * [ ] Use of correct apostrophes in new copy, ie `’` rather than `'` **Orientation Testing**: * [ ] Portrait * [ ] Landscape **Device Testing**: * [ ] iPhone SE (1st Gen) * [ ] iPhone 8 * [ ] iPhone X * [ ] iPhone 14 Pro * [ ] iPad **OS Testing**: * [ ] iOS 15 * [ ] iOS 16 * [ ] iOS 17 **Theme Testing**: * [ ] Light theme * [ ] Dark theme --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index fdfe390f62..10ac3c7192 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -10935,7 +10935,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 198.1.0; + version = 198.1.1; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index d8b3ac6978..0df8fdf10d 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "4db50292abf1180d66da55cf83f75d37395df1f9", - "version" : "198.1.0" + "revision" : "5b59c2790a7f7c69bf1f6793152bdb4ea344b1b4", + "version" : "198.1.1" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/content-scope-scripts", "state" : { - "revision" : "2bed9e2963b2a9232452911d0773fac8b56416a1", - "version" : "6.17.0" + "revision" : "1ed569676555d493c9c5575eaed22aa02569aac9", + "version" : "6.19.0" } }, { From ccdb203b7ca2799f78810bcb25a412aa6fcc5b0d Mon Sep 17 00:00:00 2001 From: Michal Smaga Date: Fri, 27 Sep 2024 16:51:27 +0200 Subject: [PATCH 12/13] For third party requests differentiate if they are affiliated with first party (#3386) Task/Issue URL: https://app.asana.com/0/414709148257752/1208376794617030/f **Description**: Fixed in BSK. When loading a website and some of the allowed third party requests may not be recognized as trackers but by their URL they may belong to the same entity as the website. For that cases we should mark their state as `.allowed(reason: .ownedByFirstParty)` (instead of `.allowed(reason: .otherThirdPartyRequest)`). --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 10ac3c7192..ecc72d710f 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -10935,7 +10935,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 198.1.1; + version = 198.2.0; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 0df8fdf10d..61f102813b 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "5b59c2790a7f7c69bf1f6793152bdb4ea344b1b4", - "version" : "198.1.1" + "revision" : "20469bbeeff33fcd18e78f672a544ee82b4a741c", + "version" : "198.2.0" } }, { From 904633668ff898dc21cf41a631b9cc1e84d37f6c Mon Sep 17 00:00:00 2001 From: Christopher Brind Date: Fri, 27 Sep 2024 16:42:54 +0100 Subject: [PATCH 13/13] fix suggestions performance (#3405) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/1201048563534612/1208413716679959/f Tech Design URL: CC: **Description**: Bump BSK to include suggestions performance fix. **Steps to test this PR**: 1. see https://github.com/duckduckgo/BrowserServicesKit/pull/1008 * [ ] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? **Copy Testing**: * [ ] Use of correct apostrophes in new copy, ie `’` rather than `'` **Orientation Testing**: * [ ] Portrait * [ ] Landscape **Device Testing**: * [ ] iPhone SE (1st Gen) * [ ] iPhone 8 * [ ] iPhone X * [ ] iPhone 14 Pro * [ ] iPad **OS Testing**: * [ ] iOS 15 * [ ] iOS 16 * [ ] iOS 17 **Theme Testing**: * [ ] Light theme * [ ] Dark theme --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- DuckDuckGo.xcodeproj/project.pbxproj | 6 +++--- .../xcshareddata/swiftpm/Package.resolved | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index ecc72d710f..689c61c817 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -692,9 +692,9 @@ 98F3A1D8217B37010011A0D4 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98F3A1D7217B37010011A0D4 /* Theme.swift */; }; 98F6EA472863124100720957 /* ContentBlockerRulesLists.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98F6EA462863124100720957 /* ContentBlockerRulesLists.swift */; }; 98F78B8E22419093007CACF4 /* ThemableNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98F78B8D22419093007CACF4 /* ThemableNavigationController.swift */; }; - 9F16230B2CA0F0190093C4FC /* DebouncerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F16230A2CA0F0190093C4FC /* DebouncerTests.swift */; }; 9F1061652C9C013F008DD5A0 /* DefaultVariantManager+Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F1061642C9C013F008DD5A0 /* DefaultVariantManager+Onboarding.swift */; }; 9F1623092C9D14F10093C4FC /* DefaultVariantManagerOnboardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F1623082C9D14F10093C4FC /* DefaultVariantManagerOnboardingTests.swift */; }; + 9F16230B2CA0F0190093C4FC /* DebouncerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F16230A2CA0F0190093C4FC /* DebouncerTests.swift */; }; 9F23B8012C2BC94400950875 /* OnboardingBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F23B8002C2BC94400950875 /* OnboardingBackground.swift */; }; 9F23B8032C2BCD0000950875 /* DaxDialogStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F23B8022C2BCD0000950875 /* DaxDialogStyles.swift */; }; 9F23B8062C2BE22700950875 /* OnboardingIntroViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F23B8052C2BE22700950875 /* OnboardingIntroViewModelTests.swift */; }; @@ -2501,9 +2501,9 @@ 98F3A1D7217B37010011A0D4 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; }; 98F6EA462863124100720957 /* ContentBlockerRulesLists.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentBlockerRulesLists.swift; sourceTree = ""; }; 98F78B8D22419093007CACF4 /* ThemableNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemableNavigationController.swift; sourceTree = ""; }; - 9F16230A2CA0F0190093C4FC /* DebouncerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebouncerTests.swift; sourceTree = ""; }; 9F1061642C9C013F008DD5A0 /* DefaultVariantManager+Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DefaultVariantManager+Onboarding.swift"; sourceTree = ""; }; 9F1623082C9D14F10093C4FC /* DefaultVariantManagerOnboardingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultVariantManagerOnboardingTests.swift; sourceTree = ""; }; + 9F16230A2CA0F0190093C4FC /* DebouncerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebouncerTests.swift; sourceTree = ""; }; 9F23B8002C2BC94400950875 /* OnboardingBackground.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingBackground.swift; sourceTree = ""; }; 9F23B8022C2BCD0000950875 /* DaxDialogStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DaxDialogStyles.swift; sourceTree = ""; }; 9F23B8052C2BE22700950875 /* OnboardingIntroViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingIntroViewModelTests.swift; sourceTree = ""; }; @@ -10935,7 +10935,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 198.2.0; + version = 198.2.1; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 61f102813b..9f70b65f0c 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "20469bbeeff33fcd18e78f672a544ee82b4a741c", - "version" : "198.2.0" + "revision" : "b60b38bace7262e0c4a006018b7e4b060ba4b754", + "version" : "198.2.1" } }, {