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..5b2eb6547c9 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() + } + + 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 {