From 5f82d5ee132524bec505b643a8f6fb920dd085b1 Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Wed, 5 Feb 2025 17:41:42 +0100 Subject: [PATCH] Add History Debug Menu on macOS and display only 1 week of history when history view is enabled (#3833) Task/Issue URL: https://app.asana.com/0/72649045549333/1209328755192085 Description: This change updates History Menu when historyView feature flag is enabled, to only keep history items for last 7 days, and offer opening Full History View in order to view all history. For testing purposes, History Debug Menu was added, where history can be populated with visits to fake websites. --- DuckDuckGo-macOS.xcodeproj/project.pbxproj | 8 +- .../xcshareddata/swiftpm/Package.resolved | 4 +- .../History/Services/HistoryDebugMenu.swift | 113 ++++++++++++++++++ DuckDuckGo/Menus/HistoryMenu.swift | 32 +++-- DuckDuckGo/Menus/MainMenu.swift | 2 + .../DataBrokerProtection/Package.swift | 2 +- LocalPackages/FeatureFlags/Package.swift | 2 +- LocalPackages/HistoryView/Package.swift | 2 +- .../NetworkProtectionMac/Package.swift | 2 +- LocalPackages/NewTabPage/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- .../UserScriptActionsManager/Package.swift | 2 +- LocalPackages/WebKitExtensions/Package.swift | 2 +- .../Model/HistoryCoordinatingMock.swift | 2 +- 14 files changed, 155 insertions(+), 22 deletions(-) create mode 100644 DuckDuckGo/History/Services/HistoryDebugMenu.swift diff --git a/DuckDuckGo-macOS.xcodeproj/project.pbxproj b/DuckDuckGo-macOS.xcodeproj/project.pbxproj index db76786806..40822b172d 100644 --- a/DuckDuckGo-macOS.xcodeproj/project.pbxproj +++ b/DuckDuckGo-macOS.xcodeproj/project.pbxproj @@ -1179,6 +1179,8 @@ 3745DE062D536DCF00024FC8 /* HistoryGroupingProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3745DE042D536DCA00024FC8 /* HistoryGroupingProvider.swift */; }; 3745DE082D536EF900024FC8 /* HistoryGroupingProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3745DE072D536EF000024FC8 /* HistoryGroupingProviderTests.swift */; }; 3745DE092D536EF900024FC8 /* HistoryGroupingProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3745DE072D536EF000024FC8 /* HistoryGroupingProviderTests.swift */; }; + 3745DE0B2D53969300024FC8 /* HistoryDebugMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3745DE0A2D53969000024FC8 /* HistoryDebugMenu.swift */; }; + 3745DE0C2D53969300024FC8 /* HistoryDebugMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3745DE0A2D53969000024FC8 /* HistoryDebugMenu.swift */; }; 37479F152891BC8300302FE2 /* TabCollectionViewModelTests+WithoutPinnedTabsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37479F142891BC8300302FE2 /* TabCollectionViewModelTests+WithoutPinnedTabsManager.swift */; }; 374EF08329B751FC003D2E87 /* RecentlyClosedCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374EF08229B751FC003D2E87 /* RecentlyClosedCoordinatorTests.swift */; }; 374EF08429B7575B003D2E87 /* RecentlyClosedCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374EF08229B751FC003D2E87 /* RecentlyClosedCoordinatorTests.swift */; }; @@ -3810,6 +3812,7 @@ 37445F9B2A1569F00029F789 /* SyncBookmarksAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncBookmarksAdapter.swift; sourceTree = ""; }; 3745DE042D536DCA00024FC8 /* HistoryGroupingProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryGroupingProvider.swift; sourceTree = ""; }; 3745DE072D536EF000024FC8 /* HistoryGroupingProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryGroupingProviderTests.swift; sourceTree = ""; }; + 3745DE0A2D53969000024FC8 /* HistoryDebugMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryDebugMenu.swift; sourceTree = ""; }; 37479F142891BC8300302FE2 /* TabCollectionViewModelTests+WithoutPinnedTabsManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TabCollectionViewModelTests+WithoutPinnedTabsManager.swift"; sourceTree = ""; }; 374EF08229B751FC003D2E87 /* RecentlyClosedCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentlyClosedCoordinatorTests.swift; sourceTree = ""; }; 374EFDF22D01C99700B30939 /* ActiveRemoteMessageModel+NewTabPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ActiveRemoteMessageModel+NewTabPage.swift"; sourceTree = ""; }; @@ -9238,6 +9241,7 @@ AAE75276263B038A00B973F8 /* Services */ = { isa = PBXGroup; children = ( + 3745DE0A2D53969000024FC8 /* HistoryDebugMenu.swift */, AAE75278263B046100B973F8 /* History.xcdatamodeld */, AAE7527B263B056C00B973F8 /* EncryptedHistoryStore.swift */, 85D0327A2B8E3D090041D1FB /* HistoryCoordinatorExtension.swift */, @@ -11591,6 +11595,7 @@ 37197EAB2942443D00394917 /* WebViewContainerView.swift in Sources */, 84F1C8DF2C774D4200716446 /* NSTableViewExtension.swift in Sources */, 3706FA88293F65D500E42796 /* Logger+Multiple.swift in Sources */, + 3745DE0C2D53969300024FC8 /* HistoryDebugMenu.swift in Sources */, 3706FA89293F65D500E42796 /* CrashReportPromptPresenter.swift in Sources */, 3706FA8B293F65D500E42796 /* PreferencesRootView.swift in Sources */, 31521AC12CC013AD00248E6F /* AIChatMenuVisibilityConfigurable.swift in Sources */, @@ -13779,6 +13784,7 @@ AAC6881B28626C1900D54247 /* RecentlyClosedWindow.swift in Sources */, 85707F2A276A35FE00DC0649 /* ActionSpeech.swift in Sources */, B6BE9FAA293F7955006363C6 /* ModalSheetCancellable.swift in Sources */, + 3745DE0B2D53969300024FC8 /* HistoryDebugMenu.swift in Sources */, B6830963274CDEC7004B46BB /* FireproofDomainsStore.swift in Sources */, F188268D2BBF01C300D9AC4F /* PixelDataModel.xcdatamodeld in Sources */, 7B430EA12A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift in Sources */, @@ -15678,7 +15684,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 235.2.0; + version = 235.3.0; }; }; 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo-macOS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo-macOS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 8541ac95eb..c2b45fe176 100644 --- a/DuckDuckGo-macOS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo-macOS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "744895ff98a5f2213333be0170e495b1e85034d0", - "version" : "235.2.0" + "revision" : "f3a9e71bb3be7dc53a74e2750d4282150e62798e", + "version" : "235.3.0" } }, { diff --git a/DuckDuckGo/History/Services/HistoryDebugMenu.swift b/DuckDuckGo/History/Services/HistoryDebugMenu.swift new file mode 100644 index 0000000000..3f9b84759d --- /dev/null +++ b/DuckDuckGo/History/Services/HistoryDebugMenu.swift @@ -0,0 +1,113 @@ +// +// HistoryDebugMenu.swift +// +// Copyright © 2025 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 AppKit +import History + +final class HistoryDebugMenu: NSMenu { + + let historyCoordinator: HistoryCoordinating + + private let environmentMenu = NSMenu() + + init(historyCoordinator: HistoryCoordinating = HistoryCoordinator.shared) { + self.historyCoordinator = historyCoordinator + super.init(title: "") + + buildItems { + NSMenuItem( + title: "Add 10 history visits each day (10 domains)", + action: #selector(populateFakeHistory), + target: self, + representedObject: (10, FakeURLsPool.random10Domains) + ) + NSMenuItem( + title: "Populate 100 history visits each day (10 domains)", + action: #selector(populateFakeHistory), + target: self, + representedObject: (100, FakeURLsPool.random10Domains) + ) + NSMenuItem( + title: "Populate 100 history visits each day (200 domains – SLOW!)", + action: #selector(populateFakeHistory), + target: self, + representedObject: (100, FakeURLsPool.random200Domains) + ) + } + } + + required init(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc func populateFakeHistory(_ sender: NSMenuItem) { + guard let (maxVisitsPerDay, pool) = sender.representedObject as? (Int, FakeURLsPool) else { + return + } + Task.detached { + self.populateHistory(maxVisitsPerDay, pool.urls) + } + } + + private func populateHistory(_ maxVisitsPerDay: Int, _ urls: [URL]) { + var date = Date() + let endDate = Date.monthAgo + + var visitsPerDay = 0 + + while date > endDate { + guard let url = urls.randomElement() else { + continue + } + let visitDate = Date(timeIntervalSince1970: TimeInterval.random(in: date.startOfDay.timeIntervalSince1970..= maxVisitsPerDay { + date = date.daysAgo(1) + visitsPerDay = 0 + } + } + } + + enum FakeURLsPool { + case random10Domains + case random200Domains + + var urls: [URL] { + switch self { + case .random10Domains: + Self.fakeURLs10Domains + case .random200Domains: + Self.fakeURLs200Domains + } + } + + private static let fakeURLs10Domains: [URL] = generateFakeURLs(numberOfDomains: 10) + private static let fakeURLs200Domains: [URL] = generateFakeURLs(numberOfDomains: 200) + + private static func generateFakeURLs(numberOfDomains: Int) -> [URL] { + (0.. Date.weekAgo.startOfDay { firstWeek.append(grouping) - } else { + } else if !featureFlagger.isFeatureOn(.historyView) { older.append(grouping) } } @@ -269,7 +274,14 @@ final class HistoryMenu: NSMenu { // MARK: - Clear All History - private func addClearAllHistoryOnTheBottom() { + private func addClearAllAndShowHistoryOnTheBottom() { + if featureFlagger.isFeatureOn(.historyView) { + if showHistorySeparator.menu != nil { + removeItem(showHistorySeparator) + } + addItem(showHistorySeparator) + addItem(showHistoryMenuItem) + } if clearAllHistorySeparator.menu != nil { removeItem(clearAllHistorySeparator) } diff --git a/DuckDuckGo/Menus/MainMenu.swift b/DuckDuckGo/Menus/MainMenu.swift index ccc6539b1f..b688975e1f 100644 --- a/DuckDuckGo/Menus/MainMenu.swift +++ b/DuckDuckGo/Menus/MainMenu.swift @@ -659,6 +659,8 @@ final class MainMenu: NSMenu { NSMenuItem(title: "Shift New Tab daily impression", action: #selector(MainViewController.debugShiftNewTabOpeningDate)) NSMenuItem(title: "Shift \(AppearancePreferences.Constants.dismissNextStepsCardsAfterDays) days", action: #selector(MainViewController.debugShiftNewTabOpeningDateNtimes)) } + NSMenuItem(title: "History") + .submenu(HistoryDebugMenu()) NSMenuItem(title: "Reset Data") { NSMenuItem(title: "Reset Default Browser Prompt", action: #selector(MainViewController.resetDefaultBrowserPrompt)) NSMenuItem(title: "Reset Default Grammar Checks", action: #selector(MainViewController.resetDefaultGrammarChecks)) diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index 830e92113e..f5d0ee95ae 100644 --- a/LocalPackages/DataBrokerProtection/Package.swift +++ b/LocalPackages/DataBrokerProtection/Package.swift @@ -29,7 +29,7 @@ let package = Package( targets: ["DataBrokerProtection"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "235.2.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "235.3.0"), .package(path: "../SwiftUIExtensions"), .package(path: "../AppKitExtensions"), .package(path: "../XPCHelper"), diff --git a/LocalPackages/FeatureFlags/Package.swift b/LocalPackages/FeatureFlags/Package.swift index 4e4c268a74..bcc61de04f 100644 --- a/LocalPackages/FeatureFlags/Package.swift +++ b/LocalPackages/FeatureFlags/Package.swift @@ -32,7 +32,7 @@ let package = Package( targets: ["FeatureFlags"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "235.2.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "235.3.0"), ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. diff --git a/LocalPackages/HistoryView/Package.swift b/LocalPackages/HistoryView/Package.swift index f74adf87a4..0de44ecc63 100644 --- a/LocalPackages/HistoryView/Package.swift +++ b/LocalPackages/HistoryView/Package.swift @@ -32,7 +32,7 @@ let package = Package( targets: ["HistoryView"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "235.2.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "235.3.0"), .package(path: "../WebKitExtensions"), .package(path: "../UserScriptActionsManager"), .package(path: "../Utilities"), diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index 5e798f9193..31c6c62b33 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -33,7 +33,7 @@ let package = Package( .library(name: "VPNAppLauncher", targets: ["VPNAppLauncher"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "235.2.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "235.3.0"), .package(url: "https://github.com/airbnb/lottie-spm", exact: "4.4.3"), .package(path: "../AppLauncher"), .package(path: "../UDSHelper"), diff --git a/LocalPackages/NewTabPage/Package.swift b/LocalPackages/NewTabPage/Package.swift index 2d47eae307..48e6b34a86 100644 --- a/LocalPackages/NewTabPage/Package.swift +++ b/LocalPackages/NewTabPage/Package.swift @@ -32,7 +32,7 @@ let package = Package( targets: ["NewTabPage"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "235.2.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "235.3.0"), .package(path: "../WebKitExtensions"), .package(path: "../UserScriptActionsManager"), .package(path: "../Utilities"), diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index 7b3ea07626..16721fa24a 100644 --- a/LocalPackages/SubscriptionUI/Package.swift +++ b/LocalPackages/SubscriptionUI/Package.swift @@ -13,7 +13,7 @@ let package = Package( targets: ["SubscriptionUI"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "235.2.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "235.3.0"), .package(path: "../PreferencesUI-macOS"), .package(path: "../SwiftUIExtensions"), .package(path: "../FeatureFlags") diff --git a/LocalPackages/UserScriptActionsManager/Package.swift b/LocalPackages/UserScriptActionsManager/Package.swift index 1c0d399af1..95529fdf6d 100644 --- a/LocalPackages/UserScriptActionsManager/Package.swift +++ b/LocalPackages/UserScriptActionsManager/Package.swift @@ -31,7 +31,7 @@ let package = Package( targets: ["UserScriptActionsManager"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "235.2.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "235.3.0"), ], targets: [ .target( diff --git a/LocalPackages/WebKitExtensions/Package.swift b/LocalPackages/WebKitExtensions/Package.swift index 28a344be14..b67527b3cd 100644 --- a/LocalPackages/WebKitExtensions/Package.swift +++ b/LocalPackages/WebKitExtensions/Package.swift @@ -32,7 +32,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "235.2.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "235.3.0"), .package(path: "../AppKitExtensions") ], targets: [ diff --git a/UnitTests/History/Model/HistoryCoordinatingMock.swift b/UnitTests/History/Model/HistoryCoordinatingMock.swift index d16af67900..0e4b3ab94e 100644 --- a/UnitTests/History/Model/HistoryCoordinatingMock.swift +++ b/UnitTests/History/Model/HistoryCoordinatingMock.swift @@ -35,7 +35,7 @@ final class HistoryCoordinatingMock: HistoryCoordinating { var addVisitCalled = false var visit: Visit? - func addVisit(of url: URL) -> Visit? { + func addVisit(of url: URL, at date: Date) -> Visit? { addVisitCalled = true return visit }