From c0c2ad2911c56ed287d7d184826da0151ba6fbf7 Mon Sep 17 00:00:00 2001 From: Brandon T Date: Thu, 1 Jun 2023 18:25:10 -0400 Subject: [PATCH] Move private browsing manager to non-singleton. Fix BraveRewards crash when allocating multiple rewards. Add persistent private browsing. Wallet fix for when onboarding is visible in multiple windows. Fix windowIds being the same on tapping the app icon. Set window selected Fix window activation predicate so that tapping the Application Icon does not create new windows. Added documentation to the SceneDelegate when restoring. --- App/iOS/Delegates/SceneDelegate.swift | 123 +++++++++++++----- .../Panel/BraveRewardsViewController.swift | 2 +- .../BackForwardListViewController.swift | 1 + .../Browser/BackForwardTableViewCell.swift | 4 +- .../Browser/BrowserViewController.swift | 117 ++++++++--------- .../BrowserViewController/BVC+Rewards.swift | 35 +---- .../BrowserViewController+Callout.swift | 2 +- .../BrowserViewController+KeyCommands.swift | 4 +- .../BrowserViewController+Menu.swift | 13 +- .../BrowserViewController+Onboarding.swift | 4 +- ...serViewController+TabManagerDelegate.swift | 22 ++-- ...rowserViewController+ToolbarDelegate.swift | 13 +- ...rViewController+WKNavigationDelegate.swift | 8 +- .../BrowserViewController+Wallet.swift | 8 +- ...rowserViewController+Web3NameService.swift | 4 +- .../Browser/Favicons/LargeFaviconView.swift | 4 +- .../Favicons/UIImageView+Favicon.swift | 4 +- .../Favorites/FavoritesViewController.swift | 6 +- .../Frontend/Browser/FrequencyQuery.swift | 2 +- .../Helpers/BrowserNavigationHelper.swift | 4 +- .../Browser/Helpers/FaviconImage.swift | 11 +- .../Browser/HomePanel/NTPDataSource.swift | 7 +- .../Browser/LinkPreviewViewController.swift | 2 +- .../Frontend/Browser/NavigationRouter.swift | 12 +- .../NewTabPageBackgroundButtonsView.swift | 9 +- .../NewTabPageViewController.swift | 22 ++-- .../Sections/BraveNewsSectionProvider.swift | 4 +- .../Sections/FavoritesSectionProvider.swift | 10 +- .../Sections/StatsSectionProvider.swift | 99 ++++++++------ .../Browser/PageZoom/PageZoomView.swift | 16 ++- .../PlaylistDetailViewController.swift | 17 ++- ...ListViewController+TableViewDelegate.swift | 4 +- .../PlaylistListViewController.swift | 11 +- .../Controllers/PlaylistNewFolderView.swift | 2 +- .../Controllers/PlaylistViewController.swift | 21 ++- .../PlaylistCacheLoader.swift | 3 +- .../PlaylistCarplayManager.swift | 27 ++-- .../Utilities/PlaylistThumbnailUtility.swift | 2 +- .../Playlist/VideoPlayer/UI/VideoPlayer.swift | 4 +- .../VideoPlayer/UI/VideoPlayerInfoBar.swift | 4 +- .../PrivacyHub/PrivacyHubAllTimeSection.swift | 5 +- .../PrivacyReportAllTimeListsView.swift | 7 +- .../PrivacyHub/PrivacyReportsManager.swift | 12 +- .../PrivacyHub/PrivacyReportsView.swift | 7 +- .../PrivateBrowsingManager.swift | 4 +- .../Browser/Search/SearchEngines.swift | 14 +- .../Search/SearchSuggestionDataSource.swift | 6 +- .../Browser/Search/SearchViewController.swift | 12 +- Sources/Brave/Frontend/Browser/Tab.swift | 2 +- .../Brave/Frontend/Browser/TabManager.swift | 65 +++++---- .../Browser/TabManagerNavDelegate.swift | 2 +- .../RecentlyClosedTabsView.swift | 2 +- .../Browser/Tabs/TabBar/TabBarCell.swift | 31 +++-- .../Tabs/TabBar/TabsBarViewController.swift | 17 +-- .../TabTrayController+KeyCommands.swift | 2 +- .../TabTrayController+TableViewDelegate.swift | 2 +- .../Tabs/TabTray/TabTrayController.swift | 27 ++-- .../Tabs/TabTray/Views/TabTrayCell.swift | 2 +- .../BottomToolbar/BottomToolbarView.swift | 10 +- .../AddEditBookmarkTableViewController.swift | 14 +- .../Menu/Bookmarks/BookmarkDetailsView.swift | 4 +- .../Bookmarks/BookmarksViewController.swift | 6 +- .../Menu/HistoryViewController.swift | 6 +- .../Toolbars/HeaderContainerView.swift | 8 +- .../Toolbars/UrlBar/TabLocationView.swift | 6 +- .../Toolbars/UrlBar/TopToolbarView.swift | 14 +- .../Brave/Frontend/ClientPreferences.swift | 2 + .../Login/LoginListViewController.swift | 2 +- .../SearchCustomEngineViewController.swift | 10 +- .../SearchQuickEnginesViewController.swift | 6 +- .../SearchSettingsTableViewController.swift | 8 +- .../Settings/SettingsViewController.swift | 4 +- .../OtherPrivacySettingsSectionView.swift | 21 +++ .../ShieldsActivityItemSourceProvider.swift | 3 +- .../Shields/ShieldsViewController.swift | 8 +- .../Paged/BraveSearchScriptHandler.swift | 2 +- .../Paged/BraveTalkScriptHandler.swift | 2 +- .../Paged/ContentBlockerScriptHandler.swift | 4 +- .../RequestBlockingContentScriptHandler.swift | 4 +- .../Paged/RewardsReportingScriptHandler.swift | 2 +- Sources/Brave/Migration/Migration.swift | 2 +- .../Shortcuts/ActivityShortcutManager.swift | 7 +- Sources/Brave/States/AppState.swift | 39 +++++- Sources/BraveStrings/BraveStrings.swift | 1 + .../Crypto/Stores/KeyringStore.swift | 21 +++ Sources/Data/models/SessionTab.swift | 9 +- Sources/Data/models/SessionWindow.swift | 2 +- 87 files changed, 663 insertions(+), 450 deletions(-) diff --git a/App/iOS/Delegates/SceneDelegate.swift b/App/iOS/Delegates/SceneDelegate.swift index 835e3d3d63b..bf7bf970a7f 100644 --- a/App/iOS/Delegates/SceneDelegate.swift +++ b/App/iOS/Delegates/SceneDelegate.swift @@ -32,43 +32,49 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } - + let browserViewController = createBrowserWindow( scene: windowScene, braveCore: AppState.shared.braveCore, profile: AppState.shared.profile, diskImageStore: AppState.shared.diskImageStore, migration: AppState.shared.migration, + rewards: AppState.shared.rewards, userActivity: connectionOptions.userActivities.first ?? session.stateRestorationActivity ) let conditions = scene.activationConditions - conditions.canActivateForTargetContentIdentifierPredicate = NSPredicate(value: false) + conditions.canActivateForTargetContentIdentifierPredicate = NSPredicate(value: true) if let windowId = session.userInfo?["WindowID"] as? UUID { let preferPredicate = NSPredicate(format: "self == %@", windowId.uuidString) - conditions.prefersToActivateForTargetContentIdentifierPredicate = - NSCompoundPredicate(orPredicateWithSubpredicates: [preferPredicate]) + conditions.prefersToActivateForTargetContentIdentifierPredicate = preferPredicate } Preferences.General.themeNormalMode.objectWillChange .receive(on: RunLoop.main) .sink { [weak self, weak scene] _ in - self?.updateTheme(for: scene) + guard let self = self, + let scene = scene as? UIWindowScene else { return } + self.updateTheme(for: scene) } .store(in: &cancellables) Preferences.General.nightModeEnabled.objectWillChange .receive(on: RunLoop.main) .sink { [weak self, weak scene] _ in - self?.updateTheme(for: scene) + guard let self = self, + let scene = scene as? UIWindowScene else { return } + self.updateTheme(for: scene) } .store(in: &cancellables) - PrivateBrowsingManager.shared.$isPrivateBrowsing + browserViewController.privateBrowsingManager.$isPrivateBrowsing .removeDuplicates() .receive(on: RunLoop.main) .sink { [weak self, weak scene] _ in - self?.updateTheme(for: scene) + guard let self = self, + let scene = scene as? UIWindowScene else { return } + self.updateTheme(for: scene) } .store(in: &cancellables) @@ -98,7 +104,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { PrivacyReportsManager.scheduleNotification(debugMode: !AppConstants.buildChannel.isPublic) PrivacyReportsManager.consolidateData() - PrivacyReportsManager.scheduleProcessingBlockedRequests() + PrivacyReportsManager.scheduleProcessingBlockedRequests(isPrivateBrowsing: browserViewController.privateBrowsingManager.isPrivateBrowsing) PrivacyReportsManager.scheduleVPNAlertsTask() } @@ -161,6 +167,12 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { return } + if let windowId = (scene.userActivity?.userInfo?["WindowID"] ?? + scene.session.userInfo?["WindowID"]) as? String, + let windowUUID = UUID(uuidString: windowId) { + SessionWindow.setSelected(windowId: windowUUID) + } + Preferences.AppState.backgroundedCleanly.value = false AppState.shared.profile.reopen() @@ -187,7 +199,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { AppState.shared.dau.sendPingToServer() } - BraveSkusManager.refreshSKUCredential(isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing) + BraveSkusManager.refreshSKUCredential(isPrivate: scene.browserViewController?.privateBrowsingManager.isPrivateBrowsing == true) } func sceneWillResignActive(_ scene: UIScene) { @@ -213,7 +225,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } URLContexts.forEach({ - guard let routerpath = NavigationPath(url: $0.url) else { + guard let routerpath = NavigationPath(url: $0.url, isPrivateBrowsing: scene.browserViewController?.privateBrowsingManager.isPrivateBrowsing == true) else { log.debug("Invalid Navigation Path: \($0.url)") return } @@ -223,11 +235,10 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } func scene(_ scene: UIScene, didUpdate userActivity: NSUserActivity) { - print("HERE") + log.debug("Updated User Activity for Scene") } func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { - guard let scene = scene as? UIWindowScene else { return } @@ -335,7 +346,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) { - if let browserViewController = windowScene.browserViewController { QuickActions.sharedInstance.handleShortCutItem(shortcutItem, withBrowserViewController: browserViewController) completionHandler(true) @@ -350,32 +360,31 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } extension SceneDelegate { - private func expectedThemeOverride(for scene: UIScene?) -> UIUserInterfaceStyle { + private func expectedThemeOverride(for scene: UIWindowScene?) -> UIUserInterfaceStyle { // The expected appearance theme should be dark mode when night mode is enabled for websites let themeValue = Preferences.General.nightModeEnabled.value ? DefaultTheme.dark.rawValue : Preferences.General.themeNormalMode.value let themeOverride = DefaultTheme(rawValue: themeValue)?.userInterfaceStyleOverride ?? .unspecified - let isPrivateBrowsing = scene?.userActivity?.userInfo?["isPrivate"] as? Bool ?? - scene?.session.userInfo?["isPrivate"] as? Bool ?? - PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivateBrowsing = scene?.browserViewController?.privateBrowsingManager.isPrivateBrowsing == true return isPrivateBrowsing ? .dark : themeOverride } - private func updateTheme(for scene: UIScene?) { - guard let window = window else { return } - UIView.transition( - with: window, duration: 0.15, options: [.transitionCrossDissolve], - animations: { - window.overrideUserInterfaceStyle = self.expectedThemeOverride(for: scene) - }, completion: nil) + private func updateTheme(for scene: UIWindowScene) { + scene.windows.forEach { window in + UIView.transition( + with: window, duration: 0.15, options: [.transitionCrossDissolve], + animations: { + window.overrideUserInterfaceStyle = self.expectedThemeOverride(for: scene) + }, completion: nil) + } } } extension SceneDelegate { - private func createBrowserWindow(scene: UIWindowScene, braveCore: BraveCoreMain, profile: Profile, diskImageStore: DiskImageStore?, migration: Migration?, userActivity: NSUserActivity?) -> BrowserViewController { - // Make sure current private browsing flag respects the private browsing only user preference - PrivateBrowsingManager.shared.isPrivateBrowsing = Preferences.Privacy.privateBrowsingOnly.value + private func createBrowserWindow(scene: UIWindowScene, braveCore: BraveCoreMain, profile: Profile, diskImageStore: DiskImageStore?, migration: Migration?, rewards: Brave.BraveRewards, userActivity: NSUserActivity?) -> BrowserViewController { + + let privateBrowsingManager = PrivateBrowsingManager() // Don't track crashes if we're building the development environment due to the fact that terminating/stopping // the simulator via Xcode will count as a "crash" and lead to restore popups in the subsequent launch @@ -387,9 +396,12 @@ extension SceneDelegate { var userActivity = userActivity if let userActivity = userActivity { + // Restore the scene with the WindowID from the User-Activity + let windowIdString = userActivity.userInfo?["WindowID"] as? String ?? "" windowId = UUID(uuidString: windowIdString) ?? UUID() - isPrivate = userActivity.userInfo?["isPrivate"] as? Bool ?? Preferences.Privacy.privateBrowsingOnly.value + isPrivate = userActivity.userInfo?["isPrivate"] as? Bool == true + privateBrowsingManager.isPrivateBrowsing = isPrivate // Create a new session window SessionWindow.createWindow(isPrivate: isPrivate, isSelected: true, uuid: windowId) @@ -397,9 +409,53 @@ extension SceneDelegate { scene.userActivity = userActivity scene.session.userInfo?["WindowID"] = windowId scene.session.userInfo?["isPrivate"] = isPrivate + } else if let sceneWindowId = scene.session.userInfo?["WindowID"] as? String, + let sceneIsPrivate = scene.session.userInfo?["isPrivate"] as? Bool, + let windowUUID = UUID(uuidString: sceneWindowId) { + + // Restore the scene from the Session's User-Info WindowID + + windowId = windowUUID + isPrivate = sceneIsPrivate + privateBrowsingManager.isPrivateBrowsing = sceneIsPrivate + + scene.userActivity = BrowserState.userActivity(for: windowId, isPrivate: isPrivate) } else { - windowId = SessionWindow.getActiveWindow(context: DataController.swiftUIContext)?.windowId ?? UUID() - isPrivate = Preferences.Privacy.privateBrowsingOnly.value + // Should NOT be possible to get here. + // However, if a controller is NOT active, and tapping the app-icon opens a New-Window + // Then we need to make sure not to restore that "New" Window + // So we iterate all the windows and if there is no active window, then we need to "Restore" one. + // If a window is already active, we need to create a new blank window. + + if let activeWindowId = SessionWindow.getActiveWindow(context: DataController.swiftUIContext)?.windowId { + let activeSession = UIApplication.shared.openSessions + .compactMap({ $0.userInfo?["WindowID"] as? String }) + .first(where: { $0 == activeWindowId.uuidString }) + + if activeSession != nil { + // An existing window is already active on screen + // So create a new window + let newWindowId = UUID() + SessionWindow.createWindow(isPrivate: false, isSelected: true, uuid: newWindowId) + windowId = newWindowId + } else { + // Restore the active window since none is active on screen + windowId = activeWindowId + } + } else { + // Should be impossible to get here. There must always be an active window. + // However, if for some reason there is none, then we should create one. + let newWindowId = UUID() + SessionWindow.createWindow(isPrivate: false, isSelected: true, uuid: newWindowId) + windowId = newWindowId + } + + isPrivate = false + privateBrowsingManager.isPrivateBrowsing = false + + scene.userActivity = BrowserState.userActivity(for: windowId, isPrivate: false) + scene.session.userInfo = ["WindowID": windowId.uuidString, + "isPrivate": false] } // Create a browser instance @@ -409,7 +465,10 @@ extension SceneDelegate { diskImageStore: diskImageStore, braveCore: braveCore, migration: migration, - crashedLastSession: crashedLastSession) + crashedLastSession: crashedLastSession, + rewards: rewards, + privateBrowsingManager: privateBrowsingManager + ) browserViewController.do { $0.edgesForExtendedLayout = [] diff --git a/Sources/Brave/Frontend/Brave Rewards/Panel/BraveRewardsViewController.swift b/Sources/Brave/Frontend/Brave Rewards/Panel/BraveRewardsViewController.swift index 9ab7127205a..8935f3c5ccb 100644 --- a/Sources/Brave/Frontend/Brave Rewards/Panel/BraveRewardsViewController.swift +++ b/Sources/Brave/Frontend/Brave Rewards/Panel/BraveRewardsViewController.swift @@ -34,7 +34,7 @@ class BraveRewardsViewController: UIViewController, PopoverContentComponent { } else { if let url = tab.url { rewardsView.publisherView.faviconImageView.contentMode = .scaleAspectFit - rewardsView.publisherView.faviconImageView.loadFavicon(for: url) + rewardsView.publisherView.faviconImageView.loadFavicon(for: url, isPrivateBrowsing: tab.isPrivate) } else { rewardsView.publisherView.faviconImageView.isHidden = true } diff --git a/Sources/Brave/Frontend/Browser/BackForwardListViewController.swift b/Sources/Brave/Frontend/Browser/BackForwardListViewController.swift index fce79c67441..554f6ccad6a 100644 --- a/Sources/Brave/Frontend/Browser/BackForwardListViewController.swift +++ b/Sources/Brave/Frontend/Browser/BackForwardListViewController.swift @@ -216,6 +216,7 @@ class BackForwardListViewController: UIViewController, UITableViewDataSource, UI return extracted.absoluteString }() + cell.isPrivateBrowsing = tabManager.privateBrowsingManager.isPrivateBrowsing cell.isCurrentTab = listData[indexPath.item] == self.currentItem cell.connectingBackwards = indexPath.item != listData.count - 1 cell.connectingForwards = indexPath.item != 0 diff --git a/Sources/Brave/Frontend/Browser/BackForwardTableViewCell.swift b/Sources/Brave/Frontend/Browser/BackForwardTableViewCell.swift index cf24846125c..99ffb39fd52 100644 --- a/Sources/Brave/Frontend/Browser/BackForwardTableViewCell.swift +++ b/Sources/Brave/Frontend/Browser/BackForwardTableViewCell.swift @@ -43,6 +43,8 @@ class BackForwardTableViewCell: UITableViewCell { label.textColor = BackForwardViewCellUX.textColor return label }() + + var isPrivateBrowsing: Bool = false var connectingForwards = true { didSet { @@ -70,7 +72,7 @@ class BackForwardTableViewCell: UITableViewCell { faviconView.backgroundColor = .white faviconView.image = Favicon.defaultImage } else { - faviconView.loadFavicon(for: s.tileURL) + faviconView.loadFavicon(for: s.tileURL, isPrivateBrowsing: isPrivateBrowsing) } var title = s.title if title.isEmpty { diff --git a/Sources/Brave/Frontend/Browser/BrowserViewController.swift b/Sources/Brave/Frontend/Browser/BrowserViewController.swift index 5c9b441ec6f..7a1813f9b81 100644 --- a/Sources/Brave/Frontend/Browser/BrowserViewController.swift +++ b/Sources/Brave/Frontend/Browser/BrowserViewController.swift @@ -52,7 +52,7 @@ public class BrowserViewController: UIViewController { private(set) lazy var topToolbar: TopToolbarView = { // Setup the URL bar, wrapped in a view to get transparency effect - let topToolbar = TopToolbarView() + let topToolbar = TopToolbarView(privateBrowsingManager: privateBrowsingManager) topToolbar.translatesAutoresizingMaskIntoConstraints = false topToolbar.delegate = self topToolbar.tabToolbarDelegate = self @@ -69,7 +69,7 @@ public class BrowserViewController: UIViewController { }() // These views wrap the top and bottom toolbars to provide background effects on them - let header = HeaderContainerView() + private(set) lazy var header = HeaderContainerView(privateBrowsingManager: privateBrowsingManager) private let headerHeightLayoutGuide = UILayoutGuide() let footer: UIView = { @@ -132,7 +132,7 @@ public class BrowserViewController: UIViewController { let collapsedURLBarView = CollapsedURLBarView() // Single data source used for all favorites vcs - public let backgroundDataSource = NTPDataSource() + private(set) public lazy var backgroundDataSource = NTPDataSource(privateBrowsingManager: self.privateBrowsingManager) let feedDataSource = FeedDataSource() private var postSetupTasks: [() -> Void] = [] @@ -164,6 +164,7 @@ public class BrowserViewController: UIViewController { let tabManager: TabManager let migration: Migration? let bookmarkManager: BookmarkManager + public let privateBrowsingManager: PrivateBrowsingManager /// Whether last session was a crash or not private let crashedLastSession: Bool @@ -273,7 +274,9 @@ public class BrowserViewController: UIViewController { diskImageStore: DiskImageStore?, braveCore: BraveCoreMain, migration: Migration?, - crashedLastSession: Bool + crashedLastSession: Bool, + rewards: BraveRewards, + privateBrowsingManager: PrivateBrowsingManager ) { self.windowId = windowId self.profile = profile @@ -281,21 +284,18 @@ public class BrowserViewController: UIViewController { self.bookmarkManager = BookmarkManager(bookmarksAPI: braveCore.bookmarksAPI) self.migration = migration self.crashedLastSession = crashedLastSession + self.rewards = rewards + self.privateBrowsingManager = privateBrowsingManager feedDataSource.historyAPI = braveCore.historyAPI - - let configuration: BraveRewards.Configuration = .current() - - Self.migrateAdsConfirmations(for: configuration) - - // Initialize Rewards - self.rewards = BraveRewards(configuration: configuration) // Initialize TabManager self.tabManager = TabManager( windowId: windowId, prefs: profile.prefs, rewards: rewards, - tabGeneratorAPI: braveCore.tabGeneratorAPI) + tabGeneratorAPI: braveCore.tabGeneratorAPI, + privateBrowsingManager: privateBrowsingManager + ) // Add Regular tabs to Sync Chain if Preferences.Chromium.syncOpenTabsEnabled.value { @@ -318,7 +318,7 @@ public class BrowserViewController: UIViewController { } } - self.deviceCheckClient = DeviceCheckClient(environment: configuration.environment) + self.deviceCheckClient = DeviceCheckClient(environment: BraveRewards.Configuration.current().environment) if Locale.current.regionCode == "JP" { benchmarkBlockingDataSource = BlockingSummaryDataSource() @@ -445,7 +445,7 @@ public class BrowserViewController: UIViewController { pageZoomListener = NotificationCenter.default.addObserver(forName: PageZoomView.notificationName, object: nil, queue: .main) { [weak self] _ in self?.tabManager.allTabs.forEach({ guard let url = $0.webView?.url else { return } - let zoomLevel = PrivateBrowsingManager.shared.isPrivateBrowsing ? 1.0 : Domain.getPersistedDomain(for: url)?.zoom_level?.doubleValue ?? Preferences.General.defaultPageZoomLevel.value + let zoomLevel = self?.privateBrowsingManager.isPrivateBrowsing == true ? 1.0 : Domain.getPersistedDomain(for: url)?.zoom_level?.doubleValue ?? Preferences.General.defaultPageZoomLevel.value $0.webView?.setValue(zoomLevel, forKey: PageZoomView.propertyName) }) } @@ -552,7 +552,7 @@ public class BrowserViewController: UIViewController { notificationsPresenter: notificationsPresenter) notificationsHandler?.canShowNotifications = { [weak self] in guard let self = self else { return false } - return !PrivateBrowsingManager.shared.isPrivateBrowsing && !self.topToolbar.inOverlayMode + return !self.privateBrowsingManager.isPrivateBrowsing && !self.topToolbar.inOverlayMode } notificationsHandler?.actionOccured = { [weak self] ad, action in guard let self = self, let ad = ad else { return } @@ -569,7 +569,7 @@ public class BrowserViewController: UIViewController { return } let request = URLRequest(url: targetURL) - self.tabManager.addTabAndSelect(request, isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing) + self.tabManager.addTabAndSelect(request, isPrivate: self.privateBrowsingManager.isPrivateBrowsing) } } } @@ -610,7 +610,7 @@ public class BrowserViewController: UIViewController { bottomTouchArea.isEnabled = showToolbar if showToolbar { - toolbar = BottomToolbarView() + toolbar = BottomToolbarView(privateBrowsingManager: privateBrowsingManager) toolbar?.setSearchButtonState(url: tabManager.selectedTab?.url) footer.addSubview(toolbar!) toolbar?.tabToolbarDelegate = self @@ -871,7 +871,7 @@ public class BrowserViewController: UIViewController { scheduleDefaultBrowserNotification() } - privateModeCancellable = PrivateBrowsingManager.shared + privateModeCancellable = privateBrowsingManager .$isPrivateBrowsing .removeDuplicates() .sink(receiveValue: { [weak self] isPrivateBrowsing in @@ -1080,7 +1080,7 @@ public class BrowserViewController: UIViewController { fileprivate func showRestoreTabsAlert() { guard canRestoreTabs() else { - self.tabManager.addTabAndSelect(isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing) + self.tabManager.addTabAndSelect(isPrivate: self.privateBrowsingManager.isPrivateBrowsing) return } let alert = UIAlertController.restoreTabsAlert( @@ -1089,7 +1089,7 @@ public class BrowserViewController: UIViewController { }, noCallback: { _ in SessionTab.deleteAll() - self.tabManager.addTabAndSelect(isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing) + self.tabManager.addTabAndSelect(isPrivate: self.privateBrowsingManager.isPrivateBrowsing) } ) self.present(alert, animated: true, completion: nil) @@ -1130,10 +1130,9 @@ public class BrowserViewController: UIViewController { } else { userActivity?.targetContentIdentifier = windowId.uuidString userActivity?.addUserInfoEntries(from: ["WindowID": windowId.uuidString, - "isPrivate": isPrivateBrowsing]) + "isPrivate": isPrivateBrowsing]) } - view.window?.windowScene?.userActivity = userActivity view.window?.windowScene?.session.userInfo = ["WindowID": windowId.uuidString, "isPrivate": isPrivateBrowsing] @@ -1302,7 +1301,9 @@ public class BrowserViewController: UIViewController { profile: profile, dataSource: backgroundDataSource, feedDataSource: feedDataSource, - rewards: rewards) + rewards: rewards, + privateBrowsingManager: privateBrowsingManager + ) // Donate NewTabPage Activity For Custom Suggestions let newTabPageActivity = ActivityShortcutManager.shared.createShortcutActivity(type: selectedTab.isPrivate ? .newPrivateTab : .newTab) @@ -1385,7 +1386,7 @@ public class BrowserViewController: UIViewController { public func presentCorrespondingVPNViewController() { if BraveSkusManager.keepShowingSessionExpiredState { let alert = BraveSkusManager.sessionExpiredStateAlert(loginCallback: { [unowned self] _ in - self.openURLInNewTab(.brave.account, isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing, + self.openURLInNewTab(.brave.account, isPrivate: self.privateBrowsingManager.isPrivateBrowsing, isPrivileged: false) }) @@ -1830,7 +1831,7 @@ public class BrowserViewController: UIViewController { } else if let tab = tabManager.getTabForURL(url) { tabManager.selectTab(tab) } else { - openURLInNewTab(url, isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing, isPrivileged: false) + openURLInNewTab(url, isPrivate: privateBrowsingManager.isPrivateBrowsing, isPrivileged: false) } } @@ -1933,7 +1934,7 @@ public class BrowserViewController: UIViewController { var activities = [UIActivity]() // Adding SendTabToSelfActivity conditionally to show device selection screen - if !PrivateBrowsingManager.shared.isPrivateBrowsing, !url.isLocal, !InternalURL.isValid(url: url), !url.isReaderModeURL, + if !privateBrowsingManager.isPrivateBrowsing, !url.isLocal, !InternalURL.isValid(url: url), !url.isReaderModeURL, braveCore.syncAPI.isSendTabToSelfVisible { let sendTabToSelfActivity = SendTabToSelfActivity() { [weak self] in guard let self = self else { return } @@ -2151,7 +2152,7 @@ public class BrowserViewController: UIViewController { } guard let webView = tabManager.selectedTab?.webView else { return } - let pageZoomBar = UIHostingController(rootView: PageZoomView(webView: webView)) + let pageZoomBar = UIHostingController(rootView: PageZoomView(webView: webView, isPrivateBrowsing: privateBrowsingManager.isPrivateBrowsing)) pageZoomBar.rootView.dismiss = { [weak self] in guard let self = self else { return } @@ -2188,7 +2189,7 @@ public class BrowserViewController: UIViewController { if let currentURL = tab.url { let domain = Domain.getPersistedDomain(for: currentURL) - let zoomLevel = PrivateBrowsingManager.shared.isPrivateBrowsing ? 1.0 : domain?.zoom_level?.doubleValue ?? Preferences.General.defaultPageZoomLevel.value + let zoomLevel = privateBrowsingManager.isPrivateBrowsing ? 1.0 : domain?.zoom_level?.doubleValue ?? Preferences.General.defaultPageZoomLevel.value tab.webView?.setValue(zoomLevel, forKey: PageZoomView.propertyName) } } @@ -2203,7 +2204,7 @@ public class BrowserViewController: UIViewController { func updateStatusBarOverlayColor() { defer { setNeedsStatusBarAppearanceUpdate() } guard isUsingBottomBar, let color = tabManager.selectedTab?.webView?.sampledPageTopColor else { - if PrivateBrowsingManager.shared.isPrivateBrowsing { + if privateBrowsingManager.isPrivateBrowsing { statusBarOverlay.backgroundColor = .privateModeBackground } else { statusBarOverlay.backgroundColor = Preferences.General.nightModeEnabled.value ? .nightModeBackground : .urlBarBackground @@ -2233,21 +2234,21 @@ public class BrowserViewController: UIViewController { webView.evaluateSafeJavaScript(functionName: "\(ReaderModeNamespace).checkReadability", contentWorld: ReaderModeScriptHandler.scriptSandbox) // Only add history of a url which is not a localhost url - if !tab.isPrivate, !url.isReaderModeURL { + if !url.isReaderModeURL { // The visitType is checked If it is "typed" or not to determine the History object we are adding // should be synced or not. This limitation exists on browser side so we are aligning with this - if let visitType = typedNavigation.first(where: { - $0.key.typedDisplayString == url.typedDisplayString - })?.value, visitType == .typed { - braveCore.historyAPI.add(url: url, title: tab.title, dateAdded: Date()) - } else { - braveCore.historyAPI.add(url: url, title: tab.title, dateAdded: Date(), isURLTyped: false) - } - - // Saving Tab. Private Mode - not supported yet. if !tab.isPrivate { - tabManager.saveTab(tab) + if let visitType = typedNavigation.first(where: { + $0.key.typedDisplayString == url.typedDisplayString + })?.value, visitType == .typed { + braveCore.historyAPI.add(url: url, title: tab.title, dateAdded: Date()) + } else { + braveCore.historyAPI.add(url: url, title: tab.title, dateAdded: Date(), isURLTyped: false) + } } + + // Saving Tab. + tabManager.saveTab(tab) } } @@ -2387,7 +2388,7 @@ extension BrowserViewController { self.topToolbar.enterOverlayMode(overlayText, pasted: false, search: false) } - if !url.isBookmarklet && !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !url.isBookmarklet && !privateBrowsingManager.isPrivateBrowsing { RecentSearch.addItem(type: .qrCode, text: nil, websiteUrl: url.absoluteString) } } @@ -2396,7 +2397,7 @@ extension BrowserViewController { popToBVC() submitSearchText(text) - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !privateBrowsingManager.isPrivateBrowsing { RecentSearch.addItem(type: .qrCode, text: text, websiteUrl: nil) } } @@ -2404,7 +2405,7 @@ extension BrowserViewController { extension BrowserViewController: SettingsDelegate { func settingsOpenURLInNewTab(_ url: URL) { - let forcedPrivate = PrivateBrowsingManager.shared.isPrivateBrowsing + let forcedPrivate = privateBrowsingManager.isPrivateBrowsing self.openURLInNewTab(url, isPrivate: forcedPrivate, isPrivileged: false) } @@ -2601,7 +2602,7 @@ extension BrowserViewController: TabDelegate { /// Triggered when "Search with Brave" is selected on selected web text func tab(_ tab: Tab, didSelectSearchWithBraveFor selectedText: String) { - let engine = profile.searchEngines.defaultEngine() + let engine = profile.searchEngines.defaultEngine(forType: tab.isPrivate ? .privateMode : .standard) guard let url = engine.searchURLForQuery(selectedText) else { assertionFailure("If this returns nil, investigate why and add proper handling or commenting") @@ -2614,7 +2615,7 @@ extension BrowserViewController: TabDelegate { isPrivate: tab.isPrivate ) - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !privateBrowsingManager.isPrivateBrowsing { RecentSearch.addItem(type: .text, text: selectedText, websiteUrl: url.absoluteString) } } @@ -2653,7 +2654,7 @@ extension BrowserViewController: TabDelegate { vc.linkTapped = { [unowned self] request in tab.rewardsEnabledCallback?(false) self.tabManager - .addTabAndSelect(request, isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing) + .addTabAndSelect(request, isPrivate: privateBrowsingManager.isPrivateBrowsing) } } @@ -2701,7 +2702,7 @@ extension BrowserViewController: TabDelegate { @MainActor private func isPendingRequestAvailable() async -> Bool { - let privateMode = PrivateBrowsingManager.shared.isPrivateBrowsing + let privateMode = privateBrowsingManager.isPrivateBrowsing // If we have an open `WalletStore`, use that so we can assign the pending request if the wallet is open, // which allows us to store the new `PendingRequest` triggering a modal presentation for that request. guard let cryptoStore = self.walletStore?.cryptoStore ?? CryptoStore.from(ipfsApi: braveCore.ipfsAPI, privateMode: privateMode) else { @@ -2738,7 +2739,7 @@ extension BrowserViewController: SearchViewControllerDelegate { } func presentSearchSettingsController() { - let settingsNavigationController = SearchSettingsTableViewController(profile: profile) + let settingsNavigationController = SearchSettingsTableViewController(profile: profile, privateBrowsingManager: privateBrowsingManager) let navController = ModalSettingsNavigationController(rootViewController: settingsNavigationController) self.present(navController, animated: true, completion: nil) @@ -2847,7 +2848,7 @@ extension BrowserViewController: ToolbarUrlActionsDelegate { updateURLBarWalletButton() case .openInNewTab(let isPrivate): let tab = tabManager.addTab(PrivilegedRequest(url: url) as URLRequest, afterTab: tabManager.selectedTab, isPrivate: isPrivate) - if isPrivate && !PrivateBrowsingManager.shared.isPrivateBrowsing { + if isPrivate && !privateBrowsingManager.isPrivateBrowsing { tabManager.selectTab(tab) } else { // If we are showing toptabs a user can just use the top tab bar @@ -2892,7 +2893,7 @@ extension BrowserViewController: ToolbarUrlActionsDelegate { extension BrowserViewController: NewTabPageDelegate { func navigateToInput(_ input: String, inNewTab: Bool, switchingToPrivateMode: Bool) { - let isPrivate = PrivateBrowsingManager.shared.isPrivateBrowsing || switchingToPrivateMode + let isPrivate = privateBrowsingManager.isPrivateBrowsing || switchingToPrivateMode if inNewTab { tabManager.addTabAndSelect(isPrivate: isPrivate) } @@ -2970,7 +2971,7 @@ extension BrowserViewController: PreferencesObserver { case Preferences.General.tabBarVisibility.key: updateTabsBarVisibility() case Preferences.Privacy.privateBrowsingOnly.key: - PrivateBrowsingManager.shared.isPrivateBrowsing = Preferences.Privacy.privateBrowsingOnly.value + privateBrowsingManager.isPrivateBrowsing = Preferences.Privacy.privateBrowsingOnly.value setupTabs() updateTabsBarVisibility() updateApplicationShortcuts() @@ -2988,7 +2989,7 @@ extension BrowserViewController: PreferencesObserver { case Preferences.General.defaultPageZoomLevel.key: tabManager.allTabs.forEach({ guard let url = $0.webView?.url else { return } - let zoomLevel = PrivateBrowsingManager.shared.isPrivateBrowsing ? 1.0 : Domain.getPersistedDomain(for: url)?.zoom_level?.doubleValue ?? Preferences.General.defaultPageZoomLevel.value + let zoomLevel = $0.isPrivate ? 1.0 : Domain.getPersistedDomain(for: url)?.zoom_level?.doubleValue ?? Preferences.General.defaultPageZoomLevel.value $0.webView?.setValue(zoomLevel, forKey: PageZoomView.propertyName) }) case Preferences.Shields.httpsEverywhere.key: @@ -3037,7 +3038,7 @@ extension BrowserViewController: PreferencesObserver { state: selectedTab?.playlistItemState ?? .none, item: selectedTab?.playlistItem) case Preferences.PrivacyReports.captureShieldsData.key: - PrivacyReportsManager.scheduleProcessingBlockedRequests() + PrivacyReportsManager.scheduleProcessingBlockedRequests(isPrivateBrowsing: privateBrowsingManager.isPrivateBrowsing) PrivacyReportsManager.scheduleNotification(debugMode: !AppConstants.buildChannel.isPublic) case Preferences.PrivacyReports.captureVPNAlerts.key: PrivacyReportsManager.scheduleVPNAlertsTask() @@ -3047,7 +3048,7 @@ extension BrowserViewController: PreferencesObserver { notificationsPresenter.removeNotification(with: WalletNotification.Constant.id) WalletProviderPermissionRequestsManager.shared.cancelAllPendingRequests(for: [.eth]) WalletProviderAccountCreationRequestManager.shared.cancelAllPendingRequests(coins: [.eth]) - let privateMode = PrivateBrowsingManager.shared.isPrivateBrowsing + let privateMode = privateBrowsingManager.isPrivateBrowsing if let cryptoStore = CryptoStore.from(ipfsApi: braveCore.ipfsAPI, privateMode: privateMode) { cryptoStore.rejectAllPendingWebpageRequests() } @@ -3058,7 +3059,7 @@ extension BrowserViewController: PreferencesObserver { notificationsPresenter.removeNotification(with: WalletNotification.Constant.id) WalletProviderPermissionRequestsManager.shared.cancelAllPendingRequests(for: [.sol]) WalletProviderAccountCreationRequestManager.shared.cancelAllPendingRequests(coins: [.sol]) - let privateMode = PrivateBrowsingManager.shared.isPrivateBrowsing + let privateMode = privateBrowsingManager.isPrivateBrowsing if let cryptoStore = CryptoStore.from(ipfsApi: braveCore.ipfsAPI, privateMode: privateMode) { cryptoStore.rejectAllPendingWebpageRequests() } @@ -3089,7 +3090,7 @@ extension BrowserViewController { extension BrowserViewController { func presentTabReceivedToast(url: URL) { // 'Tab Received' indicator will only be shown in normal browsing - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !privateBrowsingManager.isPrivateBrowsing { let toast = ButtonToast( labelText: Strings.Callout.tabReceivedCalloutTitle, image: UIImage(braveSystemNamed: "leo.smartphone.tablet-portrait"), @@ -3159,11 +3160,11 @@ extension BrowserViewController: UIScreenshotServiceDelegate { // Privacy reports extension BrowserViewController { public func openPrivacyReport() { - if PrivateBrowsingManager.shared.isPrivateBrowsing { + if privateBrowsingManager.isPrivateBrowsing { return } - let host = UIHostingController(rootView: PrivacyReportsManager.prepareView()) + let host = UIHostingController(rootView: PrivacyReportsManager.prepareView(isPrivateBrowsing: privateBrowsingManager.isPrivateBrowsing)) host.rootView.openPrivacyReportsUrl = { [weak self] in guard let self = self else { return } diff --git a/Sources/Brave/Frontend/Browser/BrowserViewController/BVC+Rewards.swift b/Sources/Brave/Frontend/Browser/BrowserViewController/BVC+Rewards.swift index 6d80987d9ce..880ac67c9d9 100644 --- a/Sources/Brave/Frontend/Browser/BrowserViewController/BVC+Rewards.swift +++ b/Sources/Brave/Frontend/Browser/BrowserViewController/BVC+Rewards.swift @@ -25,7 +25,7 @@ extension BrowserViewController { self.topToolbar.locationView.rewardsButton.isHidden = true return } - self.topToolbar.locationView.rewardsButton.isHidden = Preferences.Rewards.hideRewardsIcon.value || PrivateBrowsingManager.shared.isPrivateBrowsing + self.topToolbar.locationView.rewardsButton.isHidden = Preferences.Rewards.hideRewardsIcon.value || privateBrowsingManager.isPrivateBrowsing self.topToolbar.locationView.rewardsButton.iconState = Preferences.Rewards.rewardsToggledOnce.value ? (rewards.isEnabled || rewards.isCreatingWallet ? .enabled : .disabled) : .initial } @@ -112,35 +112,6 @@ extension BrowserViewController { Preferences.NewTabPage.atleastOneNTPNotificationWasShowed.value = false } - static func migrateAdsConfirmations(for configruation: BraveRewards.Configuration) { - // To ensure after a user launches 1.21 that their ads confirmations, viewed count and - // estimated payout remain correct. - // - // This hack is unfortunately neccessary due to a missed migration path when moving - // confirmations from ledger to ads, we must extract `confirmations.json` out of ledger's - // state file and save it as a new file under the ads directory. - let base = configruation.storageURL - let ledgerStateContainer = base.appendingPathComponent("ledger/random_state.plist") - let adsConfirmations = base.appendingPathComponent("ads/confirmations.json") - let fm = FileManager.default - - if !fm.fileExists(atPath: ledgerStateContainer.path) || fm.fileExists(atPath: adsConfirmations.path) { - // Nothing to migrate or already migrated - return - } - - do { - let contents = NSDictionary(contentsOfFile: ledgerStateContainer.path) - guard let confirmations = contents?["confirmations.json"] as? String else { - adsRewardsLog.debug("No confirmations found to migrate in ledger's state container") - return - } - try confirmations.write(toFile: adsConfirmations.path, atomically: true, encoding: .utf8) - } catch { - adsRewardsLog.error("Failed to migrate confirmations.json to ads folder: \(error.localizedDescription)") - } - } - private func loadNewTabWithRewardsURL(_ url: URL) { self.presentedViewController?.dismiss(animated: true) @@ -148,7 +119,7 @@ extension BrowserViewController { tabManager.selectTab(tab) } else { let request = URLRequest(url: url) - let isPrivate = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivate = privateBrowsingManager.isPrivateBrowsing tabManager.addTabAndSelect(request, isPrivate: isPrivate) } } @@ -214,7 +185,7 @@ extension BrowserViewController { extension Tab { func reportPageLoad(to rewards: BraveRewards, redirectionURLs urls: [URL]) { guard let webView = webView, let url = webView.url else { return } - if url.isLocal || PrivateBrowsingManager.shared.isPrivateBrowsing { return } + if url.isLocal || self.isPrivate { return } var htmlBlob: String? var classifierText: String? diff --git a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Callout.swift b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Callout.swift index d57c3597bda..16f29690560 100644 --- a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Callout.swift +++ b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Callout.swift @@ -260,7 +260,7 @@ extension BrowserViewController { var linkReceiptView = OnboardingLinkReceiptView() linkReceiptView.linkReceiptAction = { - self.openURLInNewTab(.brave.braveVPNLinkReceiptProd, isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing, isPrivileged: false) + self.openURLInNewTab(.brave.braveVPNLinkReceiptProd, isPrivate: self.privateBrowsingManager.isPrivateBrowsing, isPrivileged: false) } let popup = PopupViewController(rootView: linkReceiptView, isDismissable: true) isOnboardingOrFullScreenCalloutPresented = true diff --git a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+KeyCommands.swift b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+KeyCommands.swift index 327f3ecde3c..37937a06d9e 100644 --- a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+KeyCommands.swift +++ b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+KeyCommands.swift @@ -43,7 +43,7 @@ extension BrowserViewController { } @objc private func newTabKeyCommand() { - openBlankNewTab(attemptLocationFieldFocus: false, isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing) + openBlankNewTab(attemptLocationFieldFocus: false, isPrivate: privateBrowsingManager.isPrivateBrowsing) } @objc private func newPrivateTabKeyCommand() { @@ -211,7 +211,7 @@ extension BrowserViewController { UIKeyCommand(title: Strings.Hotkey.newPrivateTabTitle, action: #selector(newPrivateTabKeyCommand), input: "n", modifierFlags: [.command, .shift]), ] - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !privateBrowsingManager.isPrivateBrowsing { navigationCommands += [ UIKeyCommand(title: Strings.Hotkey.recentlyClosedTabTitle, action: #selector(reopenRecentlyClosedTabCommand), input: "t", modifierFlags: [.command, .shift]) ] diff --git a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Menu.swift b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Menu.swift index b9ee075ee51..100183d0266 100644 --- a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Menu.swift +++ b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Menu.swift @@ -31,7 +31,8 @@ extension BrowserViewController { }, displayAlert: { [unowned menuController] alert in menuController.present(alert, animated: true) }, openURL: { [weak self] url in - self?.openURLInNewTab(url, isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing, + guard let self = self else { return } + self.openURLInNewTab(url, isPrivate: self.privateBrowsingManager.isPrivateBrowsing, isPrivileged: false) }) @@ -69,7 +70,7 @@ extension BrowserViewController { self.present(alert, animated: true) }, openURL: { [unowned self] url in self.openURLInNewTab(url, - isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing, + isPrivate: self.privateBrowsingManager.isPrivateBrowsing, isPrivileged: false) } ) @@ -89,7 +90,7 @@ extension BrowserViewController { } // Add Brave Talk and News options only in normal browsing - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !privateBrowsingManager.isPrivateBrowsing { // Show Brave News if it is first launch and after first launch If the new is enabled if Preferences.General.isFirstLaunch.value || (!Preferences.General.isFirstLaunch.value && Preferences.BraveNews.isEnabled.value) { MenuItemFactory.button(for: .news) { [weak self] in @@ -124,13 +125,13 @@ extension BrowserViewController { let vc = BookmarksViewController( folder: bookmarkManager.lastVisitedFolder(), bookmarkManager: bookmarkManager, - isPrivateBrowsing: PrivateBrowsingManager.shared.isPrivateBrowsing) + isPrivateBrowsing: privateBrowsingManager.isPrivateBrowsing) vc.toolbarUrlActionsDelegate = self menuController.presentInnerMenu(vc) } MenuItemFactory.button(for: .history) { [unowned self, unowned menuController] in let vc = HistoryViewController( - isPrivateBrowsing: PrivateBrowsingManager.shared.isPrivateBrowsing, + isPrivateBrowsing: privateBrowsingManager.isPrivateBrowsing, historyAPI: self.braveCore.historyAPI, tabManager: self.tabManager) vc.toolbarUrlActionsDelegate = self @@ -154,7 +155,7 @@ extension BrowserViewController { } } MenuItemFactory.button(for: .settings) { [unowned self, unowned menuController] in - let isPrivateMode = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivateMode = privateBrowsingManager.isPrivateBrowsing let keyringService = BraveWallet.KeyringServiceFactory.get(privateMode: isPrivateMode) let walletService = BraveWallet.ServiceFactory.get(privateMode: isPrivateMode) let rpcService = BraveWallet.JsonRpcServiceFactory.get(privateMode: isPrivateMode) diff --git a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Onboarding.swift b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Onboarding.swift index 163b3487dec..0ddd471629f 100644 --- a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Onboarding.swift +++ b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Onboarding.swift @@ -49,7 +49,7 @@ extension BrowserViewController { tabManager.addTab( PrivilegedRequest(url: url) as URLRequest, afterTab: self.tabManager.selectedTab, - isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing) + isPrivate: privateBrowsingManager.isPrivateBrowsing) } } @@ -105,7 +105,7 @@ extension BrowserViewController { } private func showPrivacyReportsOnboardingIfNeeded() { - if Preferences.PrivacyReports.ntpOnboardingCompleted.value || PrivateBrowsingManager.shared.isPrivateBrowsing { + if Preferences.PrivacyReports.ntpOnboardingCompleted.value || privateBrowsingManager.isPrivateBrowsing { return } diff --git a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+TabManagerDelegate.swift b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+TabManagerDelegate.swift index ca1630fb244..758f6ad15bd 100644 --- a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+TabManagerDelegate.swift +++ b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+TabManagerDelegate.swift @@ -167,7 +167,7 @@ extension BrowserViewController: TabManagerDelegate { topToolbar.leaveOverlayMode(didCancel: true) updateTabsBarVisibility() - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !privateBrowsingManager.isPrivateBrowsing { rewards.reportTabClosed(tabId: Int(tab.rewardsId)) } } @@ -200,7 +200,7 @@ extension BrowserViewController: TabManagerDelegate { } func tabManagerDidRemoveAllTabs(_ tabManager: TabManager, toast: ButtonToast?) { - guard let toast = toast, !PrivateBrowsingManager.shared.isPrivateBrowsing else { + guard let toast = toast, !privateBrowsingManager.isPrivateBrowsing else { return } show(toast: toast, afterWaiting: ButtonToastUX.toastDelay) @@ -216,7 +216,7 @@ extension BrowserViewController: TabManagerDelegate { var newTabMenuChildren: [UIAction] = [] var addTabMenuChildren: [UIAction] = [] - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !privateBrowsingManager.isPrivateBrowsing { let openNewPrivateTab = UIAction( title: Strings.Hotkey.newPrivateTabTitle, image: UIImage(systemName: "plus.square.fill.on.square.fill"), @@ -232,10 +232,10 @@ extension BrowserViewController: TabManagerDelegate { } let openNewTab = UIAction( - title: PrivateBrowsingManager.shared.isPrivateBrowsing ? Strings.Hotkey.newPrivateTabTitle : Strings.Hotkey.newTabTitle, - image: PrivateBrowsingManager.shared.isPrivateBrowsing ? UIImage(systemName: "plus.square.fill.on.square.fill") : UIImage(systemName: "plus.square.on.square"), + title: privateBrowsingManager.isPrivateBrowsing ? Strings.Hotkey.newPrivateTabTitle : Strings.Hotkey.newTabTitle, + image: privateBrowsingManager.isPrivateBrowsing ? UIImage(systemName: "plus.square.fill.on.square.fill") : UIImage(systemName: "plus.square.on.square"), handler: UIAction.deferredActionHandler { [unowned self] _ in - self.openBlankNewTab(attemptLocationFieldFocus: false, isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing) + self.openBlankNewTab(attemptLocationFieldFocus: false, isPrivate: privateBrowsingManager.isPrivateBrowsing) }) if (UIDevice.current.userInterfaceIdiom == .pad && tabsBar.view.isHidden) || (UIDevice.current.userInterfaceIdiom == .phone && toolbar == nil) { @@ -244,7 +244,7 @@ extension BrowserViewController: TabManagerDelegate { addTabMenuChildren.append(openNewTab) addTabMenuChildren.append(UIAction(title: "New Window", image: UIImage(systemName: "window.horizontal.closed"), handler: UIAction.deferredActionHandler { [unowned self] _ in - self.tabsBarDidSelectAddNewWindow(PrivateBrowsingManager.shared.isPrivateBrowsing) + self.tabsBarDidSelectAddNewWindow(privateBrowsingManager.isPrivateBrowsing) })) var bookmarkMenuChildren: [UIAction] = [] @@ -268,7 +268,7 @@ extension BrowserViewController: TabManagerDelegate { image: UIImage(systemName: "book"), handler: UIAction.deferredActionHandler { [unowned self] _ in let mode = BookmarkEditMode.addFolderUsingTabs(title: Strings.savedTabsFolderTitle, tabList: tabManager.tabsForCurrentMode) - let addBookMarkController = AddEditBookmarkTableViewController(bookmarkManager: bookmarkManager, mode: mode) + let addBookMarkController = AddEditBookmarkTableViewController(bookmarkManager: bookmarkManager, mode: mode, isPrivateBrowsing: privateBrowsingManager.isPrivateBrowsing) presentSettingsNavigation(with: addBookMarkController, cancelEnabled: true) }) @@ -297,14 +297,14 @@ extension BrowserViewController: TabManagerDelegate { var recentlyClosedMenuChildren: [UIAction] = [] - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !privateBrowsingManager.isPrivateBrowsing { let recentlyClosedTab = UIAction( title: Strings.RecentlyClosed.viewRecentlyClosedTab, image: UIImage(braveSystemNamed: "leo.browser.mobile-recent-tabs"), handler: UIAction.deferredActionHandler { [weak self] _ in guard let self = self else { return } - if PrivateBrowsingManager.shared.isPrivateBrowsing { + if privateBrowsingManager.isPrivateBrowsing { return } @@ -353,7 +353,7 @@ extension BrowserViewController: TabManagerDelegate { let cancelAction = UIAlertAction(title: Strings.CancelString, style: .cancel) let closedTabsTitle = String(format: Strings.closeAllTabsTitle, tabManager.tabsForCurrentMode.count) let closeAllAction = UIAlertAction(title: closedTabsTitle, style: .destructive) { _ in - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !privateBrowsingManager.isPrivateBrowsing { // Add the tab information to recently closed before removing tabManager.addAllTabsToRecentlyClosed() } diff --git a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+ToolbarDelegate.swift b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+ToolbarDelegate.swift index 1d723a6cac8..59b7192a798 100644 --- a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+ToolbarDelegate.swift +++ b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+ToolbarDelegate.swift @@ -258,7 +258,8 @@ extension BrowserViewController: TopToolbarDelegate { if let url = searchURL, InternalURL.isValid(url: url) { searchURL = url } - if let query = profile.searchEngines.queryForSearchURL(searchURL as URL?) { + if let query = profile.searchEngines.queryForSearchURL(searchURL as URL?, + forType: privateBrowsingManager.isPrivateBrowsing ? .privateMode : .standard) { return (query, true) } else { return (topToolbar?.absoluteString, false) @@ -302,7 +303,7 @@ extension BrowserViewController: TopToolbarDelegate { // We couldn't build a URL, so pass it on to the search engine. submitSearchText(text, isBraveSearchPromotion: isBraveSearchPromotion) - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !privateBrowsingManager.isPrivateBrowsing { RecentSearch.addItem(type: .text, text: text, websiteUrl: nil) } } @@ -311,7 +312,7 @@ extension BrowserViewController: TopToolbarDelegate { @discardableResult func handleIPFSSchemeURL(_ url: URL, visitType: VisitType) -> Bool { - guard !PrivateBrowsingManager.shared.isPrivateBrowsing else { + guard !privateBrowsingManager.isPrivateBrowsing else { topToolbar.leaveOverlayMode() if let errorPageHelper = tabManager.selectedTab?.getContentScript(name: ErrorPageHelper.scriptName) as? ErrorPageHelper, let webView = tabManager.selectedTab?.webView { errorPageHelper.loadPage(IPFSErrorPageHandler.privateModeError, forUrl: url, inWebView: webView) @@ -384,7 +385,7 @@ extension BrowserViewController: TopToolbarDelegate { } func submitSearchText(_ text: String, isBraveSearchPromotion: Bool = false) { - var engine = profile.searchEngines.defaultEngine() + var engine = profile.searchEngines.defaultEngine(forType: privateBrowsingManager.isPrivateBrowsing ? .privateMode : .standard) if isBraveSearchPromotion { let braveSearchEngine = profile.searchEngines.orderedEngines.first { @@ -717,7 +718,7 @@ extension BrowserViewController: TopToolbarDelegate { let mode = BookmarkEditMode.addBookmark(title: selectedTab.displayTitle, url: bookmarkUrl.absoluteString) - let addBookMarkController = AddEditBookmarkTableViewController(bookmarkManager: bookmarkManager, mode: mode) + let addBookMarkController = AddEditBookmarkTableViewController(bookmarkManager: bookmarkManager, mode: mode, isPrivateBrowsing: privateBrowsingManager.isPrivateBrowsing) presentSettingsNavigation(with: addBookMarkController, cancelEnabled: true) } @@ -808,7 +809,7 @@ extension BrowserViewController: ToolbarDelegate { } func tabToolbarDidPressAddTab(_ tabToolbar: ToolbarProtocol, button: UIButton) { - self.openBlankNewTab(attemptLocationFieldFocus: false, isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing) + self.openBlankNewTab(attemptLocationFieldFocus: false, isPrivate: privateBrowsingManager.isPrivateBrowsing) } func tabToolbarDidLongPressForward(_ tabToolbar: ToolbarProtocol, button: UIButton) { diff --git a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+WKNavigationDelegate.swift b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+WKNavigationDelegate.swift index be1733c1d2a..307e074b482 100644 --- a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+WKNavigationDelegate.swift +++ b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+WKNavigationDelegate.swift @@ -241,7 +241,7 @@ extension BrowserViewController: WKNavigationDelegate { } } - let isPrivateBrowsing = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivateBrowsing = privateBrowsingManager.isPrivateBrowsing // Website redirection logic if url.isWebPage(includeDataURIs: false), @@ -440,7 +440,7 @@ extension BrowserViewController: WKNavigationDelegate { @MainActor public func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse) async -> WKNavigationResponsePolicy { - let isPrivateBrowsing = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivateBrowsing = privateBrowsingManager.isPrivateBrowsing let response = navigationResponse.response let responseURL = response.url let tab = tab(for: webView) @@ -687,7 +687,7 @@ extension BrowserViewController: WKNavigationDelegate { tab: tab, url: url, isSelected: tabManager.selectedTab == tab, - isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing + isPrivate: privateBrowsingManager.isPrivateBrowsing ) } @@ -1079,7 +1079,7 @@ extension BrowserViewController: WKUIDelegate { fileprivate func addTab(url: URL, inPrivateMode: Bool, currentTab: Tab) { let tab = self.tabManager.addTab(URLRequest(url: url), afterTab: currentTab, isPrivate: inPrivateMode) - if inPrivateMode && !PrivateBrowsingManager.shared.isPrivateBrowsing { + if inPrivateMode && !privateBrowsingManager.isPrivateBrowsing { self.tabManager.selectTab(tab) } else { // We're not showing the top tabs; show a toast to quick switch to the fresh new tab. diff --git a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Wallet.swift b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Wallet.swift index bd12a21313f..99f2c7a04b9 100644 --- a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Wallet.swift +++ b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Wallet.swift @@ -80,7 +80,7 @@ extension BrowserViewController { /// Initializes a new WalletStore for displaying the wallet, setting up an observer to notify /// when the pending request is updated so we can update the wallet url bar button. func newWalletStore() -> WalletStore? { - let privateMode = PrivateBrowsingManager.shared.isPrivateBrowsing + let privateMode = privateBrowsingManager.isPrivateBrowsing guard let walletStore = WalletStore.from(ipfsApi: braveCore.ipfsAPI, privateMode: privateMode) else { Logger.module.error("Failed to load wallet. One or more services were unavailable") return nil @@ -135,7 +135,7 @@ extension BrowserViewController: BraveWalletDelegate { } else { _ = tabManager.addTabAndSelect( URLRequest(url: destinationURL), - isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing + isPrivate: privateBrowsingManager.isPrivateBrowsing ) } } @@ -194,7 +194,7 @@ extension Tab: BraveWalletProviderDelegate { return } - let isPrivate = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivate = self.isPrivate // Check if eth permissions already exist for this origin and if they don't, ensure the user allows // ethereum/solana provider access @@ -340,7 +340,7 @@ extension Tab: BraveWalletProviderDelegate { } func showAccountCreation(_ coin: BraveWallet.CoinType) { - let privateMode = PrivateBrowsingManager.shared.isPrivateBrowsing + let privateMode = self.isPrivate guard let keyringService = BraveWallet.KeyringServiceFactory.get(privateMode: privateMode) else { return } diff --git a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Web3NameService.swift b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Web3NameService.swift index e199d8266f5..ceaf7452087 100644 --- a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Web3NameService.swift +++ b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+Web3NameService.swift @@ -11,7 +11,7 @@ import BraveCore extension BrowserViewController: Web3NameServiceScriptHandlerDelegate { /// Returns a `DecentralizedDNSHelper` for the given mode if supported and not in private mode. func decentralizedDNSHelperFor(url: URL?) -> DecentralizedDNSHelper? { - let isPrivateMode = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivateMode = privateBrowsingManager.isPrivateBrowsing guard !isPrivateMode, let url, DecentralizedDNSHelper.isSupported(domain: url.domainURL.schemelessAbsoluteDisplayString), @@ -24,7 +24,7 @@ extension BrowserViewController: Web3NameServiceScriptHandlerDelegate { } func web3NameServiceDecisionHandler(_ proceed: Bool, web3Service: Web3Service, originalURL: URL, visitType: VisitType) { - let isPrivateMode = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivateMode = privateBrowsingManager.isPrivateBrowsing guard let rpcService = BraveWallet.JsonRpcServiceFactory.get(privateMode: isPrivateMode), let decentralizedDNSHelper = self.decentralizedDNSHelperFor(url: originalURL) else { finishEditingAndSubmit(originalURL, visitType: visitType) diff --git a/Sources/Brave/Frontend/Browser/Favicons/LargeFaviconView.swift b/Sources/Brave/Frontend/Browser/Favicons/LargeFaviconView.swift index 07423220ee3..452f58685de 100644 --- a/Sources/Brave/Frontend/Browser/Favicons/LargeFaviconView.swift +++ b/Sources/Brave/Frontend/Browser/Favicons/LargeFaviconView.swift @@ -16,7 +16,7 @@ struct FaviconUX { /// Displays a large favicon given some favorite class LargeFaviconView: UIView { - func loadFavicon(siteURL: URL, monogramFallbackCharacter: Character? = nil) { + func loadFavicon(siteURL: URL, isPrivateBrowsing: Bool, monogramFallbackCharacter: Character? = nil) { faviconTask?.cancel() if let favicon = FaviconFetcher.getIconFromCache(for: siteURL) { faviconTask = nil @@ -34,7 +34,7 @@ class LargeFaviconView: UIView { } faviconTask = Task { @MainActor in - let isPersistent = !PrivateBrowsingManager.shared.isPrivateBrowsing + let isPersistent = !isPrivateBrowsing do { let favicon = try await FaviconFetcher.loadIcon(url: siteURL, kind: .largeIcon, diff --git a/Sources/Brave/Frontend/Browser/Favicons/UIImageView+Favicon.swift b/Sources/Brave/Frontend/Browser/Favicons/UIImageView+Favicon.swift index f960640a926..777340447de 100644 --- a/Sources/Brave/Frontend/Browser/Favicons/UIImageView+Favicon.swift +++ b/Sources/Brave/Frontend/Browser/Favicons/UIImageView+Favicon.swift @@ -28,7 +28,7 @@ extension UIImageView { /// Load the favicon from a site URL directly into a `UIImageView`. If no /// favicon is found, a monogram will be used where the letter is determined /// based on the site URL. - func loadFavicon(for siteURL: URL, monogramFallbackCharacter: Character? = nil, completion: ((Favicon?) -> Void)? = nil) { + func loadFavicon(for siteURL: URL, isPrivateBrowsing: Bool, monogramFallbackCharacter: Character? = nil, completion: ((Favicon?) -> Void)? = nil) { cancelFaviconLoad() if let icon = FaviconFetcher.getIconFromCache(for: siteURL) { @@ -39,7 +39,7 @@ extension UIImageView { self.image = Favicon.defaultImage faviconTask = Task { @MainActor in do { - let favicon = try await FaviconFetcher.loadIcon(url: siteURL, persistent: !PrivateBrowsingManager.shared.isPrivateBrowsing) + let favicon = try await FaviconFetcher.loadIcon(url: siteURL, persistent: !isPrivateBrowsing) self.image = favicon.image ?? Favicon.defaultImage completion?(favicon) } catch { diff --git a/Sources/Brave/Frontend/Browser/Favorites/FavoritesViewController.swift b/Sources/Brave/Frontend/Browser/Favorites/FavoritesViewController.swift index af957c4525a..bae22c84e12 100644 --- a/Sources/Brave/Frontend/Browser/Favorites/FavoritesViewController.swift +++ b/Sources/Brave/Frontend/Browser/Favorites/FavoritesViewController.swift @@ -94,11 +94,13 @@ class FavoritesViewController: UIViewController { $0.contentView.backgroundColor = UIColor.braveBackground.withAlphaComponent(0.5) } private var hasPasteboardURL = false + private var isPrivateBrowsing: Bool init(tabType: TabType, action: @escaping (Favorite, BookmarksAction) -> Void, recentSearchAction: @escaping (RecentSearch?, Bool) -> Void) { self.tabType = tabType self.action = action self.recentSearchAction = recentSearchAction + self.isPrivateBrowsing = tabType.isPrivate collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) super.init(nibName: nil, bundle: nil) @@ -352,7 +354,7 @@ extension FavoritesViewController: UICollectionViewDelegateFlowLayout { }) var urlChildren: [UIAction] = [openInNewTab] - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !self.isPrivateBrowsing { let openInNewPrivateTab = UIAction( title: Strings.openNewPrivateTabButtonTitle, handler: UIAction.deferredActionHandler { _ in @@ -668,7 +670,7 @@ extension FavoritesViewController: NSFetchedResultsControllerDelegate { cell.textLabel.text = favorite.displayTitle ?? favorite.url if let url = favorite.url?.asURL { - cell.imageView.loadFavicon(siteURL: url) + cell.imageView.loadFavicon(siteURL: url, isPrivateBrowsing: self.isPrivateBrowsing) } cell.accessibilityLabel = cell.textLabel.text diff --git a/Sources/Brave/Frontend/Browser/FrequencyQuery.swift b/Sources/Brave/Frontend/Browser/FrequencyQuery.swift index 66102bd4c41..024aa17e974 100644 --- a/Sources/Brave/Frontend/Browser/FrequencyQuery.swift +++ b/Sources/Brave/Frontend/Browser/FrequencyQuery.swift @@ -79,7 +79,7 @@ class FrequencyQuery { var tabList = [Site]() for tab in tabs { - if PrivateBrowsingManager.shared.isPrivateBrowsing { + if tab.isPrivate { if let url = tab.url, url.isWebPage(), !(InternalURL(url)?.isAboutHomeURL ?? false) { if let selectedTabID = tabManager.selectedTab?.id, selectedTabID == tab.id { continue diff --git a/Sources/Brave/Frontend/Browser/Helpers/BrowserNavigationHelper.swift b/Sources/Brave/Frontend/Browser/Helpers/BrowserNavigationHelper.swift index c4a49aca3cd..8d8e4e9c9ca 100644 --- a/Sources/Brave/Frontend/Browser/Helpers/BrowserNavigationHelper.swift +++ b/Sources/Brave/Frontend/Browser/Helpers/BrowserNavigationHelper.swift @@ -45,7 +45,7 @@ class BrowserNavigationHelper { let vc = BookmarksViewController( folder: bvc.bookmarkManager.lastVisitedFolder(), bookmarkManager: bvc.bookmarkManager, - isPrivateBrowsing: PrivateBrowsingManager.shared.isPrivateBrowsing) + isPrivateBrowsing: bvc.privateBrowsingManager.isPrivateBrowsing) vc.toolbarUrlActionsDelegate = bvc open(vc, doneButton: DoneButton(style: .done, position: .right)) @@ -58,7 +58,7 @@ class BrowserNavigationHelper { func openHistory() { guard let bvc = bvc else { return } let vc = HistoryViewController( - isPrivateBrowsing: PrivateBrowsingManager.shared.isPrivateBrowsing, + isPrivateBrowsing: bvc.privateBrowsingManager.isPrivateBrowsing, historyAPI: bvc.braveCore.historyAPI, tabManager: bvc.tabManager) vc.toolbarUrlActionsDelegate = bvc diff --git a/Sources/Brave/Frontend/Browser/Helpers/FaviconImage.swift b/Sources/Brave/Frontend/Browser/Helpers/FaviconImage.swift index 7b842d320a7..1ac8a31584d 100644 --- a/Sources/Brave/Frontend/Browser/Helpers/FaviconImage.swift +++ b/Sources/Brave/Frontend/Browser/Helpers/FaviconImage.swift @@ -14,10 +14,10 @@ private class FaviconHelper: ObservableObject { @Published var image: UIImage? private var faviconTask: Task? - func load(url: URL) { + func load(url: URL, isPrivateBrowsing: Bool) { faviconTask?.cancel() faviconTask = Task { @MainActor in - let favicon = try await FaviconFetcher.loadIcon(url: url, persistent: !PrivateBrowsingManager.shared.isPrivateBrowsing) + let favicon = try await FaviconFetcher.loadIcon(url: url, persistent: !isPrivateBrowsing) self.image = favicon.image } } @@ -25,9 +25,12 @@ private class FaviconHelper: ObservableObject { struct FaviconImage: View { let url: URL? + private let isPrivateBrowsing: Bool @StateObject private var faviconLoader = FaviconHelper() - init(url: String?) { + init(url: String?, isPrivateBrowsing: Bool) { + self.isPrivateBrowsing = isPrivateBrowsing + if let url = url { self.url = URL(string: url) } else { @@ -43,7 +46,7 @@ struct FaviconImage: View { .clipShape(RoundedRectangle(cornerRadius: 10, style: .continuous)) .onAppear { if let url = url { - faviconLoader.load(url: url) + faviconLoader.load(url: url, isPrivateBrowsing: isPrivateBrowsing) } } } diff --git a/Sources/Brave/Frontend/Browser/HomePanel/NTPDataSource.swift b/Sources/Brave/Frontend/Browser/HomePanel/NTPDataSource.swift index 3f6f0c36f54..7486a7cbab8 100644 --- a/Sources/Brave/Frontend/Browser/HomePanel/NTPDataSource.swift +++ b/Sources/Brave/Frontend/Browser/HomePanel/NTPDataSource.swift @@ -9,6 +9,8 @@ import BraveCore import os.log public class NTPDataSource { + + var privateBrowsingManager: PrivateBrowsingManager var initializeFavorites: ((_ sites: [CustomTheme.TopSite]?) -> Void)? @@ -55,7 +57,8 @@ public class NTPDataSource { } }() - public init() { + public init(privateBrowsingManager: PrivateBrowsingManager) { + self.privateBrowsingManager = privateBrowsingManager downloader.delegate = self Preferences.NewTabPage.backgroundSponsoredImages.observe(from: self) @@ -121,7 +124,7 @@ public class NTPDataSource { let attemptSponsored = Preferences.NewTabPage.backgroundSponsoredImages.value && backgroundRotationCounter == NTPDataSource.sponsorshipShowValue - && !PrivateBrowsingManager.shared.isPrivateBrowsing + && !privateBrowsingManager.isPrivateBrowsing if attemptSponsored { // Pick the campaign randomly diff --git a/Sources/Brave/Frontend/Browser/LinkPreviewViewController.swift b/Sources/Brave/Frontend/Browser/LinkPreviewViewController.swift index 4292226662b..aaa1afb1798 100644 --- a/Sources/Brave/Frontend/Browser/LinkPreviewViewController.swift +++ b/Sources/Brave/Frontend/Browser/LinkPreviewViewController.swift @@ -45,7 +45,7 @@ class LinkPreviewViewController: UIViewController { } // Add rule lists for this page - let domain = Domain.getOrCreate(forUrl: url, persistent: !PrivateBrowsingManager.shared.isPrivateBrowsing) + let domain = Domain.getOrCreate(forUrl: url, persistent: !currentTab.isPrivate) Task(priority: .userInitiated) { let ruleLists = await ContentBlockerManager.shared.ruleLists(for: domain) diff --git a/Sources/Brave/Frontend/Browser/NavigationRouter.swift b/Sources/Brave/Frontend/Browser/NavigationRouter.swift index 37e8834dbf9..4ea3edc0f1a 100644 --- a/Sources/Brave/Frontend/Browser/NavigationRouter.swift +++ b/Sources/Brave/Frontend/Browser/NavigationRouter.swift @@ -21,10 +21,10 @@ public enum NavigationPath: Equatable { case text(String) case widgetShortcutURL(WidgetShortcut) - public init?(url: URL) { + public init?(url: URL, isPrivateBrowsing: Bool) { let urlString = url.absoluteString if url.scheme == "http" || url.scheme == "https" || url.isIPFSScheme { - self = .url(webURL: url, isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing) + self = .url(webURL: url, isPrivate: isPrivateBrowsing) return } @@ -48,7 +48,7 @@ public enum NavigationPath: Equatable { } else if urlString.starts(with: "\(scheme)://open-url") { let urlText = components.valueForQuery("url") let url = URIFixup.getURL(urlText ?? "") ?? urlText?.asURL - let forcedPrivate = Preferences.Privacy.privateBrowsingOnly.value || PrivateBrowsingManager.shared.isPrivateBrowsing + let forcedPrivate = Preferences.Privacy.privateBrowsingOnly.value || isPrivateBrowsing let isPrivate = Bool(components.valueForQuery("private") ?? "") ?? forcedPrivate self = .url(webURL: url, isPrivate: isPrivate) } else if urlString.starts(with: "\(scheme)://open-text") { @@ -95,7 +95,7 @@ public enum NavigationPath: Equatable { private static func handleText(text: String, with bvc: BrowserViewController) { bvc.openBlankNewTab( attemptLocationFieldFocus: true, - isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing, + isPrivate: bvc.privateBrowsingManager.isPrivateBrowsing, searchFor: text) } @@ -106,10 +106,10 @@ public enum NavigationPath: Equatable { if let url = bvc.tabManager.selectedTab?.url, InternalURL(url)?.isAboutHomeURL == true { bvc.focusURLBar() } else { - bvc.openBlankNewTab(attemptLocationFieldFocus: true, isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing) + bvc.openBlankNewTab(attemptLocationFieldFocus: true, isPrivate: bvc.privateBrowsingManager.isPrivateBrowsing) } case .newTab: - bvc.openBlankNewTab(attemptLocationFieldFocus: false, isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing) + bvc.openBlankNewTab(attemptLocationFieldFocus: false, isPrivate: bvc.privateBrowsingManager.isPrivateBrowsing) case .newPrivateTab: bvc.openBlankNewTab(attemptLocationFieldFocus: false, isPrivate: true) case .bookmarks: diff --git a/Sources/Brave/Frontend/Browser/New Tab Page/Backgrounds/NewTabPageBackgroundButtonsView.swift b/Sources/Brave/Frontend/Browser/New Tab Page/Backgrounds/NewTabPageBackgroundButtonsView.swift index 1180683a82c..dde59980f3e 100644 --- a/Sources/Brave/Frontend/Browser/New Tab Page/Backgrounds/NewTabPageBackgroundButtonsView.swift +++ b/Sources/Brave/Frontend/Browser/New Tab Page/Backgrounds/NewTabPageBackgroundButtonsView.swift @@ -76,9 +76,12 @@ class NewTabPageBackgroundButtonsView: UIView, PreferencesObserver { } private var safeAreaInsetsConstraint: Constraint? private let collectionViewSafeAreaLayoutGuide = UILayoutGuide() + private let privateBrowsingManager: PrivateBrowsingManager - override init(frame: CGRect) { - super.init(frame: frame) + init(privateBrowsingManager: PrivateBrowsingManager) { + self.privateBrowsingManager = privateBrowsingManager + + super.init(frame: .zero) Preferences.BraveNews.isEnabled.observe(from: self) @@ -105,7 +108,7 @@ class NewTabPageBackgroundButtonsView: UIView, PreferencesObserver { let isLandscape = frame.width > frame.height let braveNewsVisible = - !PrivateBrowsingManager.shared.isPrivateBrowsing && (Preferences.BraveNews.isEnabled.value || Preferences.BraveNews.isShowingOptIn.value) + !privateBrowsingManager.isPrivateBrowsing && (Preferences.BraveNews.isEnabled.value || Preferences.BraveNews.isShowingOptIn.value) imageCreditButton.snp.remakeConstraints { $0.leading.equalTo(collectionViewSafeAreaLayoutGuide).inset(16) diff --git a/Sources/Brave/Frontend/Browser/New Tab Page/NewTabPageViewController.swift b/Sources/Brave/Frontend/Browser/New Tab Page/NewTabPageViewController.swift index addfbc6f07f..271e8e5368d 100644 --- a/Sources/Brave/Frontend/Browser/New Tab Page/NewTabPageViewController.swift +++ b/Sources/Brave/Frontend/Browser/New Tab Page/NewTabPageViewController.swift @@ -107,7 +107,7 @@ class NewTabPageViewController: UIViewController { private var background: NewTabPageBackground private let backgroundView = NewTabPageBackgroundView() - private let backgroundButtonsView = NewTabPageBackgroundButtonsView() + private let backgroundButtonsView: NewTabPageBackgroundButtonsView /// A gradient to display over background images to ensure visibility of /// the NTP contents and sponsored logo /// @@ -129,17 +129,21 @@ class NewTabPageViewController: UIViewController { private let notifications: NewTabPageNotifications private var cancellables: Set = [] + private let privateBrowsingManager: PrivateBrowsingManager init( tab: Tab, profile: Profile, dataSource: NTPDataSource, feedDataSource: FeedDataSource, - rewards: BraveRewards + rewards: BraveRewards, + privateBrowsingManager: PrivateBrowsingManager ) { self.tab = tab self.rewards = rewards self.feedDataSource = feedDataSource + self.privateBrowsingManager = privateBrowsingManager + self.backgroundButtonsView = NewTabPageBackgroundButtonsView(privateBrowsingManager: privateBrowsingManager) background = NewTabPageBackground(dataSource: dataSource) notifications = NewTabPageNotifications(rewards: rewards) collectionView = NewTabCollectionView(frame: .zero, collectionViewLayout: layout) @@ -149,12 +153,12 @@ class NewTabPageViewController: UIViewController { Preferences.NewTabPage.showNewTabFavourites.observe(from: self) sections = [ - StatsSectionProvider(openPrivacyHubPressed: { [weak self] in - if PrivateBrowsingManager.shared.isPrivateBrowsing { + StatsSectionProvider(isPrivateBrowsing: tab.isPrivate, openPrivacyHubPressed: { [weak self] in + if self?.privateBrowsingManager.isPrivateBrowsing == true { return } - let host = UIHostingController(rootView: PrivacyReportsManager.prepareView()) + let host = UIHostingController(rootView: PrivacyReportsManager.prepareView(isPrivateBrowsing: privateBrowsingManager.isPrivateBrowsing)) host.rootView.onDismiss = { [weak self] in DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { guard let self = self else { return } @@ -183,7 +187,7 @@ class NewTabPageViewController: UIViewController { self?.handleFavoriteAction(favorite: bookmark, action: action) }, legacyLongPressAction: { [weak self] alertController in self?.present(alertController, animated: true) - }), + }, isPrivateBrowsing: privateBrowsingManager.isPrivateBrowsing), FavoritesOverflowSectionProvider(action: { [weak self] in self?.delegate?.focusURLBar() }), @@ -194,7 +198,7 @@ class NewTabPageViewController: UIViewController { sections.insert(NTPDefaultBrowserCalloutProvider(), at: 0) } - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !privateBrowsingManager.isPrivateBrowsing { sections.append( BraveNewsSectionProvider( dataSource: feedDataSource, @@ -462,7 +466,7 @@ class NewTabPageViewController: UIViewController { } private func presentNotification() { - if PrivateBrowsingManager.shared.isPrivateBrowsing || notificationShowing { + if privateBrowsingManager.isPrivateBrowsing || notificationShowing { return } @@ -865,7 +869,7 @@ extension NewTabPageViewController: PreferencesObserver { // MARK: - UIScrollViewDelegate extension NewTabPageViewController { var isBraveNewsVisible: Bool { - return !PrivateBrowsingManager.shared.isPrivateBrowsing && (Preferences.BraveNews.isEnabled.value || Preferences.BraveNews.isShowingOptIn.value) + return !privateBrowsingManager.isPrivateBrowsing && (Preferences.BraveNews.isEnabled.value || Preferences.BraveNews.isShowingOptIn.value) } func scrollViewDidScroll(_ scrollView: UIScrollView) { diff --git a/Sources/Brave/Frontend/Browser/New Tab Page/Sections/BraveNewsSectionProvider.swift b/Sources/Brave/Frontend/Browser/New Tab Page/Sections/BraveNewsSectionProvider.swift index 13daa70e7ce..006bcdcdbdb 100644 --- a/Sources/Brave/Frontend/Browser/New Tab Page/Sections/BraveNewsSectionProvider.swift +++ b/Sources/Brave/Frontend/Browser/New Tab Page/Sections/BraveNewsSectionProvider.swift @@ -415,7 +415,7 @@ class BraveNewsSectionProvider: NSObject, NTPObservableSectionProvider { openInNewTab, // Brave News is only available in normal tabs, so this isn't technically required // but good to be on the safe side - !PrivateBrowsingManager.shared.isPrivateBrowsing ? openInNewPrivateTab : nil, + openInNewPrivateTab, ].compactMap { $0 } let children: [UIMenu] = [ UIMenu(title: "", options: [.displayInline], children: openActions) @@ -472,7 +472,7 @@ class BraveNewsSectionProvider: NSObject, NTPObservableSectionProvider { openInNewTab, // Brave News is only available in normal tabs, so this isn't technically required // but good to be on the safe side - !PrivateBrowsingManager.shared.isPrivateBrowsing ? openInNewPrivateTab : nil, + openInNewPrivateTab, ].compactMap({ $0 }) let manageActions = [ diff --git a/Sources/Brave/Frontend/Browser/New Tab Page/Sections/FavoritesSectionProvider.swift b/Sources/Brave/Frontend/Browser/New Tab Page/Sections/FavoritesSectionProvider.swift index 395acda66f4..a91887ed723 100644 --- a/Sources/Brave/Frontend/Browser/New Tab Page/Sections/FavoritesSectionProvider.swift +++ b/Sources/Brave/Frontend/Browser/New Tab Page/Sections/FavoritesSectionProvider.swift @@ -21,6 +21,8 @@ class FavoritesSectionProvider: NSObject, NTPObservableSectionProvider { var sectionDidChange: (() -> Void)? var action: (Favorite, BookmarksAction) -> Void var legacyLongPressAction: (UIAlertController) -> Void + + private let isPrivateBrowsing: Bool var hasMoreThanOneFavouriteItems: Bool { frc.fetchedObjects?.count ?? 0 > 0 @@ -30,10 +32,12 @@ class FavoritesSectionProvider: NSObject, NTPObservableSectionProvider { init( action: @escaping (Favorite, BookmarksAction) -> Void, - legacyLongPressAction: @escaping (UIAlertController) -> Void + legacyLongPressAction: @escaping (UIAlertController) -> Void, + isPrivateBrowsing: Bool ) { self.action = action self.legacyLongPressAction = legacyLongPressAction + self.isPrivateBrowsing = isPrivateBrowsing frc = Favorite.frc() super.init() @@ -110,7 +114,7 @@ class FavoritesSectionProvider: NSObject, NTPObservableSectionProvider { cell.imageView.cancelLoading() if let url = fav.url?.asURL { - cell.imageView.loadFavicon(siteURL: url) + cell.imageView.loadFavicon(siteURL: url, isPrivateBrowsing: isPrivateBrowsing) } cell.accessibilityLabel = cell.textLabel.text } @@ -174,7 +178,7 @@ class FavoritesSectionProvider: NSObject, NTPObservableSectionProvider { }) var urlChildren: [UIAction] = [openInNewTab] - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !self.isPrivateBrowsing { let openInNewPrivateTab = UIAction( title: Strings.openNewPrivateTabButtonTitle, handler: UIAction.deferredActionHandler { _ in diff --git a/Sources/Brave/Frontend/Browser/New Tab Page/Sections/StatsSectionProvider.swift b/Sources/Brave/Frontend/Browser/New Tab Page/Sections/StatsSectionProvider.swift index e6539d70c6b..0e1443fcc9f 100644 --- a/Sources/Brave/Frontend/Browser/New Tab Page/Sections/StatsSectionProvider.swift +++ b/Sources/Brave/Frontend/Browser/New Tab Page/Sections/StatsSectionProvider.swift @@ -12,10 +12,12 @@ import BraveUI import UIKit class StatsSectionProvider: NSObject, NTPSectionProvider { + private let isPrivateBrowsing: Bool var openPrivacyHubPressed: () -> Void var hidePrivacyHubPressed: () -> Void - init(openPrivacyHubPressed: @escaping () -> Void, hidePrivacyHubPressed: @escaping () -> Void) { + init(isPrivateBrowsing: Bool, openPrivacyHubPressed: @escaping () -> Void, hidePrivacyHubPressed: @escaping () -> Void) { + self.isPrivateBrowsing = isPrivateBrowsing self.openPrivacyHubPressed = openPrivacyHubPressed self.hidePrivacyHubPressed = hidePrivacyHubPressed } @@ -48,6 +50,7 @@ class StatsSectionProvider: NSObject, NTPSectionProvider { let longPress = UILongPressGestureRecognizer(target: self, action: #selector(tappedButton(_:))) cell.view.do { + $0.isPrivateBrowsing = self.isPrivateBrowsing $0.addGestureRecognizer(tap) $0.addGestureRecognizer(longPress) @@ -147,45 +150,10 @@ class BraveShieldStatsView: SpringButton { }() } + private let background = UIView() + override init(frame: CGRect) { - super.init(frame: frame) - - if !PrivateBrowsingManager.shared.isPrivateBrowsing, Preferences.NewTabPage.showNewTabPrivacyHub.value { - let background = UIView() - background.backgroundColor = .init(white: 0, alpha: 0.25) - background.layer.cornerRadius = 12 - background.layer.cornerCurve = .continuous - background.isUserInteractionEnabled = false - insertSubview(background, at: 0) - background.snp.makeConstraints { - $0.edges.equalToSuperview() - } - - let settingsButton = BraveButton(type: .system).then { - $0.setImage(UIImage(named: "privacy_reports_3dots", in: .module, compatibleWith: nil)!.template, for: .normal) - $0.tintColor = .white - $0.hitTestSlop = UIEdgeInsets(equalInset: -25) - } - - let hidePrivacyHub = UIAction( - title: Strings.PrivacyHub.hidePrivacyHubWidgetActionTitle, - image: UIImage(braveSystemNamed: "leo.eye.off"), - handler: UIAction.deferredActionHandler { [unowned self] _ in - self.hidePrivacyHubPressed?() - }) - - let showPrivacyHub = UIAction( - title: Strings.PrivacyHub.openPrivacyHubWidgetActionTitle, - image: UIImage(named: "privacy_reports_shield", in: .module, compatibleWith: nil)?.template, - handler: UIAction.deferredActionHandler { [unowned self] _ in - self.openPrivacyHubPressed?() - }) - - settingsButton.menu = UIMenu(title: "", options: .displayInline, children: [hidePrivacyHub, showPrivacyHub]) - settingsButton.showsMenuAsPrimaryAction = true - - topStackView.addStackViewItems(.view(privacyReportLabel), .view(settingsButton)) - } + super.init(frame: .zero) statsStackView.addStackViewItems(.view(adsStatView), .view(dataSavedStatView), .view(timeStatView)) contentStackView.addStackViewItems(.view(topStackView), .view(statsStackView)) @@ -205,6 +173,59 @@ class BraveShieldStatsView: SpringButton { fatalError("init(coder:) has not been implemented") } + private var _isPrivateBrowsing: Bool = false + + var isPrivateBrowsing: Bool = false { + didSet { + if _isPrivateBrowsing == isPrivateBrowsing { + return + } + + _isPrivateBrowsing = isPrivateBrowsing + + if isPrivateBrowsing { + background.removeFromSuperview() + topStackView.arrangedSubviews.forEach { + $0.removeFromSuperview() + } + } else if Preferences.NewTabPage.showNewTabPrivacyHub.value { + background.backgroundColor = .init(white: 0, alpha: 0.25) + background.layer.cornerRadius = 12 + background.layer.cornerCurve = .continuous + background.isUserInteractionEnabled = false + insertSubview(background, at: 0) + background.snp.makeConstraints { + $0.edges.equalToSuperview() + } + + let settingsButton = BraveButton(type: .system).then { + $0.setImage(UIImage(named: "privacy_reports_3dots", in: .module, compatibleWith: nil)!.template, for: .normal) + $0.tintColor = .white + $0.hitTestSlop = UIEdgeInsets(equalInset: -25) + } + + let hidePrivacyHub = UIAction( + title: Strings.PrivacyHub.hidePrivacyHubWidgetActionTitle, + image: UIImage(braveSystemNamed: "leo.eye.off"), + handler: UIAction.deferredActionHandler { [unowned self] _ in + self.hidePrivacyHubPressed?() + }) + + let showPrivacyHub = UIAction( + title: Strings.PrivacyHub.openPrivacyHubWidgetActionTitle, + image: UIImage(named: "privacy_reports_shield", in: .module, compatibleWith: nil)?.template, + handler: UIAction.deferredActionHandler { [unowned self] _ in + self.openPrivacyHubPressed?() + }) + + settingsButton.menu = UIMenu(title: "", options: .displayInline, children: [hidePrivacyHub, showPrivacyHub]) + settingsButton.showsMenuAsPrimaryAction = true + + topStackView.addStackViewItems(.view(privacyReportLabel), .view(settingsButton)) + } + } + } + deinit { NotificationCenter.default.removeObserver(self) } diff --git a/Sources/Brave/Frontend/Browser/PageZoom/PageZoomView.swift b/Sources/Brave/Frontend/Browser/PageZoom/PageZoomView.swift index 89e7138cbe8..4b02a9cea09 100644 --- a/Sources/Brave/Frontend/Browser/PageZoom/PageZoomView.swift +++ b/Sources/Brave/Frontend/Browser/PageZoom/PageZoomView.swift @@ -13,6 +13,7 @@ import Preferences private struct ZoomView: View { @ScaledMetric private var buttonWidth = 44.0 + var isPrivateBrowsing: Bool var minValue: Double var maxValue: Double @Binding var value: Double @@ -62,12 +63,12 @@ private struct ZoomView: View { Button(action: onReset) { Text(NSNumber(value: value), formatter: PageZoomView.percentFormatter) .font(.system(.footnote).weight(.medium)) - .foregroundColor((value == (PrivateBrowsingManager.shared.isPrivateBrowsing ? 1.0 : Preferences.General.defaultPageZoomLevel.value)) ? .accentColor : Color(UIColor.braveLabel)) + .foregroundColor((value == (isPrivateBrowsing ? 1.0 : Preferences.General.defaultPageZoomLevel.value)) ? .accentColor : Color(UIColor.braveLabel)) .padding() .contentShape(Rectangle()) } .fixedSize(horizontal: true, vertical: false) - .disabled(value == (PrivateBrowsingManager.shared.isPrivateBrowsing ? 1.0 : Preferences.General.defaultPageZoomLevel.value)) + .disabled(value == (isPrivateBrowsing ? 1.0 : Preferences.General.defaultPageZoomLevel.value)) } } @@ -75,6 +76,7 @@ struct PageZoomView: View { @Environment(\.managedObjectContext) private var context private var webView: WKWebView? + private let isPrivateBrowsing: Bool @State private var minValue = 0.5 @State private var maxValue = 3.0 @State private var currentValue: Double @@ -97,11 +99,12 @@ struct PageZoomView: View { var dismiss: (() -> Void)? - init(webView: WKWebView?) { + init(webView: WKWebView?, isPrivateBrowsing: Bool) { self.webView = webView + self.isPrivateBrowsing = isPrivateBrowsing // Private Browsing on Safari iOS always defaults to 100%, and isn't persistently saved. - if PrivateBrowsingManager.shared.isPrivateBrowsing { + if isPrivateBrowsing { _currentValue = State(initialValue: 1.0) return } @@ -126,6 +129,7 @@ struct PageZoomView: View { .frame(maxWidth: .infinity, alignment: .leading) ZoomView( + isPrivateBrowsing: isPrivateBrowsing, minValue: minValue, maxValue: maxValue, value: $currentValue, @@ -156,7 +160,7 @@ struct PageZoomView: View { webView.setValue(currentValue, forKey: PageZoomView.propertyName) // Do NOT store the changes in the Domain - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !isPrivateBrowsing { let domain = Domain.getPersistedDomain(for: url)?.then { $0.zoom_level = currentValue == $0.zoom_level?.doubleValue ? nil : NSNumber(value: currentValue) } @@ -188,7 +192,7 @@ struct PageZoomView: View { #if DEBUG struct PageZoomView_Previews: PreviewProvider { static var previews: some View { - PageZoomView(webView: nil) + PageZoomView(webView: nil, isPrivateBrowsing: false) .previewLayout(PreviewLayout.sizeThatFits) } } diff --git a/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistDetailViewController.swift b/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistDetailViewController.swift index 45c4c95d0d6..c40aa4ee348 100644 --- a/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistDetailViewController.swift +++ b/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistDetailViewController.swift @@ -12,8 +12,18 @@ import UIKit class PlaylistDetailViewController: UIViewController, UIGestureRecognizerDelegate { private var playerView: VideoView? + private let isPrivateBrowsing: Bool weak var delegate: PlaylistViewControllerDelegate? - + + init(isPrivateBrowsing: Bool) { + self.isPrivateBrowsing = isPrivateBrowsing + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func viewDidLoad() { super.viewDidLoad() @@ -147,11 +157,10 @@ extension PlaylistDetailViewController { if let url = URL(string: item.pageSrc) { self.dismiss(animated: true, completion: nil) - - let isPrivateBrowsing = PrivateBrowsingManager.shared.isPrivateBrowsing + self.delegate?.openURLInNewTab( url, - isPrivate: isPrivateBrowsing, + isPrivate: self.isPrivateBrowsing, isPrivileged: false) } })) diff --git a/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistListViewController+TableViewDelegate.swift b/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistListViewController+TableViewDelegate.swift index 76dbdf91fa6..c0f6d3af14e 100644 --- a/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistListViewController+TableViewDelegate.swift +++ b/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistListViewController+TableViewDelegate.swift @@ -149,7 +149,7 @@ extension PlaylistListViewController: UITableViewDelegate { handler: { [weak self] (action, view, completionHandler) in guard let self = self else { return } - let isPrivateBrowsing = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivateBrowsing = self.privateBrowsingManager?.isPrivateBrowsing == true let style: UIAlertController.Style = UIDevice.current.userInterfaceIdiom == .pad ? .alert : .actionSheet let alert = UIAlertController( @@ -244,7 +244,7 @@ extension PlaylistListViewController: UITableViewDelegate { // In Private-Browsing, we do not show "Open in New Tab", // we only show "Open in Private Tab" - let isPrivateBrowsing = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivateBrowsing = self.privateBrowsingManager?.isPrivateBrowsing == true if !isPrivateBrowsing { actions.append( UIAction( diff --git a/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistListViewController.swift b/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistListViewController.swift index 22f595c8fc6..ccf63578aa3 100644 --- a/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistListViewController.swift +++ b/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistListViewController.swift @@ -48,6 +48,8 @@ class PlaylistListViewController: UIViewController { weak var delegate: PlaylistViewControllerDelegate? private let playerView: VideoView + let privateBrowsingManager: PrivateBrowsingManager? + private var observers = Set() private var folderObserver: AnyCancellable? private var sharedFolderLoadingTask: Task? @@ -72,8 +74,9 @@ class PlaylistListViewController: UIViewController { $0.allowsSelectionDuringEditing = true } - init(playerView: VideoView) { + init(playerView: VideoView, privateBrowsingManager: PrivateBrowsingManager?) { self.playerView = playerView + self.privateBrowsingManager = privateBrowsingManager super.init(nibName: nil, bundle: nil) } @@ -638,7 +641,7 @@ extension PlaylistListViewController { activityIndicator.isHidden = false let selectedCell = tableView.cellForRow(at: indexPath) as? PlaylistCell - playerView.setVideoInfo(videoDomain: item.pageSrc, videoTitle: item.pageTitle) + playerView.setVideoInfo(videoDomain: item.pageSrc, videoTitle: item.pageTitle, isPrivateBrowsing: privateBrowsingManager?.isPrivateBrowsing == true) PlaylistMediaStreamer.setNowPlayingMediaArtwork(image: selectedCell?.iconView.image) completion?(item) } @@ -753,7 +756,7 @@ extension PlaylistListViewController { if let url = URL(string: item.pageSrc) { self.dismiss(animated: true, completion: nil) - let isPrivateBrowsing = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivateBrowsing = self.privateBrowsingManager?.isPrivateBrowsing == true self.delegate?.openURLInNewTab( url, isPrivate: isPrivateBrowsing, @@ -826,7 +829,7 @@ extension PlaylistListViewController { let pageURL = URL(string: currentItem.pageSrc) { self.dismiss(animated: true) { - let isPrivateBrowsing = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivateBrowsing = self.privateBrowsingManager?.isPrivateBrowsing == true browser.tabManager.addTabAndSelect( URLRequest(url: pageURL), isPrivate: isPrivateBrowsing) diff --git a/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistNewFolderView.swift b/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistNewFolderView.swift index ea8d363503d..c13fae364e8 100644 --- a/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistNewFolderView.swift +++ b/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistNewFolderView.swift @@ -41,7 +41,7 @@ class PlaylistFolderImageLoader: ObservableObject { func load(domainUrl: URL) { faviconTask?.cancel() faviconTask = Task { @MainActor in - let favicon = try await FaviconFetcher.loadIcon(url: domainUrl, persistent: !PrivateBrowsingManager.shared.isPrivateBrowsing) + let favicon = try await FaviconFetcher.loadIcon(url: domainUrl, persistent: true) self.image = favicon.image } } diff --git a/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistViewController.swift b/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistViewController.swift index e87c085c5f6..199dbe8ac4b 100644 --- a/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistViewController.swift +++ b/Sources/Brave/Frontend/Browser/Playlist/Controllers/PlaylistViewController.swift @@ -49,11 +49,12 @@ class PlaylistViewController: UIViewController { private let player: MediaPlayer private let playerView = VideoView() private let mediaStreamer: PlaylistMediaStreamer + private let privateBrowsingManager: PrivateBrowsingManager? private let splitController = UISplitViewController() private let folderController = PlaylistFolderController() - private lazy var listController = PlaylistListViewController(playerView: playerView) - private let detailController = PlaylistDetailViewController() + private lazy var listController = PlaylistListViewController(playerView: playerView, privateBrowsingManager: privateBrowsingManager) + private lazy var detailController = PlaylistDetailViewController(isPrivateBrowsing: privateBrowsingManager?.isPrivateBrowsing == true) private var folderObserver: AnyCancellable? private var playerStateObservers = Set() @@ -68,14 +69,17 @@ class PlaylistViewController: UIViewController { profile: Profile?, mediaPlayer: MediaPlayer, initialItem: PlaylistInfo?, - initialItemPlaybackOffset: Double + initialItemPlaybackOffset: Double, + privateBrowsingManager: PrivateBrowsingManager? ) { self.openInNewTab = openInNewTab self.openPlaylistSettingsMenu = openPlaylistSettingsMenu self.player = mediaPlayer self.mediaStreamer = PlaylistMediaStreamer(playerView: playerView) + self.privateBrowsingManager = privateBrowsingManager self.folderSharingUrl = nil + super.init(nibName: nil, bundle: nil) listController.initialItem = initialItem @@ -309,7 +313,7 @@ class PlaylistViewController: UIViewController { } if let item = PlaylistCarplayManager.shared.currentPlaylistItem { - playerView.setVideoInfo(videoDomain: item.pageSrc, videoTitle: item.pageTitle) + playerView.setVideoInfo(videoDomain: item.pageSrc, videoTitle: item.pageTitle, isPrivateBrowsing: privateBrowsingManager?.isPrivateBrowsing == true) } else { playerView.resetVideoInfo() } @@ -326,7 +330,8 @@ class PlaylistViewController: UIViewController { } else if let item = PlaylistCarplayManager.shared.currentPlaylistItem { self.playerView.setVideoInfo( videoDomain: item.pageSrc, - videoTitle: item.pageTitle) + videoTitle: item.pageTitle, + isPrivateBrowsing: self.privateBrowsingManager?.isPrivateBrowsing == true) } self.listController.highlightActiveItem() @@ -908,7 +913,8 @@ extension PlaylistViewController: VideoViewDelegate { PlaylistMediaStreamer.clearNowPlayingInfo() self.playerView.setVideoInfo( videoDomain: item.pageSrc, - videoTitle: item.pageTitle) + videoTitle: item.pageTitle, + isPrivateBrowsing: self.privateBrowsingManager?.isPrivateBrowsing == true) PlaylistMediaStreamer.setNowPlayingInfo(item, withPlayer: self.player) } catch { PlaylistMediaStreamer.clearNowPlayingInfo() @@ -955,7 +961,8 @@ extension PlaylistViewController: VideoViewDelegate { playerView.setVideoInfo( videoDomain: item.pageSrc, - videoTitle: item.pageTitle) + videoTitle: item.pageTitle, + isPrivateBrowsing: privateBrowsingManager?.isPrivateBrowsing == true) PlaylistMediaStreamer.setNowPlayingInfo(item, withPlayer: self.player) return item diff --git a/Sources/Brave/Frontend/Browser/Playlist/Managers & Cache/PlaylistCacheLoader.swift b/Sources/Brave/Frontend/Browser/Playlist/Managers & Cache/PlaylistCacheLoader.swift index b5d27cc0038..093ba2698e5 100644 --- a/Sources/Brave/Frontend/Browser/Playlist/Managers & Cache/PlaylistCacheLoader.swift +++ b/Sources/Brave/Frontend/Browser/Playlist/Managers & Cache/PlaylistCacheLoader.swift @@ -554,8 +554,7 @@ extension PlaylistWebLoader: WKNavigationDelegate { tab.currentPageData = PageData(mainFrameURL: mainDocumentURL) } - let isPrivateBrowsing = PrivateBrowsingManager.shared.isPrivateBrowsing - let domainForMainFrame = Domain.getOrCreate(forUrl: mainDocumentURL, persistent: !isPrivateBrowsing) + let domainForMainFrame = Domain.getOrCreate(forUrl: mainDocumentURL, persistent: false) if let requestURL = navigationAction.request.url, let targetFrame = navigationAction.targetFrame { diff --git a/Sources/Brave/Frontend/Browser/Playlist/Managers & Cache/PlaylistCarplayManager.swift b/Sources/Brave/Frontend/Browser/Playlist/Managers & Cache/PlaylistCarplayManager.swift index c90da057966..d68986fd7c8 100644 --- a/Sources/Brave/Frontend/Browser/Playlist/Managers & Cache/PlaylistCarplayManager.swift +++ b/Sources/Brave/Frontend/Browser/Playlist/Managers & Cache/PlaylistCarplayManager.swift @@ -72,23 +72,13 @@ public class PlaylistCarplayManager: NSObject { // Setup Playlist Download Resume Session PlaylistManager.shared.restoreSession() - // REFACTOR to support multiple windows. - // OR find a way to get WebKit to load `Youtube` and other sites WITHOUT having to be in the view hierarchy.. - var currentWindow = browserController?.view.window - - // BrowserController can actually be null when CarPlay is launched by the system - // The only such window that will be available is the actual CarPlay window - // So that's the window we need to use - // This does NOT break Multi-Window because we don't actually have multiple windows running - // when there is no browser controller. There is only a single CarPlay window. - if currentWindow == nil { - currentWindow = - UIApplication.shared.connectedScenes - .filter({ $0.activationState == .foregroundActive }) - .compactMap({ $0 as? UIWindowScene }) - .first?.windows - .filter({ $0.isKeyWindow }).first - } + // REFACTOR to find a way to get WebKit to load `Youtube` and other sites WITHOUT having to be in the view hierarchy.. + let currentWindow = + UIApplication.shared.connectedScenes + .filter({ $0.activationState == .foregroundActive }) + .compactMap({ $0 as? UIWindowScene }) + .first?.windows + .filter({ $0.isKeyWindow }).first // If there is no media player, create one, // pass it to the car-play controller @@ -125,7 +115,8 @@ public class PlaylistCarplayManager: NSObject { profile: browserController?.profile, mediaPlayer: mediaPlayer, initialItem: initialItem, - initialItemPlaybackOffset: initialItemPlaybackOffset) + initialItemPlaybackOffset: initialItemPlaybackOffset, + privateBrowsingManager: browserController?.privateBrowsingManager) self.mediaPlayer = mediaPlayer return playlistController } diff --git a/Sources/Brave/Frontend/Browser/Playlist/Utilities/PlaylistThumbnailUtility.swift b/Sources/Brave/Frontend/Browser/Playlist/Utilities/PlaylistThumbnailUtility.swift index 45c8ac38574..1540cddb98b 100644 --- a/Sources/Brave/Frontend/Browser/Playlist/Utilities/PlaylistThumbnailUtility.swift +++ b/Sources/Brave/Frontend/Browser/Playlist/Utilities/PlaylistThumbnailUtility.swift @@ -150,7 +150,7 @@ public class PlaylistThumbnailRenderer { favIconGenerator = Task { @MainActor in do { - let favicon = try await FaviconFetcher.loadIcon(url: url, persistent: !PrivateBrowsingManager.shared.isPrivateBrowsing) + let favicon = try await FaviconFetcher.loadIcon(url: url, persistent: true) await SDImageCache.shared.store(favicon.image, forKey: url.absoluteString) completion(favicon.image) } catch { diff --git a/Sources/Brave/Frontend/Browser/Playlist/VideoPlayer/UI/VideoPlayer.swift b/Sources/Brave/Frontend/Browser/Playlist/VideoPlayer/UI/VideoPlayer.swift index 0bed804aedf..23139986c02 100644 --- a/Sources/Brave/Frontend/Browser/Playlist/VideoPlayer/UI/VideoPlayer.swift +++ b/Sources/Brave/Frontend/Browser/Playlist/VideoPlayer/UI/VideoPlayer.swift @@ -574,7 +574,7 @@ class VideoView: UIView, VideoTrackerBarDelegate { staticImageView.contentMode = .scaleAspectFit } - func setVideoInfo(videoDomain: String, videoTitle: String?) { + func setVideoInfo(videoDomain: String, videoTitle: String?, isPrivateBrowsing: Bool) { var displayTitle = videoTitle ?? "" if displayTitle.isEmpty { @@ -596,7 +596,7 @@ class VideoView: UIView, VideoTrackerBarDelegate { } infoView.titleLabel.text = displayTitle - infoView.updateFavIcon(domain: videoDomain) + infoView.updateFavIcon(domain: videoDomain, isPrivateBrowsing: isPrivateBrowsing) } func resetVideoInfo() { diff --git a/Sources/Brave/Frontend/Browser/Playlist/VideoPlayer/UI/VideoPlayerInfoBar.swift b/Sources/Brave/Frontend/Browser/Playlist/VideoPlayer/UI/VideoPlayerInfoBar.swift index 3b83a3ce0bf..f144ad03bc3 100644 --- a/Sources/Brave/Frontend/Browser/Playlist/VideoPlayer/UI/VideoPlayerInfoBar.swift +++ b/Sources/Brave/Frontend/Browser/Playlist/VideoPlayer/UI/VideoPlayerInfoBar.swift @@ -108,14 +108,14 @@ class VideoPlayerInfoBar: UIView { fatalError("init(coder:) has not been implemented") } - func updateFavIcon(domain: String) { + func updateFavIcon(domain: String, isPrivateBrowsing: Bool) { favIconImageView.cancelFaviconLoad() favIconImageView.clearMonogramFavicon() favIconImageView.contentMode = .scaleAspectFit favIconImageView.image = Favicon.defaultImage if let url = URL(string: domain) { - favIconImageView.loadFavicon(for: url) + favIconImageView.loadFavicon(for: url, isPrivateBrowsing: isPrivateBrowsing) } } diff --git a/Sources/Brave/Frontend/Browser/PrivacyHub/PrivacyHubAllTimeSection.swift b/Sources/Brave/Frontend/Browser/PrivacyHub/PrivacyHubAllTimeSection.swift index 2b99f6aa9fe..2b84039014c 100644 --- a/Sources/Brave/Frontend/Browser/PrivacyHub/PrivacyHubAllTimeSection.swift +++ b/Sources/Brave/Frontend/Browser/PrivacyHub/PrivacyHubAllTimeSection.swift @@ -21,6 +21,7 @@ extension PrivacyReportsView { @State private var mostFrequentTrackerLoading = true @State private var riskiestWebsiteLoading = true + private(set) var isPrivateBrowsing: Bool private(set) var onDismiss: () -> Void private func allTimeItemView(trackerOrWebsite: CountableEntity?, countableLabel: String, header: String) -> some View { @@ -87,7 +88,7 @@ extension PrivacyReportsView { } NavigationLink( - destination: PrivacyReportAllTimeListsView(onDismiss: onDismiss) + destination: PrivacyReportAllTimeListsView(isPrivateBrowsing: isPrivateBrowsing, onDismiss: onDismiss) ) { HStack { Text(Strings.PrivacyHub.allTimeListsButtonText) @@ -122,7 +123,7 @@ extension PrivacyReportsView { #if DEBUG struct PrivacyHubAllTimeSection_Previews: PreviewProvider { static var previews: some View { - PrivacyReportsView.PrivacyHubAllTimeSection(onDismiss: {}) + PrivacyReportsView.PrivacyHubAllTimeSection(isPrivateBrowsing: false, onDismiss: {}) } } #endif diff --git a/Sources/Brave/Frontend/Browser/PrivacyHub/PrivacyReportAllTimeListsView.swift b/Sources/Brave/Frontend/Browser/PrivacyHub/PrivacyReportAllTimeListsView.swift index d08a5b221ce..597815e7ea4 100644 --- a/Sources/Brave/Frontend/Browser/PrivacyHub/PrivacyReportAllTimeListsView.swift +++ b/Sources/Brave/Frontend/Browser/PrivacyHub/PrivacyReportAllTimeListsView.swift @@ -18,6 +18,7 @@ struct PrivacyReportAllTimeListsView: View { @State private var trackersLoading = true @State private var websitesLoading = true + private(set) var isPrivateBrowsing: Bool private(set) var onDismiss: () -> Void enum Page: String, CaseIterable, Identifiable { @@ -126,7 +127,7 @@ struct PrivacyReportAllTimeListsView: View { Section { ForEach(websites) { item in HStack { - FaviconImage(url: item.faviconUrl) + FaviconImage(url: item.faviconUrl, isPrivateBrowsing: isPrivateBrowsing) Text(item.domain) Spacer() Text("\(item.count)") @@ -199,8 +200,8 @@ struct PrivacyReportAllTimeListsView: View { struct PrivacyReportAllTimeListsView_Previews: PreviewProvider { static var previews: some View { Group { - PrivacyReportAllTimeListsView(onDismiss: {}) - PrivacyReportAllTimeListsView(onDismiss: {}) + PrivacyReportAllTimeListsView(isPrivateBrowsing: false, onDismiss: {}) + PrivacyReportAllTimeListsView(isPrivateBrowsing: false, onDismiss: {}) .preferredColorScheme(.dark) } } diff --git a/Sources/Brave/Frontend/Browser/PrivacyHub/PrivacyReportsManager.swift b/Sources/Brave/Frontend/Browser/PrivacyHub/PrivacyReportsManager.swift index 235222dd33c..5d583feb08d 100644 --- a/Sources/Brave/Frontend/Browser/PrivacyHub/PrivacyReportsManager.swift +++ b/Sources/Brave/Frontend/Browser/PrivacyHub/PrivacyReportsManager.swift @@ -19,8 +19,8 @@ public struct PrivacyReportsManager { /// Instead a periodic timer is run and all requests gathered during this timeframe are saved in one database transaction. public static var pendingBlockedRequests: [(host: String, domain: URL, date: Date)] = [] - public static func processBlockedRequests() { - if PrivateBrowsingManager.shared.isPrivateBrowsing { return } + public static func processBlockedRequests(isPrivateBrowsing: Bool) { + if isPrivateBrowsing { return } let itemsToSave = pendingBlockedRequests pendingBlockedRequests.removeAll() @@ -35,13 +35,13 @@ public struct PrivacyReportsManager { private static var saveBlockedResourcesTimer: Timer? private static var vpnAlertsTimer: Timer? - public static func scheduleProcessingBlockedRequests() { + public static func scheduleProcessingBlockedRequests(isPrivateBrowsing: Bool) { saveBlockedResourcesTimer?.invalidate() let timeInterval = AppConstants.buildChannel.isPublic ? 60.0 : 10.0 saveBlockedResourcesTimer = Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: true) { _ in - processBlockedRequests() + processBlockedRequests(isPrivateBrowsing: isPrivateBrowsing) } } @@ -80,9 +80,9 @@ public struct PrivacyReportsManager { // MARK: - View /// Fetches required data to present the privacy reports view and returns the view. - static func prepareView() -> PrivacyReportsView { + static func prepareView(isPrivateBrowsing: Bool) -> PrivacyReportsView { let last = BraveVPNAlert.last(3) - let view = PrivacyReportsView(lastVPNAlerts: last) + let view = PrivacyReportsView(lastVPNAlerts: last, isPrivateBrowsing: isPrivateBrowsing) Preferences.PrivacyReports.ntpOnboardingCompleted.value = true diff --git a/Sources/Brave/Frontend/Browser/PrivacyHub/PrivacyReportsView.swift b/Sources/Brave/Frontend/Browser/PrivacyHub/PrivacyReportsView.swift index a5aabf188ba..0dade80a4b8 100644 --- a/Sources/Brave/Frontend/Browser/PrivacyHub/PrivacyReportsView.swift +++ b/Sources/Brave/Frontend/Browser/PrivacyHub/PrivacyReportsView.swift @@ -13,6 +13,7 @@ struct PrivacyReportsView: View { let lastVPNAlerts: [BraveVPNAlert]? + private(set) var isPrivateBrowsing: Bool var onDismiss: (() -> Void)? var openPrivacyReportsUrl: (() -> Void)? @@ -97,7 +98,7 @@ struct PrivacyReportsView: View { Divider() } - PrivacyHubAllTimeSection(onDismiss: dismissView) + PrivacyHubAllTimeSection(isPrivateBrowsing: isPrivateBrowsing, onDismiss: dismissView) VStack { Text(Strings.PrivacyHub.privacyReportsDisclaimer) @@ -142,9 +143,9 @@ struct PrivacyReports_Previews: PreviewProvider { static var previews: some View { Group { - PrivacyReportsView(lastVPNAlerts: nil) + PrivacyReportsView(lastVPNAlerts: nil, isPrivateBrowsing: false) - PrivacyReportsView(lastVPNAlerts: nil) + PrivacyReportsView(lastVPNAlerts: nil, isPrivateBrowsing: false) .preferredColorScheme(.dark) } } diff --git a/Sources/Brave/Frontend/Browser/PrivacyProtection/PrivateBrowsingManager.swift b/Sources/Brave/Frontend/Browser/PrivacyProtection/PrivateBrowsingManager.swift index 1020d7f7cfa..d5bf540fb68 100644 --- a/Sources/Brave/Frontend/Browser/PrivacyProtection/PrivateBrowsingManager.swift +++ b/Sources/Brave/Frontend/Browser/PrivacyProtection/PrivateBrowsingManager.swift @@ -7,6 +7,8 @@ import Data import Combine public final class PrivateBrowsingManager: ObservableObject { + + public init() {} @Published public var isPrivateBrowsing = false { didSet { @@ -17,6 +19,4 @@ public final class PrivateBrowsingManager: ObservableObject { } } } - - public static let shared = PrivateBrowsingManager() } diff --git a/Sources/Brave/Frontend/Browser/Search/SearchEngines.swift b/Sources/Brave/Frontend/Browser/Search/SearchEngines.swift index bc92e97388a..8d210e3caab 100644 --- a/Sources/Brave/Frontend/Browser/Search/SearchEngines.swift +++ b/Sources/Brave/Frontend/Browser/Search/SearchEngines.swift @@ -77,9 +77,7 @@ public class SearchEngines { } /// If no engine type is specified this method returns search engine for regular browsing. - func defaultEngine(forType type: DefaultEngineType? = nil) -> OpenSearchEngine { - let engineType = type ?? (PrivateBrowsingManager.shared.isPrivateBrowsing ? .privateMode : .standard) - + func defaultEngine(forType engineType: DefaultEngineType) -> OpenSearchEngine { if let name = engineType.option.value, let defaultEngine = orderedEngines.first(where: { $0.engineID == name || $0.shortName == name }) { return defaultEngine @@ -141,7 +139,7 @@ public class SearchEngines { } } - func isEngineDefault(_ engine: OpenSearchEngine, type: DefaultEngineType? = nil) -> Bool { + func isEngineDefault(_ engine: OpenSearchEngine, type: DefaultEngineType) -> Bool { return defaultEngine(forType: type).shortName == engine.shortName } @@ -192,8 +190,8 @@ public class SearchEngines { disabledEngineNames.removeValue(forKey: engine.shortName) } - func disableEngine(_ engine: OpenSearchEngine) { - if isEngineDefault(engine) { + func disableEngine(_ engine: OpenSearchEngine, isPrivateBrowsing: Bool) { + if isEngineDefault(engine, type: isPrivateBrowsing ? .privateMode : .standard) { // Can't disable default engine. return } @@ -232,8 +230,8 @@ public class SearchEngines { } } - func queryForSearchURL(_ url: URL?) -> String? { - return defaultEngine().queryForSearchURL(url) + func queryForSearchURL(_ url: URL?, forType engineType: DefaultEngineType) -> String? { + return defaultEngine(forType: engineType).queryForSearchURL(url) } fileprivate func getDisabledEngineNames() -> [String: Bool] { diff --git a/Sources/Brave/Frontend/Browser/Search/SearchSuggestionDataSource.swift b/Sources/Brave/Frontend/Browser/Search/SearchSuggestionDataSource.swift index 90e9101d02f..c02a4d74334 100644 --- a/Sources/Brave/Frontend/Browser/Search/SearchSuggestionDataSource.swift +++ b/Sources/Brave/Frontend/Browser/Search/SearchSuggestionDataSource.swift @@ -53,7 +53,7 @@ class SearchSuggestionDataSource { // In that case, we count it as if there are no quick suggestions to show // Unless Default Search Engine is different than Quick Search Engine var hasQuickSearchEngines: Bool { - let isDefaultEngineQuickEngine = searchEngines?.defaultEngine().engineID == quickSearchEngines.first?.engineID + let isDefaultEngineQuickEngine = searchEngines?.defaultEngine(forType: tabType == .private ? .privateMode : .standard).engineID == quickSearchEngines.first?.engineID if quickSearchEngines.count == 1 { return !isDefaultEngineQuickEngine @@ -82,7 +82,7 @@ class SearchSuggestionDataSource { var braveSearchPromotionAvailable: Bool { guard Preferences.Review.launchCount.value > 1, - searchEngines?.defaultEngine().shortName != OpenSearchEngine.EngineNames.brave, + searchEngines?.defaultEngine(forType: tabType == .private ? .privateMode : .standard).shortName != OpenSearchEngine.EngineNames.brave, let braveSearchPromotionLaunchDate = Preferences.BraveSearch.braveSearchPromotionLaunchDate.value, Preferences.BraveSearch.braveSearchPromotionCompletionState.value != BraveSearchPromotionState.dismissed.rawValue, Preferences.BraveSearch.braveSearchPromotionCompletionState.value != BraveSearchPromotionState.maybeLaterSameSession.rawValue else { @@ -161,7 +161,7 @@ class SearchSuggestionDataSource { // Show the default search engine first. if !tabType.isPrivate, let userAgent = SearchViewController.userAgent, - let engines = searchEngines?.defaultEngine() { + let engines = searchEngines?.defaultEngine(forType: tabType == .private ? .privateMode : .standard) { suggestClient = SearchSuggestClient(searchEngine: engines, userAgent: userAgent) } } diff --git a/Sources/Brave/Frontend/Browser/Search/SearchViewController.swift b/Sources/Brave/Frontend/Browser/Search/SearchViewController.swift index 8f29ebaa876..1017ee05499 100644 --- a/Sources/Brave/Frontend/Browser/Search/SearchViewController.swift +++ b/Sources/Brave/Frontend/Browser/Search/SearchViewController.swift @@ -333,7 +333,7 @@ public class SearchViewController: SiteTableViewController, LoaderListener { } private func submitSeachTemplateQuery(isBraveSearchPromotion: Bool) { - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !dataSource.tabType.isPrivate { RecentSearch.addItem(type: .text, text: dataSource.searchQuery, websiteUrl: nil) } searchDelegate?.searchViewController( @@ -359,7 +359,7 @@ public class SearchViewController: SiteTableViewController, LoaderListener { return } - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !dataSource.tabType.isPrivate { RecentSearch.addItem(type: .website, text: localSearchQuery, websiteUrl: url.absoluteString) } searchDelegate?.searchViewController(self, didSelectURL: url) @@ -381,7 +381,7 @@ public class SearchViewController: SiteTableViewController, LoaderListener { case .searchSuggestions: if !isBraveSearchPrompt(for: indexPath) { // Assume that only the default search engine can provide search suggestions. - let engine = dataSource.searchEngines?.defaultEngine() + let engine = dataSource.searchEngines?.defaultEngine(forType: dataSource.tabType == .private ? .privateMode : .standard) let suggestion = dataSource.suggestions[indexPath.row] var url = URIFixup.getURL(suggestion) @@ -390,7 +390,7 @@ public class SearchViewController: SiteTableViewController, LoaderListener { } if let url = url { - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !dataSource.tabType.isPrivate { RecentSearch.addItem(type: .website, text: suggestion, websiteUrl: url.absoluteString) } searchDelegate?.searchViewController(self, didSelectURL: url) @@ -441,7 +441,7 @@ public class SearchViewController: SiteTableViewController, LoaderListener { case .quickBar: return nil case .searchSuggestionsOptIn: return nil case .searchSuggestions: - if let defaultSearchEngine = dataSource.searchEngines?.defaultEngine() { + if let defaultSearchEngine = dataSource.searchEngines?.defaultEngine(forType: dataSource.tabType == .private ? .privateMode : .standard) { if defaultSearchEngine.shortName.contains(Strings.searchSuggestionSectionTitleNoSearchFormat) || defaultSearchEngine.shortName.lowercased().contains("search") { return defaultSearchEngine.displayName } @@ -622,7 +622,7 @@ public class SearchViewController: SiteTableViewController, LoaderListener { cell.imageView?.contentMode = .scaleAspectFit cell.imageView?.layer.borderColor = SearchViewControllerUX.iconBorderColor.cgColor cell.imageView?.layer.borderWidth = SearchViewControllerUX.iconBorderWidth - cell.imageView?.loadFavicon(for: site.tileURL) + cell.imageView?.loadFavicon(for: site.tileURL, isPrivateBrowsing: dataSource.tabType.isPrivate) cell.backgroundColor = .secondaryBraveBackground } diff --git a/Sources/Brave/Frontend/Browser/Tab.swift b/Sources/Brave/Frontend/Browser/Tab.swift index 747a5903b6b..c3b8ebcd398 100644 --- a/Sources/Brave/Frontend/Browser/Tab.swift +++ b/Sources/Brave/Frontend/Browser/Tab.swift @@ -555,7 +555,7 @@ class Tab: NSObject { /// In private browsing the URL is in memory but this is not the case for normal mode /// For Normal Mode Tab information is fetched using Tab ID from var fetchedURL: URL? { - if PrivateBrowsingManager.shared.isPrivateBrowsing { + if isPrivate { if let url = url, url.isWebPage() { return url } diff --git a/Sources/Brave/Frontend/Browser/TabManager.swift b/Sources/Brave/Frontend/Browser/TabManager.swift index a7acce308aa..5a2eace6075 100644 --- a/Sources/Brave/Frontend/Browser/TabManager.swift +++ b/Sources/Brave/Frontend/Browser/TabManager.swift @@ -92,6 +92,7 @@ class TabManager: NSObject { private var syncTabsTask: DispatchWorkItem? private var metricsHeartbeat: Timer? private let windowId: UUID + public let privateBrowsingManager: PrivateBrowsingManager /// The property returning only existing tab is NTP for current mode var isBrowserEmptyForCurrentMode: Bool { @@ -106,7 +107,7 @@ class TabManager: NSObject { } } - init(windowId: UUID, prefs: Prefs, rewards: BraveRewards?, tabGeneratorAPI: BraveTabGeneratorAPI?) { + init(windowId: UUID, prefs: Prefs, rewards: BraveRewards?, tabGeneratorAPI: BraveTabGeneratorAPI?, privateBrowsingManager: PrivateBrowsingManager) { assert(Thread.isMainThread) self.windowId = windowId @@ -114,6 +115,7 @@ class TabManager: NSObject { self.navDelegate = TabManagerNavDelegate() self.rewards = rewards self.tabGeneratorAPI = tabGeneratorAPI + self.privateBrowsingManager = privateBrowsingManager self.tabEventHandlers = TabEventHandlers.create(with: prefs) super.init() @@ -193,7 +195,7 @@ class TabManager: NSObject { // What the users sees displayed based on current private browsing mode var tabsForCurrentMode: [Tab] { - let tabType: TabType = PrivateBrowsingManager.shared.isPrivateBrowsing ? .private : .regular + let tabType: TabType = privateBrowsingManager.isPrivateBrowsing ? .private : .regular return tabs(withType: tabType) } @@ -208,7 +210,7 @@ class TabManager: NSObject { func tabsForCurrentMode(for query: String? = nil) -> [Tab] { if let query = query { - let tabType: TabType = PrivateBrowsingManager.shared.isPrivateBrowsing ? .private : .regular + let tabType: TabType = privateBrowsingManager.isPrivateBrowsing ? .private : .regular return tabs(withType: tabType, query: query) } else { return tabsForCurrentMode @@ -300,11 +302,11 @@ class TabManager: NSObject { return } // Convert the global mode to private if opening private tab from normal tab/ history/bookmark. - if selectedTab?.isPrivate == false && tab?.isPrivate == true { - PrivateBrowsingManager.shared.isPrivateBrowsing = true + if selectedTab?.isPrivate != true && tab?.isPrivate == true { + privateBrowsingManager.isPrivateBrowsing = true } // Make sure to wipe the private tabs if the user has the pref turned on - if !TabType.of(tab).isPrivate { + if !TabType.of(tab).isPrivate && (Preferences.Privacy.privateBrowsingOnly.value || !Preferences.Privacy.persistentPrivateBrowsing.value) { removeAllPrivateTabs() } @@ -357,7 +359,7 @@ class TabManager: NSObject { guard let newSelectedTab = tab, let previousTab = previous, let newTabUrl = newSelectedTab.url, let previousTabUrl = previousTab.url else { return } - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !privateBrowsingManager.isPrivateBrowsing { if previousTab.displayFavicon == nil { adsRewardsLog.warning("No favicon found in \(previousTab) to report to rewards panel") } @@ -379,7 +381,9 @@ class TabManager: NSObject { // we only want to remove all private tabs when leaving PBM and not when entering. func willSwitchTabMode(leavingPBM: Bool) { if leavingPBM { - removeAllPrivateTabs() + if Preferences.Privacy.privateBrowsingOnly.value || !Preferences.Privacy.persistentPrivateBrowsing.value { + removeAllPrivateTabs() + } } } @@ -496,7 +500,7 @@ class TabManager: NSObject { } private func saveTabOrder() { - if PrivateBrowsingManager.shared.isPrivateBrowsing { return } + if Preferences.Privacy.privateBrowsingOnly.value || (privateBrowsingManager.isPrivateBrowsing && !Preferences.Privacy.persistentPrivateBrowsing.value) { return } let allTabIds = allTabs.compactMap { $0.id } SessionTab.saveTabOrder(tabIds: allTabIds) } @@ -505,11 +509,14 @@ class TabManager: NSObject { assert(Thread.isMainThread) let isPrivate = tab.type == .private - if !isPrivate { + let isPersistentTab = !isPrivate || (isPrivate && !Preferences.Privacy.privateBrowsingOnly.value && Preferences.Privacy.persistentPrivateBrowsing.value) + + if isPersistentTab { SessionTab.createIfNeeded(windowId: windowId, tabId: tab.id, title: Strings.newTab, - tabURL: request?.url ?? TabManager.ntpInteralURL) + tabURL: request?.url ?? TabManager.ntpInteralURL, + isPrivate: isPrivate) } delegates.forEach { $0.get()?.tabManager(self, willAddTab: tab) } @@ -541,7 +548,7 @@ class TabManager: NSObject { } // Ignore on restore. - if flushToDisk && !zombie && !isPrivate { + if flushToDisk && !zombie && isPersistentTab { saveTab(tab, saveOrder: true) } @@ -556,11 +563,13 @@ class TabManager: NSObject { tab.webStateDebounceTimer?.invalidate() if state == .complete || state == .loaded || state == .pushstate || state == .popstate || state == .replacestate { - // Saving Tab Private Mode - not supported yet. - if !tab.isPrivate { - self.preserveScreenshots() - self.saveTab(tab) + + if Preferences.Privacy.privateBrowsingOnly.value || (tab.isPrivate && !Preferences.Privacy.persistentPrivateBrowsing.value) { + return } + + self.preserveScreenshots() + self.saveTab(tab) } } } @@ -581,8 +590,10 @@ class TabManager: NSObject { } func saveAllTabs() { - if PrivateBrowsingManager.shared.isPrivateBrowsing { return } - SessionTab.updateAll(tabs: tabs(withType: .regular).compactMap({ + if Preferences.Privacy.privateBrowsingOnly.value || (privateBrowsingManager.isPrivateBrowsing && !Preferences.Privacy.persistentPrivateBrowsing.value) { return } + + let tabs = Preferences.Privacy.persistentPrivateBrowsing.value ? allTabs : tabs(withType: .regular) + SessionTab.updateAll(tabs: tabs.compactMap({ if let sessionData = $0.webView?.sessionData { return ($0.id, sessionData, $0.title, $0.url ?? TabManager.ntpInteralURL) } @@ -591,7 +602,7 @@ class TabManager: NSObject { } func saveTab(_ tab: Tab, saveOrder: Bool = false) { - if PrivateBrowsingManager.shared.isPrivateBrowsing { return } + if Preferences.Privacy.privateBrowsingOnly.value || (tab.isPrivate && !Preferences.Privacy.persistentPrivateBrowsing.value) { return } SessionTab.update(tabId: tab.id, interactionState: tab.webView?.sessionData ?? Data(), title: tab.title, url: tab.url ?? TabManager.ntpInteralURL) if saveOrder { saveTabOrder() @@ -920,20 +931,19 @@ class TabManager: NSObject { flushToDisk: false, zombie: true, id: savedTab.tabId, - isPrivate: false) - - let isPrivateBrowsing = PrivateBrowsingManager.shared.isPrivateBrowsing + isPrivate: savedTab.isPrivate) tab.lastTitle = savedTab.title tab.favicon = FaviconFetcher.getIconFromCache(for: tabURL) ?? Favicon.default tab.setScreenshot(savedTab.screenshot) Task { @MainActor in - tab.favicon = try await FaviconFetcher.loadIcon(url: tabURL, kind: .smallIcon, persistent: !isPrivateBrowsing) + tab.favicon = try await FaviconFetcher.loadIcon(url: tabURL, kind: .smallIcon, persistent: tab.isPrivate) tab.setScreenshot(savedTab.screenshot) } - if savedTab.isSelected { + // Do not select the private tab since we always restore to regular mode! + if savedTab.isSelected && !savedTab.isPrivate { tabToSelect = tab } } @@ -1149,8 +1159,11 @@ extension TabManager: WKNavigationDelegate { return } - // Saving Tab Private Mode - not supported yet. - if let tab = tabForWebView(webView), !tab.isPrivate { + if let tab = tabForWebView(webView) { + if Preferences.Privacy.privateBrowsingOnly.value || (tab.isPrivate && !Preferences.Privacy.persistentPrivateBrowsing.value) { + return + } + preserveScreenshots() saveTab(tab) } diff --git a/Sources/Brave/Frontend/Browser/TabManagerNavDelegate.swift b/Sources/Brave/Frontend/Browser/TabManagerNavDelegate.swift index b7fa66e9258..357944324ae 100644 --- a/Sources/Brave/Frontend/Browser/TabManagerNavDelegate.swift +++ b/Sources/Brave/Frontend/Browser/TabManagerNavDelegate.swift @@ -68,7 +68,7 @@ class TabManagerNavDelegate: NSObject, WKNavigationDelegate { } private func defaultAllowPolicy() -> WKNavigationActionPolicy { - let isPrivateBrowsing = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivateBrowsing = tabManager?.privateBrowsingManager.isPrivateBrowsing == true if isPrivateBrowsing || !Preferences.General.followUniversalLinks.value { // Stop Brave from opening universal links by using the private enum value // `_WKNavigationActionPolicyAllowWithoutTryingAppLink` which is defined here: diff --git a/Sources/Brave/Frontend/Browser/Tabs/RecentlyClosedTabs/RecentlyClosedTabsView.swift b/Sources/Brave/Frontend/Browser/Tabs/RecentlyClosedTabs/RecentlyClosedTabsView.swift index 5a08cb5d6e8..247608a6ba3 100644 --- a/Sources/Brave/Frontend/Browser/Tabs/RecentlyClosedTabs/RecentlyClosedTabsView.swift +++ b/Sources/Brave/Frontend/Browser/Tabs/RecentlyClosedTabs/RecentlyClosedTabsView.swift @@ -57,7 +57,7 @@ struct RecentlyClosedTabsView: View { onRecentlyClosedSelected?(recentlyClosed) }) { HStack { - FaviconImage(url: recentlyClosed.url) + FaviconImage(url: recentlyClosed.url, isPrivateBrowsing: tabManager?.privateBrowsingManager.isPrivateBrowsing == true) VStack(alignment: .leading) { Text(recentlyClosed.title ?? "") .font(.footnote.weight(.semibold)) diff --git a/Sources/Brave/Frontend/Browser/Tabs/TabBar/TabBarCell.swift b/Sources/Brave/Frontend/Browser/Tabs/TabBar/TabBarCell.swift index 6df2d9ffb35..0273eb7d4ee 100644 --- a/Sources/Brave/Frontend/Browser/Tabs/TabBar/TabBarCell.swift +++ b/Sources/Brave/Frontend/Browser/Tabs/TabBar/TabBarCell.swift @@ -39,7 +39,23 @@ class TabBarCell: UICollectionViewCell { } } weak var tab: Tab? - weak var tabManager: TabManager? + weak var tabManager: TabManager? { + didSet { + privateModeCancellable = tabManager?.privateBrowsingManager + .$isPrivateBrowsing + .removeDuplicates() + .sink(receiveValue: { [weak self] isPrivateBrowsing in + self?.updateColors(isPrivateBrowsing) + }) + + Preferences.General.nightModeEnabled.objectWillChange + .receive(on: RunLoop.main) + .sink { [weak self] _ in + self?.updateColors(self?.tabManager?.privateBrowsingManager.isPrivateBrowsing == true) + } + .store(in: &cancellables) + } + } var closeTabCallback: ((Tab) -> Void)? private var cancellables: Set = [] @@ -62,19 +78,6 @@ class TabBarCell: UICollectionViewCell { updateFont() isSelected = false - privateModeCancellable = PrivateBrowsingManager.shared - .$isPrivateBrowsing - .removeDuplicates() - .sink(receiveValue: { [weak self] isPrivateBrowsing in - self?.updateColors(isPrivateBrowsing) - }) - - Preferences.General.nightModeEnabled.objectWillChange - .receive(on: RunLoop.main) - .sink { [weak self] _ in - self?.updateColors(PrivateBrowsingManager.shared.isPrivateBrowsing) - } - .store(in: &cancellables) } private var privateModeCancellable: AnyCancellable? diff --git a/Sources/Brave/Frontend/Browser/Tabs/TabBar/TabsBarViewController.swift b/Sources/Brave/Frontend/Browser/Tabs/TabBar/TabsBarViewController.swift index 8cde0809a31..0f2cf0edc20 100644 --- a/Sources/Brave/Frontend/Browser/Tabs/TabBar/TabsBarViewController.swift +++ b/Sources/Brave/Frontend/Browser/Tabs/TabBar/TabsBarViewController.swift @@ -101,8 +101,9 @@ class TabsBarViewController: UIViewController { } var newTabMenu: [UIAction] = [] + let isPrivateBrowsing = tabManager?.privateBrowsingManager.isPrivateBrowsing == true - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !isPrivateBrowsing { let openNewPrivateTab = UIAction( title: Strings.Hotkey.newPrivateTabTitle, image: UIImage(systemName: "plus.square.fill.on.square.fill"), @@ -114,20 +115,20 @@ class TabsBarViewController: UIViewController { } let openNewTab = UIAction( - title: PrivateBrowsingManager.shared.isPrivateBrowsing ? Strings.Hotkey.newPrivateTabTitle : Strings.Hotkey.newTabTitle, - image: PrivateBrowsingManager.shared.isPrivateBrowsing ? UIImage(systemName: "plus.square.fill.on.square.fill") : UIImage(systemName: "plus.square.on.square"), + title: isPrivateBrowsing ? Strings.Hotkey.newPrivateTabTitle : Strings.Hotkey.newTabTitle, + image: isPrivateBrowsing ? UIImage(systemName: "plus.square.fill.on.square.fill") : UIImage(systemName: "plus.square.on.square"), handler: UIAction.deferredActionHandler { [unowned self] _ in - self.delegate?.tabsBarDidSelectAddNewTab(PrivateBrowsingManager.shared.isPrivateBrowsing) + self.delegate?.tabsBarDidSelectAddNewTab(isPrivateBrowsing) }) newTabMenu.append(openNewTab) newTabMenu.append(UIAction(title: "New Window", image: UIImage(systemName: "window.horizontal.closed"), handler: UIAction.deferredActionHandler { [unowned self] _ in - self.delegate?.tabsBarDidSelectAddNewWindow(PrivateBrowsingManager.shared.isPrivateBrowsing) + self.delegate?.tabsBarDidSelectAddNewWindow(isPrivateBrowsing) })) plusButton.menu = UIMenu(title: "", identifier: nil, children: newTabMenu) - privateModeCancellable = PrivateBrowsingManager.shared + privateModeCancellable = tabManager?.privateBrowsingManager .$isPrivateBrowsing .removeDuplicates() .sink(receiveValue: { [weak self] isPrivateBrowsing in @@ -137,7 +138,7 @@ class TabsBarViewController: UIViewController { Preferences.General.nightModeEnabled.objectWillChange .receive(on: RunLoop.main) .sink { [weak self] _ in - self?.updateColors(PrivateBrowsingManager.shared.isPrivateBrowsing) + self?.updateColors(self?.tabManager?.privateBrowsingManager.isPrivateBrowsing == true) } .store(in: &cancellables) } @@ -204,7 +205,7 @@ class TabsBarViewController: UIViewController { } @objc func addTabPressed() { - tabManager?.addTabAndSelect(isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing) + tabManager?.addTabAndSelect(isPrivate: tabManager?.privateBrowsingManager.isPrivateBrowsing == true) } @objc private func didLongPressAddTab(_ longPress: UILongPressGestureRecognizer) { diff --git a/Sources/Brave/Frontend/Browser/Tabs/TabTray/TabTrayController+KeyCommands.swift b/Sources/Brave/Frontend/Browser/Tabs/TabTray/TabTrayController+KeyCommands.swift index 53ef5ed254f..5c5d947e8ea 100644 --- a/Sources/Brave/Frontend/Browser/Tabs/TabTray/TabTrayController+KeyCommands.swift +++ b/Sources/Brave/Frontend/Browser/Tabs/TabTray/TabTrayController+KeyCommands.swift @@ -105,7 +105,7 @@ extension TabTrayController { UIKeyCommand(title: Strings.Hotkey.openNewTabFromTabTrayKeyCodeTitle, action: #selector(didOpenNewTabKeyCommand), input: "t", modifierFlags: .command) ] - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !tabManager.privateBrowsingManager.isPrivateBrowsing { navigationCommands += [ UIKeyCommand(title: Strings.Hotkey.recentlyClosedTabTitle, action: #selector(reopenRecentlyClosedTabCommand), input: "t", modifierFlags: [.command, .shift]) ] diff --git a/Sources/Brave/Frontend/Browser/Tabs/TabTray/TabTrayController+TableViewDelegate.swift b/Sources/Brave/Frontend/Browser/Tabs/TabTray/TabTrayController+TableViewDelegate.swift index cc4ecb978cc..19c053f2dac 100644 --- a/Sources/Brave/Frontend/Browser/Tabs/TabTray/TabTrayController+TableViewDelegate.swift +++ b/Sources/Brave/Frontend/Browser/Tabs/TabTray/TabTrayController+TableViewDelegate.swift @@ -50,7 +50,7 @@ extension TabTrayController: UITableViewDataSource, UITableViewDelegate { $0.layer.cornerRadius = 6 $0.layer.cornerCurve = .continuous $0.layer.masksToBounds = true - $0.loadFavicon(for: distantTab.url) + $0.loadFavicon(for: distantTab.url, isPrivateBrowsing: tabManager.privateBrowsingManager.isPrivateBrowsing) } } diff --git a/Sources/Brave/Frontend/Browser/Tabs/TabTray/TabTrayController.swift b/Sources/Brave/Frontend/Browser/Tabs/TabTray/TabTrayController.swift index 4a692b29b71..d30e764e4a7 100644 --- a/Sources/Brave/Frontend/Browser/Tabs/TabTray/TabTrayController.swift +++ b/Sources/Brave/Frontend/Browser/Tabs/TabTray/TabTrayController.swift @@ -85,7 +85,7 @@ class TabTrayController: LoadingViewController { private(set) var privateMode: Bool = false { didSet { // Should be set immediately before other logic executes - PrivateBrowsingManager.shared.isPrivateBrowsing = privateMode + tabManager.privateBrowsingManager.isPrivateBrowsing = privateMode applySnapshot() privateModeButton.isSelected = privateMode @@ -176,7 +176,7 @@ class TabTrayController: LoadingViewController { overlayDetails: EmptyOverlayStateDetails(title: Strings.noSearchResultsfound)) override var preferredStatusBarStyle: UIStatusBarStyle { - if PrivateBrowsingManager.shared.isPrivateBrowsing { + if tabManager.privateBrowsingManager.isPrivateBrowsing { return .lightContent } @@ -298,7 +298,7 @@ class TabTrayController: LoadingViewController { UIBarButtonItem(customView: doneButton), ] - privateModeCancellable = PrivateBrowsingManager.shared + privateModeCancellable = tabManager.privateBrowsingManager .$isPrivateBrowsing .removeDuplicates() .sink(receiveValue: { [weak self] isPrivateBrowsing in @@ -418,7 +418,7 @@ class TabTrayController: LoadingViewController { } override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) { - guard !PrivateBrowsingManager.shared.isPrivateBrowsing, let recentlyClosedTab = RecentlyClosed.all().first else { + guard !tabManager.privateBrowsingManager.isPrivateBrowsing, let recentlyClosedTab = RecentlyClosed.all().first else { return } @@ -568,7 +568,7 @@ class TabTrayController: LoadingViewController { } @objc private func tappedButton(_ gestureRecognizer: UIGestureRecognizer) { - if PrivateBrowsingManager.shared.isPrivateBrowsing { + if tabManager.privateBrowsingManager.isPrivateBrowsing { return } @@ -603,10 +603,19 @@ class TabTrayController: LoadingViewController { tabTypeSelector.selectedSegmentIndex = 0 tabTypeSelector.sendActions(for: UIControl.Event.valueChanged) - tabTrayView.showPrivateModeInfo() - // New private tab is created immediately to reflect changes on NTP. - // If user drags the modal down or dismisses it, a new private tab will be ready. - tabManager.addTabAndSelect(isPrivate: true) + if !Preferences.Privacy.persistentPrivateBrowsing.value { + tabTrayView.showPrivateModeInfo() + // New private tab is created immediately to reflect changes on NTP. + // If user drags the modal down or dismisses it, a new private tab will be ready. + tabManager.addTabAndSelect(isPrivate: true) + } else { + if tabManager.tabsForCurrentMode.isEmpty { + tabManager.addTabAndSelect(isPrivate: true) + } + + tabTrayView.hidePrivateModeInfo() + tabTrayView.collectionView.reloadData() + } } else { tabTrayView.hidePrivateModeInfo() diff --git a/Sources/Brave/Frontend/Browser/Tabs/TabTray/Views/TabTrayCell.swift b/Sources/Brave/Frontend/Browser/Tabs/TabTray/Views/TabTrayCell.swift index 0cb35657b94..a6ff3538714 100644 --- a/Sources/Brave/Frontend/Browser/Tabs/TabTray/Views/TabTrayCell.swift +++ b/Sources/Brave/Frontend/Browser/Tabs/TabTray/Views/TabTrayCell.swift @@ -77,7 +77,7 @@ class TabCell: UICollectionViewCell { if let displayFavicon = tab.displayFavicon { favicon.image = displayFavicon.image ?? Favicon.defaultImage } else if let url = tab.url, !url.isLocal, !InternalURL.isValid(url: url) { - favicon.loadFavicon(for: url) + favicon.loadFavicon(for: url, isPrivateBrowsing: tab.isPrivate) } else { favicon.image = Favicon.defaultImage } diff --git a/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/BottomToolbarView.swift b/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/BottomToolbarView.swift index 9feef1bbc51..24e0f2640a0 100644 --- a/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/BottomToolbarView.swift +++ b/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/BottomToolbarView.swift @@ -26,10 +26,12 @@ class BottomToolbarView: UIView, ToolbarProtocol { private let contentView = UIStackView() private var cancellables: Set = [] let line = UIView.separatorLine + private let privateBrowsingManager: PrivateBrowsingManager - fileprivate override init(frame: CGRect) { + init(privateBrowsingManager: PrivateBrowsingManager) { + self.privateBrowsingManager = privateBrowsingManager actionButtons = [backButton, forwardButton, addTabButton, searchButton, tabsButton, menuButton] - super.init(frame: frame) + super.init(frame: .zero) setupAccessibility() backgroundColor = Preferences.General.nightModeEnabled.value ? .nightModeBackground : .urlBarBackground @@ -48,7 +50,7 @@ class BottomToolbarView: UIView, ToolbarProtocol { $0.leading.trailing.equalToSuperview() } - privateModeCancellable = PrivateBrowsingManager.shared + privateModeCancellable = privateBrowsingManager .$isPrivateBrowsing .removeDuplicates() .sink(receiveValue: { [weak self] isPrivateBrowsing in @@ -58,7 +60,7 @@ class BottomToolbarView: UIView, ToolbarProtocol { Preferences.General.nightModeEnabled.objectWillChange .receive(on: RunLoop.main) .sink { [weak self] _ in - self?.updateColors(PrivateBrowsingManager.shared.isPrivateBrowsing) + self?.updateColors(privateBrowsingManager.isPrivateBrowsing) } .store(in: &cancellables) diff --git a/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/Bookmarks/AddEditBookmarkTableViewController.swift b/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/Bookmarks/AddEditBookmarkTableViewController.swift index eeb428b73ee..d444799ce13 100644 --- a/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/Bookmarks/AddEditBookmarkTableViewController.swift +++ b/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/Bookmarks/AddEditBookmarkTableViewController.swift @@ -49,11 +49,11 @@ class AddEditBookmarkTableViewController: UITableViewController { private lazy var bookmarkDetailsView: BookmarkFormFieldsProtocol = { switch mode { case .addBookmark(let title, let url): - return BookmarkDetailsView(title: title, url: url) + return BookmarkDetailsView(title: title, url: url, isPrivateBrowsing: isPrivateBrowsing) case .addFolder(let title), .addFolderUsingTabs(title: let title, _): return FolderDetailsViewTableViewCell(title: title, viewHeight: UX.cellHeight) case .editBookmark(let bookmark), .editFavorite(let bookmark): - return BookmarkDetailsView(title: bookmark.title, url: bookmark.url) + return BookmarkDetailsView(title: bookmark.title, url: bookmark.url, isPrivateBrowsing: isPrivateBrowsing) case .editFolder(let folder): return FolderDetailsViewTableViewCell(title: folder.title, viewHeight: UX.cellHeight) } @@ -150,10 +150,12 @@ class AddEditBookmarkTableViewController: UITableViewController { private var saveLocation: BookmarkSaveLocation private var rootFolderName: String private var rootFolderId: Int = 0 // MobileBookmarks Folder Id + private var isPrivateBrowsing: Bool - init(bookmarkManager: BookmarkManager, mode: BookmarkEditMode) { + init(bookmarkManager: BookmarkManager, mode: BookmarkEditMode, isPrivateBrowsing: Bool) { self.bookmarkManager = bookmarkManager self.mode = mode + self.isPrivateBrowsing = isPrivateBrowsing saveLocation = mode.initialSaveLocation presentationMode = .currentSelection @@ -371,7 +373,7 @@ class AddEditBookmarkTableViewController: UITableViewController { isLoading = true for tab in tabs { - if PrivateBrowsingManager.shared.isPrivateBrowsing { + if tab.isPrivate { if let url = tab.url, url.isWebPage(), !(InternalURL(url)?.isAboutHomeURL ?? false) { bookmarkManager.add(url: url, title: tab.title, parentFolder: parentFolder) } @@ -437,7 +439,9 @@ class AddEditBookmarkTableViewController: UITableViewController { } private func showNewFolderVC() { - let vc = AddEditBookmarkTableViewController(bookmarkManager: bookmarkManager, mode: .addFolder(title: Strings.newFolderDefaultName)) + let vc = AddEditBookmarkTableViewController(bookmarkManager: bookmarkManager, + mode: .addFolder(title: Strings.newFolderDefaultName), + isPrivateBrowsing: isPrivateBrowsing) navigationController?.pushViewController(vc, animated: true) } diff --git a/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/Bookmarks/BookmarkDetailsView.swift b/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/Bookmarks/BookmarkDetailsView.swift index ec422c8b7ad..fa07d94e89c 100644 --- a/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/Bookmarks/BookmarkDetailsView.swift +++ b/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/Bookmarks/BookmarkDetailsView.swift @@ -52,7 +52,7 @@ class BookmarkDetailsView: AddEditHeaderView, BookmarkFormFieldsProtocol { // MARK: - Initialization - convenience init(title: String?, url: String?) { + convenience init(title: String?, url: String?, isPrivateBrowsing: Bool) { self.init(frame: .zero) backgroundColor = .secondaryBraveGroupedBackground @@ -76,7 +76,7 @@ class BookmarkDetailsView: AddEditHeaderView, BookmarkFormFieldsProtocol { if url?.isBookmarklet == true { url = url?.removingPercentEncoding } else if let url = url, let favUrl = URL(string: url) { - faviconImageView.loadFavicon(siteURL: favUrl) + faviconImageView.loadFavicon(siteURL: favUrl, isPrivateBrowsing: isPrivateBrowsing) } titleTextField.text = title ?? Strings.newBookmarkDefaultName diff --git a/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/Bookmarks/BookmarksViewController.swift b/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/Bookmarks/BookmarksViewController.swift index 250870ca333..d3030065c30 100644 --- a/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/Bookmarks/BookmarksViewController.swift +++ b/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/Bookmarks/BookmarksViewController.swift @@ -417,7 +417,7 @@ class BookmarksViewController: SiteTableViewController, ToolbarUrlActionsProtoco cell.imageView?.clearMonogramFavicon() if let urlString = item.url, let url = URL(string: urlString) { - cell.imageView?.loadFavicon(for: url) { [weak cell] favicon in + cell.imageView?.loadFavicon(for: url, isPrivateBrowsing: isPrivateBrowsing) { [weak cell] favicon in if favicon?.isMonogramImage == true, let icon = item.bookmarkNode.icon { cell?.imageView?.image = icon } @@ -604,7 +604,7 @@ class BookmarksViewController: SiteTableViewController, ToolbarUrlActionsProtoco var newTabActionMenu: [UIAction] = [openInNewTabAction] - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !isPrivateBrowsing { newTabActionMenu.append(newPrivateTabAction) } @@ -691,7 +691,7 @@ extension BookmarksViewController { } if let mode = mode { - let vc = AddEditBookmarkTableViewController(bookmarkManager: bookmarkManager, mode: mode) + let vc = AddEditBookmarkTableViewController(bookmarkManager: bookmarkManager, mode: mode, isPrivateBrowsing: isPrivateBrowsing) self.navigationController?.pushViewController(vc, animated: true) } } diff --git a/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/HistoryViewController.swift b/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/HistoryViewController.swift index 32d9990386f..4477c39f12d 100644 --- a/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/HistoryViewController.swift +++ b/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/HistoryViewController.swift @@ -240,10 +240,10 @@ class HistoryViewController: SiteTableViewController, ToolbarUrlActionsProtocol let domain = Domain.getOrCreate( forUrl: historyItem.url, - persistent: !PrivateBrowsingManager.shared.isPrivateBrowsing) + persistent: !isPrivateBrowsing) if domain.url?.asURL != nil { - cell.imageView?.loadFavicon(for: historyItem.url) + cell.imageView?.loadFavicon(for: historyItem.url, isPrivateBrowsing: isPrivateBrowsing) } else { cell.imageView?.clearMonogramFavicon() cell.imageView?.image = Favicon.defaultImage @@ -340,7 +340,7 @@ class HistoryViewController: SiteTableViewController, ToolbarUrlActionsProtocol var newTabActionMenu: [UIAction] = [openInNewTabAction] - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !isPrivateBrowsing { newTabActionMenu.append(newPrivateTabAction) } diff --git a/Sources/Brave/Frontend/Browser/Toolbars/HeaderContainerView.swift b/Sources/Brave/Frontend/Browser/Toolbars/HeaderContainerView.swift index e08c09a52a5..10f0d5929c7 100644 --- a/Sources/Brave/Frontend/Browser/Toolbars/HeaderContainerView.swift +++ b/Sources/Brave/Frontend/Browser/Toolbars/HeaderContainerView.swift @@ -32,8 +32,8 @@ class HeaderContainerView: UIView { private var cancellables: Set = [] - override init(frame: CGRect) { - super.init(frame: frame) + init(privateBrowsingManager: PrivateBrowsingManager) { + super.init(frame: .zero) addSubview(contentView) contentView.addSubview(expandedBarStackView) @@ -51,7 +51,7 @@ class HeaderContainerView: UIView { $0.edges.equalToSuperview() } - PrivateBrowsingManager.shared + privateBrowsingManager .$isPrivateBrowsing .removeDuplicates() .sink(receiveValue: { [weak self] isPrivateBrowsing in @@ -62,7 +62,7 @@ class HeaderContainerView: UIView { Preferences.General.nightModeEnabled.objectWillChange .receive(on: RunLoop.main) .sink { [weak self] _ in - self?.updateColors(PrivateBrowsingManager.shared.isPrivateBrowsing) + self?.updateColors(privateBrowsingManager.isPrivateBrowsing) } .store(in: &cancellables) } diff --git a/Sources/Brave/Frontend/Browser/Toolbars/UrlBar/TabLocationView.swift b/Sources/Brave/Frontend/Browser/Toolbars/UrlBar/TabLocationView.swift index 94cf15e0ab7..b0467df8bd5 100644 --- a/Sources/Brave/Frontend/Browser/Toolbars/UrlBar/TabLocationView.swift +++ b/Sources/Brave/Frontend/Browser/Toolbars/UrlBar/TabLocationView.swift @@ -238,8 +238,8 @@ class TabLocationView: UIView { $0.insetsLayoutMarginsFromSafeArea = false } - override init(frame: CGRect) { - super.init(frame: frame) + init(privateBrowsingManager: PrivateBrowsingManager) { + super.init(frame: .zero) backgroundColor = .braveBackground @@ -286,7 +286,7 @@ class TabLocationView: UIView { dragInteraction.allowsSimultaneousRecognitionDuringLift = true self.addInteraction(dragInteraction) - privateModeCancellable = PrivateBrowsingManager.shared.$isPrivateBrowsing + privateModeCancellable = privateBrowsingManager.$isPrivateBrowsing .removeDuplicates() .sink(receiveValue: { [weak self] isPrivateBrowsing in self?.updateColors(isPrivateBrowsing) diff --git a/Sources/Brave/Frontend/Browser/Toolbars/UrlBar/TopToolbarView.swift b/Sources/Brave/Frontend/Browser/Toolbars/UrlBar/TopToolbarView.swift index 002184e0c7d..41e49b2be48 100644 --- a/Sources/Brave/Frontend/Browser/Toolbars/UrlBar/TopToolbarView.swift +++ b/Sources/Brave/Frontend/Browser/Toolbars/UrlBar/TopToolbarView.swift @@ -97,7 +97,7 @@ class TopToolbarView: UIView, ToolbarProtocol { fileprivate var locationTextField: UrlBarTextField? lazy var locationView: TabLocationView = { - let locationView = TabLocationView() + let locationView = TabLocationView(privateBrowsingManager: self.privateBrowsingManager) locationView.translatesAutoresizingMaskIntoConstraints = false locationView.readerModeState = ReaderModeState.unavailable locationView.delegate = self @@ -184,7 +184,7 @@ class TopToolbarView: UIView, ToolbarProtocol { var shieldIcon = "brave.logo" let shieldsOffIcon = "brave.logo.greyscale" if let currentURL = currentURL { - let isPrivateBrowsing = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivateBrowsing = privateBrowsingManager.isPrivateBrowsing let domain = Domain.getOrCreate(forUrl: currentURL, persistent: !isPrivateBrowsing) if domain.areAllShieldsOff { shieldIcon = shieldsOffIcon @@ -209,9 +209,11 @@ class TopToolbarView: UIView, ToolbarProtocol { } private(set) var displayTabTraySwipeGestureRecognizer: UISwipeGestureRecognizer? + private let privateBrowsingManager: PrivateBrowsingManager - override init(frame: CGRect) { - super.init(frame: frame) + init(privateBrowsingManager: PrivateBrowsingManager) { + self.privateBrowsingManager = privateBrowsingManager + super.init(frame: .zero) backgroundColor = Preferences.General.nightModeEnabled.value ? .nightModeBackground : .urlBarBackground @@ -255,7 +257,7 @@ class TopToolbarView: UIView, ToolbarProtocol { // Make sure we hide any views that shouldn't be showing in non-overlay mode. updateViewsForOverlayModeAndToolbarChanges() - privateModeCancellable = PrivateBrowsingManager.shared + privateModeCancellable = privateBrowsingManager .$isPrivateBrowsing .removeDuplicates() .sink(receiveValue: { [weak self] isPrivateBrowsing in @@ -265,7 +267,7 @@ class TopToolbarView: UIView, ToolbarProtocol { Preferences.General.nightModeEnabled.objectWillChange .receive(on: RunLoop.main) .sink { [weak self] _ in - self?.updateColors(PrivateBrowsingManager.shared.isPrivateBrowsing) + self?.updateColors(privateBrowsingManager.isPrivateBrowsing) } .store(in: &cancellables) diff --git a/Sources/Brave/Frontend/ClientPreferences.swift b/Sources/Brave/Frontend/ClientPreferences.swift index f645536a6da..f800201e2ce 100644 --- a/Sources/Brave/Frontend/ClientPreferences.swift +++ b/Sources/Brave/Frontend/ClientPreferences.swift @@ -123,6 +123,8 @@ extension Preferences { static let lockWithPasscode = Option(key: "privacy.lock-with-passcode", default: false) /// Forces all private tabs public static let privateBrowsingOnly = Option(key: "privacy.private-only", default: false) + /// Whether or not private browsing tabs can be session restored (persistent private browsing) + public static let persistentPrivateBrowsing = Option(key: "privacy.private-browsing-persistence", default: false) /// Blocks all cookies and access to local storage static let blockAllCookies = Option(key: "privacy.block-all-cookies", default: false) /// The toggles states for clear private data screen diff --git a/Sources/Brave/Frontend/Login/LoginListViewController.swift b/Sources/Brave/Frontend/Login/LoginListViewController.swift index 0ec78190abc..9b0b31a5c74 100644 --- a/Sources/Brave/Frontend/Login/LoginListViewController.swift +++ b/Sources/Brave/Frontend/Login/LoginListViewController.swift @@ -204,7 +204,7 @@ extension LoginListViewController { $0.layer.cornerCurve = .continuous $0.layer.masksToBounds = true if let signOnRealmURL = URL(string: loginInfo.signOnRealm) { - $0.loadFavicon(for: signOnRealmURL) + $0.loadFavicon(for: signOnRealmURL, isPrivateBrowsing: false) } } diff --git a/Sources/Brave/Frontend/Settings/SearchCustomEngineViewController.swift b/Sources/Brave/Frontend/Settings/SearchCustomEngineViewController.swift index 40d6aca27de..a05b903e573 100644 --- a/Sources/Brave/Frontend/Settings/SearchCustomEngineViewController.swift +++ b/Sources/Brave/Frontend/Settings/SearchCustomEngineViewController.swift @@ -41,6 +41,7 @@ class SearchCustomEngineViewController: UIViewController { // MARK: Properties private var profile: Profile + private var privateBrowsingManager: PrivateBrowsingManager private var urlText: String? @@ -84,8 +85,9 @@ class SearchCustomEngineViewController: UIViewController { // MARK: Lifecycle - init(profile: Profile) { + init(profile: Profile, privateBrowsingManager: PrivateBrowsingManager) { self.profile = profile + self.privateBrowsingManager = privateBrowsingManager super.init(nibName: nil, bundle: nil) } @@ -170,7 +172,7 @@ class SearchCustomEngineViewController: UIViewController { // MARK: Actions - @objc func checkAddEngineType(_ nav: UINavigationController?) { + @objc func checkAddEngineType() { if isAutoAddEnabled { addOpenSearchEngine() } else { @@ -392,7 +394,7 @@ extension SearchCustomEngineViewController { faviconTask?.cancel() faviconTask = Task { @MainActor in do { - let icon = try await FaviconFetcher.loadIcon(url: url, persistent: !PrivateBrowsingManager.shared.isPrivateBrowsing) + let icon = try await FaviconFetcher.loadIcon(url: url, persistent: !privateBrowsingManager.isPrivateBrowsing) self.faviconImage = icon.image ?? Favicon.defaultImage } catch { self.faviconImage = Favicon.defaultImage @@ -474,7 +476,7 @@ extension SearchCustomEngineViewController { faviconTask?.cancel() faviconTask = Task { @MainActor in - let favicon = try? await FaviconFetcher.loadIcon(url: hostUrl, persistent: !PrivateBrowsingManager.shared.isPrivateBrowsing) + let favicon = try? await FaviconFetcher.loadIcon(url: hostUrl, persistent: !privateBrowsingManager.isPrivateBrowsing) if let image = favicon?.image { engineImage = image } diff --git a/Sources/Brave/Frontend/Settings/SearchQuickEnginesViewController.swift b/Sources/Brave/Frontend/Settings/SearchQuickEnginesViewController.swift index 439584771fb..2576854a495 100644 --- a/Sources/Brave/Frontend/Settings/SearchQuickEnginesViewController.swift +++ b/Sources/Brave/Frontend/Settings/SearchQuickEnginesViewController.swift @@ -28,11 +28,13 @@ class SearchQuickEnginesViewController: UITableViewController { private var searchEngines: SearchEngines private let profile: Profile + private let isPrivateBrowsing: Bool // MARK: Lifecycle - init(profile: Profile) { + init(profile: Profile, isPrivateBrowsing: Bool) { self.profile = profile + self.isPrivateBrowsing = isPrivateBrowsing self.searchEngines = profile.searchEngines super.init(nibName: nil, bundle: nil) } @@ -142,7 +144,7 @@ extension SearchQuickEnginesViewController { if toggle.isOn { searchEngines.enableEngine(engine) } else { - searchEngines.disableEngine(engine) + searchEngines.disableEngine(engine, isPrivateBrowsing: isPrivateBrowsing) } } } diff --git a/Sources/Brave/Frontend/Settings/SearchSettingsTableViewController.swift b/Sources/Brave/Frontend/Settings/SearchSettingsTableViewController.swift index 1cfc5cf6da5..4e54a9321b9 100644 --- a/Sources/Brave/Frontend/Settings/SearchSettingsTableViewController.swift +++ b/Sources/Brave/Frontend/Settings/SearchSettingsTableViewController.swift @@ -59,6 +59,7 @@ class SearchSettingsTableViewController: UITableViewController { private var searchEngines: SearchEngines private let profile: Profile private var showDeletion = false + private var privateBrowsingManager: PrivateBrowsingManager private func searchPickerEngines(type: DefaultEngineType) -> [OpenSearchEngine] { let isPrivate = type == .privateMode @@ -90,8 +91,9 @@ class SearchSettingsTableViewController: UITableViewController { // MARK: Lifecycle - init(profile: Profile) { + init(profile: Profile, privateBrowsingManager: PrivateBrowsingManager) { self.profile = profile + self.privateBrowsingManager = privateBrowsingManager self.searchEngines = profile.searchEngines super.init(nibName: nil, bundle: nil) } @@ -289,10 +291,10 @@ class SearchSettingsTableViewController: UITableViewController { } else if indexPath.section == Section.current.rawValue && indexPath.item == CurrentEngineType.private.rawValue { navigationController?.pushViewController(configureSearchEnginePicker(.privateMode), animated: true) } else if indexPath.section == Section.current.rawValue && indexPath.item == CurrentEngineType.quick.rawValue { - let quickSearchEnginesViewController = SearchQuickEnginesViewController(profile: profile) + let quickSearchEnginesViewController = SearchQuickEnginesViewController(profile: profile, isPrivateBrowsing: privateBrowsingManager.isPrivateBrowsing) navigationController?.pushViewController(quickSearchEnginesViewController, animated: true) } else if indexPath.section == Section.customSearch.rawValue && indexPath.item == customSearchEngines.count { - let customEngineViewController = SearchCustomEngineViewController(profile: profile) + let customEngineViewController = SearchCustomEngineViewController(profile: profile, privateBrowsingManager: privateBrowsingManager) navigationController?.pushViewController(customEngineViewController, animated: true) } diff --git a/Sources/Brave/Frontend/Settings/SettingsViewController.swift b/Sources/Brave/Frontend/Settings/SettingsViewController.swift index 555579bf446..df80d7b5306 100644 --- a/Sources/Brave/Frontend/Settings/SettingsViewController.swift +++ b/Sources/Brave/Frontend/Settings/SettingsViewController.swift @@ -315,7 +315,7 @@ class SettingsViewController: TableViewController { Row( text: Strings.searchEngines, selection: { [unowned self] in - let viewController = SearchSettingsTableViewController(profile: self.profile) + let viewController = SearchSettingsTableViewController(profile: self.profile, privateBrowsingManager: tabManager.privateBrowsingManager) self.navigationController?.pushViewController(viewController, animated: true) }, image: UIImage(braveSystemNamed: "leo.search"), accessory: .disclosureIndicator, cellClass: MultilineValue1Cell.self), Row( @@ -507,7 +507,7 @@ class SettingsViewController: TableViewController { )) // We do NOT persistently save page-zoom settings in Private Browsing - if !PrivateBrowsingManager.shared.isPrivateBrowsing { + if !tabManager.privateBrowsingManager.isPrivateBrowsing { display.rows.append( Row(text: Strings.PageZoom.settingsMenuTitle, selection: { [weak self] in diff --git a/Sources/Brave/Frontend/Settings/Shields/OtherPrivacySettingsSectionView.swift b/Sources/Brave/Frontend/Settings/Shields/OtherPrivacySettingsSectionView.swift index 3dfc390891d..721e8dd139c 100644 --- a/Sources/Brave/Frontend/Settings/Shields/OtherPrivacySettingsSectionView.swift +++ b/Sources/Brave/Frontend/Settings/Shields/OtherPrivacySettingsSectionView.swift @@ -7,6 +7,7 @@ import SwiftUI import Preferences import Strings import BraveShared +import Data struct OtherPrivacySettingsSectionView: View { @State private var showPrivateBrowsingConfirmation = false @@ -34,6 +35,7 @@ struct OtherPrivacySettingsSectionView: View { Task { @MainActor in try await Task.sleep(nanoseconds: NSEC_PER_MSEC * 100) + Preferences.Privacy.persistentPrivateBrowsing.value = false await settings.clearPrivateData([CookiesAndCacheClearable()]) // First remove all tabs so that only a blank tab exists. @@ -52,6 +54,25 @@ struct OtherPrivacySettingsSectionView: View { ) }) + if !Preferences.Privacy.privateBrowsingOnly.value { + OptionToggleView(title: Strings.persistentPrivateBrowsing, + subtitle: nil, + option: Preferences.Privacy.persistentPrivateBrowsing) { newValue in + Task { @MainActor in + if newValue { + settings.tabManager.saveAllTabs() + } else { + let tabs = settings.tabManager.allTabs.filter({ $0.isPrivate }) + if settings.tabManager.privateBrowsingManager.isPrivateBrowsing { + SessionTab.deleteAll(tabIds: tabs.map({ $0.id })) + } else { + settings.tabManager.removeTabs(tabs) + } + } + } + } + } + ShieldToggleView( title: Strings.blockMobileAnnoyances, subtitle: nil, diff --git a/Sources/Brave/Frontend/Shields/ShieldsActivityItemSourceProvider.swift b/Sources/Brave/Frontend/Shields/ShieldsActivityItemSourceProvider.swift index 79b703a094b..b4d99a87464 100644 --- a/Sources/Brave/Frontend/Shields/ShieldsActivityItemSourceProvider.swift +++ b/Sources/Brave/Frontend/Shields/ShieldsActivityItemSourceProvider.swift @@ -23,12 +23,13 @@ final class ShieldsActivityItemSourceProvider { static let shared = ShieldsActivityItemSourceProvider() - func setupGlobalShieldsActivityController() -> UIActivityViewController { + func setupGlobalShieldsActivityController(isPrivateBrowsing: Bool) -> UIActivityViewController { let backgroundImage = UIImage(named: "share-activity-background", in: .module, compatibleWith: nil)! let statsView = UIView(frame: CGRect(size: backgroundImage.size)).then { let backgroundImageView = UIImageView(image: backgroundImage) let statsInfoView = BraveShieldStatsView() + statsInfoView.isPrivateBrowsing = isPrivateBrowsing $0.addSubview(backgroundImageView) $0.addSubview(statsInfoView) diff --git a/Sources/Brave/Frontend/Shields/ShieldsViewController.swift b/Sources/Brave/Frontend/Shields/ShieldsViewController.swift index f936d5f914f..843f0fe60d8 100644 --- a/Sources/Brave/Frontend/Shields/ShieldsViewController.swift +++ b/Sources/Brave/Frontend/Shields/ShieldsViewController.swift @@ -62,7 +62,7 @@ class ShieldsViewController: UIViewController, PopoverContentComponent { private func updateToggleStatus() { var domain: Domain? if let url = url { - let isPrivateBrowsing = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivateBrowsing = tab.isPrivate domain = Domain.getOrCreate(forUrl: url, persistent: !isPrivateBrowsing) } @@ -104,7 +104,7 @@ class ShieldsViewController: UIViewController, PopoverContentComponent { let isOn = allOff ? !on : on Domain.setBraveShield( forUrl: url, shield: shield, isOn: isOn, - isPrivateBrowsing: PrivateBrowsingManager.shared.isPrivateBrowsing) + isPrivateBrowsing: tab.isPrivate) } private func updateGlobalShieldState(_ on: Bool, animated: Bool = false) { @@ -229,7 +229,7 @@ class ShieldsViewController: UIViewController, PopoverContentComponent { super.viewDidLoad() if let url = url { - shieldsView.simpleShieldView.faviconImageView.loadFavicon(for: url) + shieldsView.simpleShieldView.faviconImageView.loadFavicon(for: url, isPrivateBrowsing: tab.isPrivate) } else { shieldsView.simpleShieldView.faviconImageView.isHidden = true } @@ -309,7 +309,7 @@ class ShieldsViewController: UIViewController, PopoverContentComponent { @objc private func tappedShareShieldsButton() { let globalShieldsActivityController = - ShieldsActivityItemSourceProvider.shared.setupGlobalShieldsActivityController() + ShieldsActivityItemSourceProvider.shared.setupGlobalShieldsActivityController(isPrivateBrowsing: tab.isPrivate) globalShieldsActivityController.popoverPresentationController?.sourceView = view present(globalShieldsActivityController, animated: true, completion: nil) diff --git a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/BraveSearchScriptHandler.swift b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/BraveSearchScriptHandler.swift index 6077fd6ccb5..7803e334741 100644 --- a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/BraveSearchScriptHandler.swift +++ b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/BraveSearchScriptHandler.swift @@ -98,7 +98,7 @@ class BraveSearchScriptHandler: TabContentScript { } private func handleCanSetBraveSearchAsDefault(replyHandler: (Any?, String?) -> Void) { - if PrivateBrowsingManager.shared.isPrivateBrowsing { + if tab?.isPrivate == true { Logger.module.debug("Private mode detected, skipping setting Brave Search as a default") replyHandler(false, nil) return diff --git a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/BraveTalkScriptHandler.swift b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/BraveTalkScriptHandler.swift index 89f6f4c11dd..faa37a3a60e 100644 --- a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/BraveTalkScriptHandler.swift +++ b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/BraveTalkScriptHandler.swift @@ -123,7 +123,7 @@ class BraveTalkScriptHandler: TabContentScript { } private func handleBraveRequestAdsEnabled(_ replyHandler: @escaping (Any?, String?) -> Void) { - guard let rewards = rewards, !PrivateBrowsingManager.shared.isPrivateBrowsing else { + guard let rewards = rewards, tab?.isPrivate != true else { replyHandler(false, nil) return } diff --git a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/ContentBlockerScriptHandler.swift b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/ContentBlockerScriptHandler.swift index 178289d6d56..49eef6cd8fe 100644 --- a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/ContentBlockerScriptHandler.swift +++ b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/ContentBlockerScriptHandler.swift @@ -65,7 +65,7 @@ extension ContentBlockerHelper: TabContentScript { let dto = try JSONDecoder().decode(ContentBlockerDTO.self, from: data) Task { @MainActor in - let isPrivateBrowsing = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivateBrowsing = self.tab?.isPrivate == true let domain = Domain.getOrCreate(forUrl: currentTabURL, persistent: !isPrivateBrowsing) if domain.areAllShieldsOff { // if domain is "all_off", can just skip @@ -109,7 +109,7 @@ extension ContentBlockerHelper: TabContentScript { if blockedType == .ad, Preferences.PrivacyReports.captureShieldsData.value, let domainURL = URL(string: domainURLString), let blockedResourceHost = requestURL.baseDomain, - !PrivateBrowsingManager.shared.isPrivateBrowsing { + tab?.isPrivate != true { PrivacyReportsManager.pendingBlockedRequests.append((blockedResourceHost, domainURL, Date())) } diff --git a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/RequestBlockingContentScriptHandler.swift b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/RequestBlockingContentScriptHandler.swift index cb1b34991fc..3ed3e9403b3 100644 --- a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/RequestBlockingContentScriptHandler.swift +++ b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/RequestBlockingContentScriptHandler.swift @@ -66,7 +66,7 @@ class RequestBlockingContentScriptHandler: TabContentScript { // we use `NSURL(idnString: String)` to parse them guard let requestURL = NSURL(idnString: dto.data.resourceURL) as URL? else { return } guard let sourceURL = NSURL(idnString: dto.data.sourceURL) as URL? else { return } - let isPrivateBrowsing = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivateBrowsing = tab.isPrivate Task { @MainActor in let domain = Domain.getOrCreate(forUrl: currentTabURL, persistent: !isPrivateBrowsing) @@ -87,7 +87,7 @@ class RequestBlockingContentScriptHandler: TabContentScript { if shouldBlock, Preferences.PrivacyReports.captureShieldsData.value, let domainURL = URL(string: domainURLString), let blockedResourceHost = requestURL.baseDomain, - !PrivateBrowsingManager.shared.isPrivateBrowsing { + !isPrivateBrowsing { PrivacyReportsManager.pendingBlockedRequests.append((blockedResourceHost, domainURL, Date())) } diff --git a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/RewardsReportingScriptHandler.swift b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/RewardsReportingScriptHandler.swift index 5b7a654637a..acdd7f3dba3 100644 --- a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/RewardsReportingScriptHandler.swift +++ b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/ScriptHandlers/Paged/RewardsReportingScriptHandler.swift @@ -43,7 +43,7 @@ class RewardsReportingScriptHandler: TabContentScript { var referrerUrl: String? } - if PrivateBrowsingManager.shared.isPrivateBrowsing || !rewards.isEnabled { + if tab?.isPrivate == true || !rewards.isEnabled { return } diff --git a/Sources/Brave/Migration/Migration.swift b/Sources/Brave/Migration/Migration.swift index 1a1205d07f6..2b9b4e04489 100644 --- a/Sources/Brave/Migration/Migration.swift +++ b/Sources/Brave/Migration/Migration.swift @@ -74,7 +74,7 @@ public class Migration { // Migrate from TabMO to SessionTab and SessionWindow public static func migrateTabStateToWebkitState(diskImageStore: DiskImageStore?) { - let isPrivate = PrivateBrowsingManager.shared.isPrivateBrowsing + let isPrivate = false // Private tabs at the time of writing this code was never persistent, so it wouldn't "restore". if Preferences.Migration.tabMigrationToInteractionStateCompleted.value { SessionWindow.createIfNeeded(index: 0, isPrivate: isPrivate, isSelected: true) diff --git a/Sources/Brave/Shortcuts/ActivityShortcutManager.swift b/Sources/Brave/Shortcuts/ActivityShortcutManager.swift index e6816270a41..8e5bfa259a7 100644 --- a/Sources/Brave/Shortcuts/ActivityShortcutManager.swift +++ b/Sources/Brave/Shortcuts/ActivityShortcutManager.swift @@ -129,7 +129,7 @@ public class ActivityShortcutManager: NSObject { private func handleActivityDetails(type: ActivityType, using bvc: BrowserViewController) { switch type { case .newTab: - bvc.openBlankNewTab(attemptLocationFieldFocus: false, isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing, isExternal: true) + bvc.openBlankNewTab(attemptLocationFieldFocus: false, isPrivate: bvc.privateBrowsingManager.isPrivateBrowsing, isExternal: true) bvc.popToBVC() case .newPrivateTab: bvc.openBlankNewTab(attemptLocationFieldFocus: false, isPrivate: true, isExternal: true) @@ -137,7 +137,7 @@ public class ActivityShortcutManager: NSObject { case .clearBrowsingHistory: bvc.clearHistoryAndOpenNewTab() case .enableBraveVPN: - bvc.openBlankNewTab(attemptLocationFieldFocus: false, isPrivate: PrivateBrowsingManager.shared.isPrivateBrowsing, isExternal: true) + bvc.openBlankNewTab(attemptLocationFieldFocus: false, isPrivate: bvc.privateBrowsingManager.isPrivateBrowsing, isExternal: true) bvc.popToBVC() switch BraveVPN.vpnState { @@ -215,8 +215,7 @@ public class ActivityShortcutManager: NSObject { // MARK: Intent Donation Methods public func donateCustomIntent(for type: IntentType, with urlString: String) { - guard !PrivateBrowsingManager.shared.isPrivateBrowsing, - !urlString.isEmpty, + guard !urlString.isEmpty, URL(string: urlString) != nil else { return } diff --git a/Sources/Brave/States/AppState.swift b/Sources/Brave/States/AppState.swift index 4ae4880da54..7aabf82fd3f 100644 --- a/Sources/Brave/States/AppState.swift +++ b/Sources/Brave/States/AppState.swift @@ -29,6 +29,7 @@ public class AppState { public let dau: DAU public let migration: Migration public let profile: Profile + public let rewards: BraveRewards public var state: State = .launching(options: [:], active: false) { didSet { @@ -59,8 +60,7 @@ public class AppState { namespace: "TabManagerScreenshots", quality: UIConstants.screenshotQuality) } catch { - //log.error("Failed to create an image store for files: \(profile.files.rootPath) and namespace: \"TabManagerScreenshots\": \(error.localizedDescription)") - assertionFailure() + Logger.module.error("Failed to create an image store for files: \(self.profile.files.rootPath) and namespace: \"TabManagerScreenshots\": \(error.localizedDescription)") } return nil }() @@ -86,9 +86,13 @@ public class AppState { // Perform Migrations migration.launchMigrations(keyPrefix: profile.prefs.getBranchPrefix(), profile: profile) + // Setup Rewards & Ads + let configuration = BraveRewards.Configuration.current() + Self.migrateAdsConfirmations(for: configuration) + rewards = BraveRewards(configuration: configuration) + // Setup Custom URL scheme handlers setupCustomSchemeHandlers(profile: profile) - } public enum State { @@ -196,4 +200,33 @@ public class AppState { InternalSchemeHandler.responders[path] = responder } } + + private static func migrateAdsConfirmations(for configruation: BraveRewards.Configuration) { + // To ensure after a user launches 1.21 that their ads confirmations, viewed count and + // estimated payout remain correct. + // + // This hack is unfortunately neccessary due to a missed migration path when moving + // confirmations from ledger to ads, we must extract `confirmations.json` out of ledger's + // state file and save it as a new file under the ads directory. + let base = configruation.storageURL + let ledgerStateContainer = base.appendingPathComponent("ledger/random_state.plist") + let adsConfirmations = base.appendingPathComponent("ads/confirmations.json") + let fm = FileManager.default + + if !fm.fileExists(atPath: ledgerStateContainer.path) || fm.fileExists(atPath: adsConfirmations.path) { + // Nothing to migrate or already migrated + return + } + + do { + let contents = NSDictionary(contentsOfFile: ledgerStateContainer.path) + guard let confirmations = contents?["confirmations.json"] as? String else { + adsRewardsLog.debug("No confirmations found to migrate in ledger's state container") + return + } + try confirmations.write(toFile: adsConfirmations.path, atomically: true, encoding: .utf8) + } catch { + adsRewardsLog.error("Failed to migrate confirmations.json to ads folder: \(error.localizedDescription)") + } + } } diff --git a/Sources/BraveStrings/BraveStrings.swift b/Sources/BraveStrings/BraveStrings.swift index 121258bfd63..2c9f2588d02 100644 --- a/Sources/BraveStrings/BraveStrings.swift +++ b/Sources/BraveStrings/BraveStrings.swift @@ -1017,6 +1017,7 @@ extension Strings { public static let mediaAutoBackgrounding = NSLocalizedString("MediaAutoBackgrounding", tableName: "BraveShared", bundle: .module, value: "Enable Background Audio", comment: "Setting to allow media to play in the background") public static let showTabsBar = NSLocalizedString("ShowTabsBar", tableName: "BraveShared", bundle: .module, value: "Tabs Bar", comment: "Setting to show/hide the tabs bar") public static let privateBrowsingOnly = NSLocalizedString("PrivateBrowsingOnly", tableName: "BraveShared", bundle: .module, value: "Private Browsing Only", comment: "Setting to keep app in private mode") + public static let persistentPrivateBrowsing = NSLocalizedString("PersistentPrivateBrowsing", tableName: "BraveShared", bundle: .module, value: "Persistent Private Browsing", comment: "Setting to allow the app to restore private browsing tabs") public static let shieldsDefaults = NSLocalizedString("ShieldsDefaults", tableName: "BraveShared", bundle: .module, value: "Brave Shields Global Defaults", comment: "Section title for adbblock, tracking protection, HTTPS-E, and cookies") public static let shieldsDefaultsFooter = NSLocalizedString("ShieldsDefaultsFooter", tableName: "BraveShared", bundle: .module, value: "These are the default Shields settings for new sites. Changing these won't affect your existing per-site settings.", comment: "Section footer for global shields defaults") public static let HTTPSEverywhere = NSLocalizedString("HTTPSEverywhere", tableName: "BraveShared", bundle: .module, value: "Upgrade Connections to HTTPS", comment: "") diff --git a/Sources/BraveWallet/Crypto/Stores/KeyringStore.swift b/Sources/BraveWallet/Crypto/Stores/KeyringStore.swift index 37a7097da0c..1d929e9c39d 100644 --- a/Sources/BraveWallet/Crypto/Stores/KeyringStore.swift +++ b/Sources/BraveWallet/Crypto/Stores/KeyringStore.swift @@ -111,6 +111,13 @@ public class KeyringStore: ObservableObject { /// The origin of the active tab (if applicable). Used for fetching/selecting network for the DApp origin. public var origin: URLOrigin? + + /// If this KeyringStore instance is creating a wallet. + /// This flag is used to know when to dismiss onboarding when multiple windows are visible. + private var isCreatingWallet = false + /// If this KeyringStore instance is restoring a wallet. + /// This flag is used to know when to dismiss onboarding when multiple windows are visible. + private var isRestoringWallet = false private let keyringService: BraveWalletKeyringService private let walletService: BraveWalletBraveWalletService @@ -182,6 +189,8 @@ public class KeyringStore: ObservableObject { } func markOnboardingCompleted() { + self.isCreatingWallet = false + self.isRestoringWallet = false self.isOnboardingVisible = false } @@ -230,6 +239,7 @@ public class KeyringStore: ObservableObject { } func createWallet(password: String, completion: ((String) -> Void)? = nil) { + isCreatingWallet = true keyringService.createWallet(password) { [weak self] mnemonic in self?.updateKeyringInfo() completion?(mnemonic) @@ -251,6 +261,7 @@ public class KeyringStore: ObservableObject { } func restoreWallet(phrase: String, password: String, isLegacyBraveWallet: Bool, completion: ((Bool) -> Void)? = nil) { + isRestoringWallet = true keyringService.restoreWallet( phrase, password: password, @@ -397,6 +408,11 @@ extension KeyringStore: BraveWalletKeyringServiceObserver { } public func keyringCreated(_ keyringId: String) { + if isOnboardingVisible, !isCreatingWallet, keyringId == BraveWallet.DefaultKeyringId { + // Another window has created a wallet. We should dismiss onboarding on this + // window and allow the other window to continue with it's onboarding flow. + isOnboardingVisible = false + } Task { @MainActor in let newKeyring = await keyringService.keyringInfo(keyringId) if let newKeyringCoin = newKeyring.coin { @@ -411,6 +427,11 @@ extension KeyringStore: BraveWalletKeyringServiceObserver { } public func keyringRestored(_ keyringId: String) { + if isOnboardingVisible && !isRestoringWallet, keyringId == BraveWallet.DefaultKeyringId { + // Another window has restored a wallet. We should dismiss onboarding on this + // window and allow the other window to continue with it's onboarding flow. + isOnboardingVisible = false + } updateKeyringInfo() } diff --git a/Sources/Data/models/SessionTab.swift b/Sources/Data/models/SessionTab.swift index 0a0fee5cf03..c087e433ba7 100644 --- a/Sources/Data/models/SessionTab.swift +++ b/Sources/Data/models/SessionTab.swift @@ -127,6 +127,11 @@ extension SessionTab { deleteAll(context: .new(inMemory: false)) } + public static func deleteAll(tabIds: [UUID]) { + let predicate = NSPredicate(format: "\(#keyPath(SessionTab.tabId)) IN %@", tabIds) + deleteAll(predicate: predicate, context: .new(inMemory: false)) + } + public static func deleteAll(olderThan timeInterval: TimeInterval) { let lastUpdatedKeyPath = #keyPath(SessionTab.lastUpdated) let date = Date().advanced(by: -timeInterval) as NSDate @@ -207,7 +212,7 @@ extension SessionTab { } } - public static func createIfNeeded(windowId: UUID, tabId: UUID, title: String, tabURL: URL) { + public static func createIfNeeded(windowId: UUID, tabId: UUID, title: String, tabURL: URL, isPrivate: Bool) { DataController.perform { context in guard !SessionTab.exists(tabId: tabId, in: context), let window = SessionWindow.from(windowId: windowId, in: context) else { return } @@ -217,7 +222,7 @@ extension SessionTab { sessionTabGroup: nil, index: Int32(window.sessionTabs?.count ?? 0), interactionState: Data(), - isPrivate: false, + isPrivate: isPrivate, isSelected: false, lastUpdated: .now, screenshotData: Data(), diff --git a/Sources/Data/models/SessionWindow.swift b/Sources/Data/models/SessionWindow.swift index 377294acc00..defccb0475d 100644 --- a/Sources/Data/models/SessionWindow.swift +++ b/Sources/Data/models/SessionWindow.swift @@ -112,7 +112,7 @@ extension SessionWindow { /// Since only one window can be active at a time, all other windows are marked as deselected public static func setSelected(windowId: UUID) { DataController.perform { context in - guard let window = Self.from(windowId: windowId) else { return } + guard let window = Self.from(windowId: windowId, in: context) else { return } let predicate = NSPredicate(format: "isSelected == true") all(where: predicate, context: context)?.forEach {