From 3485b2e4917d4c3c534ca369be60c6737bcd2a3f Mon Sep 17 00:00:00 2001 From: Juan Manuel Pereira Date: Tue, 26 Nov 2024 14:44:21 -0300 Subject: [PATCH] Implement hiding toolbars on full screen --- DuckDuckGo/Common/Localizables/UserText.swift | 1 + .../Utilities/UserDefaultsWrapper.swift | 2 + DuckDuckGo/Localizable.xcstrings | 14 ++++++- DuckDuckGo/MainWindow/MainView.swift | 15 +++++-- .../MainWindow/MainViewController.swift | 2 +- .../MainWindow/MainWindowController.swift | 42 +++++++++++++++++-- .../Model/AppearancePreferences.swift | 11 +++++ .../View/PreferencesAppearanceView.swift | 2 + .../AppearancePreferencesTests.swift | 10 ++++- .../MockAppearancePreferencesPersistor.swift | 2 + 10 files changed, 90 insertions(+), 11 deletions(-) diff --git a/DuckDuckGo/Common/Localizables/UserText.swift b/DuckDuckGo/Common/Localizables/UserText.swift index 6d08fbb4a6..4ec0364d66 100644 --- a/DuckDuckGo/Common/Localizables/UserText.swift +++ b/DuckDuckGo/Common/Localizables/UserText.swift @@ -704,6 +704,7 @@ struct UserText { static let themeSystem = NSLocalizedString("preferences.appearance.theme.system", value: "System", comment: "In the preferences for themes, the option to select for use the change the mode based on the system preferences.") static let addressBar = NSLocalizedString("preferences.appearance.address-bar", value: "Address Bar", comment: "Theme preferences") static let showFullWebsiteAddress = NSLocalizedString("preferences.appearance.show-full-url", value: "Full website address", comment: "Option to show full URL in the address bar") + static let hideToolbarsOnFullScreen = NSLocalizedString("preferences.appearance.hide-toolbars-on-full-screen", value: "Remove Tabs and Bookmarks Bar toolbars on Full Screen", comment: "Option to hide tabs and bookmarks bar toolbars on full screen") static let showAutocompleteSuggestions = NSLocalizedString("preferences.appearance.show-autocomplete-suggestions", value: "Autocomplete suggestions", comment: "Option to show autocomplete suggestions in the address bar") static let customizeBackground = NSLocalizedString("preferences.appearance.customize-background", value: "Customize Background", comment: "Button to open home page background customization options") static let zoomPickerTitle = NSLocalizedString("preferences.appearance.zoom-picker", value: "Default page zoom", comment: "Default page zoom picker title") diff --git a/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift b/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift index 7fad506059..6895c75e24 100644 --- a/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift +++ b/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift @@ -155,6 +155,8 @@ public struct UserDefaultsWrapper { case centerAlignedBookmarksBar = "bookmarks.bar.center.aligned" case lastBookmarksBarUsagePixelSendDate = "bookmarks.bar.last-usage-pixel-send-date" + case hideToolbarsOnFullScreen = "hide.toolbars.on.fullscren" + case pinnedViews = "pinning.pinned-views" case manuallyToggledPinnedViews = "pinning.manually-toggled-pinned-views" diff --git a/DuckDuckGo/Localizable.xcstrings b/DuckDuckGo/Localizable.xcstrings index f90ccc2115..95e0f0ed06 100644 --- a/DuckDuckGo/Localizable.xcstrings +++ b/DuckDuckGo/Localizable.xcstrings @@ -52814,6 +52814,18 @@ } } }, + "preferences.appearance.hide-toolbars-on-full-screen" : { + "comment" : "Option to hide tabs and bookmarks bar toolbars on full screen", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Remove Tabs and Bookmarks Bar toolbars on Full Screen" + } + } + } + }, "preferences.appearance.show-autocomplete-suggestions" : { "comment" : "Option to show autocomplete suggestions in the address bar", "extractionState" : "extracted_with_value", @@ -64606,4 +64618,4 @@ } }, "version" : "1.0" -} +} \ No newline at end of file diff --git a/DuckDuckGo/MainWindow/MainView.swift b/DuckDuckGo/MainWindow/MainView.swift index ca6b4e1357..92975a6b6a 100644 --- a/DuckDuckGo/MainWindow/MainView.swift +++ b/DuckDuckGo/MainWindow/MainView.swift @@ -31,6 +31,9 @@ final class MainView: NSView { private(set) var navigationBarTopConstraint: NSLayoutConstraint! private(set) var bookmarksBarHeightConstraint: NSLayoutConstraint! + private(set) var webContainerTopConstraint: NSLayoutConstraint! + private(set) var webContainerTopConstraintToNavigation: NSLayoutConstraint! + private(set) var tabBarHeightConstraint: NSLayoutConstraint! @Published var isMouseAboveWebView: Bool = false @@ -59,14 +62,19 @@ final class MainView: NSView { private func addConstraints() { bookmarksBarHeightConstraint = bookmarksBarContainerView.heightAnchor.constraint(equalToConstant: 34) - + tabBarHeightConstraint = tabBarContainerView.heightAnchor.constraint(equalToConstant: 38) navigationBarTopConstraint = navigationBarContainerView.topAnchor.constraint(equalTo: topAnchor, constant: 38) + webContainerTopConstraint = webContainerView.topAnchor.constraint(equalTo: bookmarksBarContainerView.bottomAnchor) + webContainerTopConstraintToNavigation = webContainerView.topAnchor.constraint(equalTo: navigationBarContainerView.bottomAnchor) + + webContainerTopConstraint.priority = .defaultHigh + webContainerTopConstraintToNavigation.priority = .defaultLow NSLayoutConstraint.activate([ tabBarContainerView.topAnchor.constraint(equalTo: topAnchor), tabBarContainerView.leadingAnchor.constraint(equalTo: leadingAnchor), tabBarContainerView.trailingAnchor.constraint(equalTo: trailingAnchor), - tabBarContainerView.heightAnchor.constraint(equalToConstant: 38), + tabBarHeightConstraint, divider.topAnchor.constraint(equalTo: navigationBarContainerView.bottomAnchor), divider.leadingAnchor.constraint(equalTo: leadingAnchor), @@ -82,7 +90,8 @@ final class MainView: NSView { navigationBarContainerView.leadingAnchor.constraint(equalTo: leadingAnchor), navigationBarContainerView.trailingAnchor.constraint(equalTo: trailingAnchor), - webContainerView.topAnchor.constraint(equalTo: bookmarksBarContainerView.bottomAnchor), + webContainerTopConstraint, + webContainerTopConstraintToNavigation, webContainerView.bottomAnchor.constraint(equalTo: bottomAnchor), webContainerView.leadingAnchor.constraint(equalTo: leadingAnchor), webContainerView.trailingAnchor.constraint(equalTo: trailingAnchor), diff --git a/DuckDuckGo/MainWindow/MainViewController.swift b/DuckDuckGo/MainWindow/MainViewController.swift index d0674088c2..fa7cca6089 100644 --- a/DuckDuckGo/MainWindow/MainViewController.swift +++ b/DuckDuckGo/MainWindow/MainViewController.swift @@ -27,7 +27,7 @@ import os.log import BrokenSitePrompt final class MainViewController: NSViewController { - private lazy var mainView = MainView(frame: NSRect(x: 0, y: 0, width: 600, height: 660)) + private(set) lazy var mainView = MainView(frame: NSRect(x: 0, y: 0, width: 600, height: 660)) let tabBarViewController: TabBarViewController let navigationBarViewController: NavigationBarViewController diff --git a/DuckDuckGo/MainWindow/MainWindowController.swift b/DuckDuckGo/MainWindow/MainWindowController.swift index a21f293ae6..3522729ae1 100644 --- a/DuckDuckGo/MainWindow/MainWindowController.swift +++ b/DuckDuckGo/MainWindow/MainWindowController.swift @@ -26,6 +26,7 @@ final class MainWindowController: NSWindowController { private var fireViewModel: FireViewModel private static var knownFullScreenMouseDetectionWindows = Set() let fireWindowSession: FireWindowSession? + private let appearancePreferences: AppearancePreferencesUserDefaultsPersistor var mainViewController: MainViewController { // swiftlint:disable force_cast @@ -51,6 +52,7 @@ final class MainWindowController: NSWindowController { assert(!mainViewController.isBurner || fireWindowSession != nil) self.fireWindowSession = fireWindowSession fireWindowSession?.addWindow(window) + appearancePreferences = AppearancePreferencesUserDefaultsPersistor() super.init(window: window) @@ -227,6 +229,42 @@ extension MainWindowController: NSWindowDelegate { func windowWillEnterFullScreen(_ notification: Notification) { mainViewController.tabBarViewController.draggingSpace.isHidden = true mainViewController.windowWillEnterFullScreen() + + if appearancePreferences.hideToolbarsOnFullScreen { + onEnterFullScreenWhenFullScreenModeIsEnabled() + } + } + + func windowWillExitFullScreen(_ notification: Notification) { + mainViewController.tabBarViewController.draggingSpace.isHidden = false + + if appearancePreferences.hideToolbarsOnFullScreen { + onExitFullScreenWhenFullScreenModeIsEnabled() + } + } + + private func onEnterFullScreenWhenFullScreenModeIsEnabled() { + guard let toolbar = window?.toolbar else { return } + toolbar.isVisible = false + + mainViewController.mainView.navigationBarTopConstraint.animator().constant = 0 + mainViewController.mainView.tabBarHeightConstraint.animator().constant = 0 + mainViewController.mainView.webContainerTopConstraintToNavigation.animator().priority = .defaultHigh + mainViewController.mainView.webContainerTopConstraint.animator().priority = .defaultLow + moveTabBarView(toTitlebarView: false) + } + + private func onExitFullScreenWhenFullScreenModeIsEnabled() { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { [weak self] in + guard let toolbar = self?.window?.toolbar else { return } + toolbar.isVisible = true + + self?.mainViewController.mainView.tabBarHeightConstraint.animator().constant = 38 + self?.mainViewController.mainView.navigationBarTopConstraint.animator().constant = 38 + self?.mainViewController.mainView.webContainerTopConstraintToNavigation.animator().priority = .defaultLow + self?.mainViewController.mainView.webContainerTopConstraint.animator().priority = .defaultHigh + self?.moveTabBarView(toTitlebarView: true) + } } func windowWillMiniaturize(_ notification: Notification) { @@ -276,10 +314,6 @@ extension MainWindowController: NSWindowDelegate { } } - func windowWillExitFullScreen(_ notification: Notification) { - mainViewController.tabBarViewController.draggingSpace.isHidden = false - } - func windowWillClose(_ notification: Notification) { mainViewController.windowWillClose() diff --git a/DuckDuckGo/Preferences/Model/AppearancePreferences.swift b/DuckDuckGo/Preferences/Model/AppearancePreferences.swift index 43fc227272..09338b6c8f 100644 --- a/DuckDuckGo/Preferences/Model/AppearancePreferences.swift +++ b/DuckDuckGo/Preferences/Model/AppearancePreferences.swift @@ -39,6 +39,7 @@ protocol AppearancePreferencesPersistor { var homeButtonPosition: HomeButtonPosition { get set } var homePageCustomBackground: String? { get set } var centerAlignedBookmarksBar: Bool { get set } + var hideToolbarsOnFullScreen: Bool { get set } } struct AppearancePreferencesUserDefaultsPersistor: AppearancePreferencesPersistor { @@ -101,6 +102,9 @@ struct AppearancePreferencesUserDefaultsPersistor: AppearancePreferencesPersisto @UserDefaultsWrapper(key: .centerAlignedBookmarksBar, defaultValue: true) var centerAlignedBookmarksBar: Bool + + @UserDefaultsWrapper(key: .hideToolbarsOnFullScreen, defaultValue: false) + var hideToolbarsOnFullScreen: Bool } protocol HomePageNavigator { @@ -208,6 +212,12 @@ final class AppearancePreferences: ObservableObject { } } + @Published var hideToolbarsOnFullScreen: Bool { + didSet { + persistor.hideToolbarsOnFullScreen = hideToolbarsOnFullScreen + } + } + @Published var favoritesDisplayMode: FavoritesDisplayMode { didSet { persistor.favoritesDisplayMode = favoritesDisplayMode.description @@ -355,6 +365,7 @@ final class AppearancePreferences: ObservableObject { homeButtonPosition = persistor.homeButtonPosition homePageCustomBackground = persistor.homePageCustomBackground.flatMap(CustomBackground.init) centerAlignedBookmarksBarBool = persistor.centerAlignedBookmarksBar + hideToolbarsOnFullScreen = persistor.hideToolbarsOnFullScreen } private var persistor: AppearancePreferencesPersistor diff --git a/DuckDuckGo/Preferences/View/PreferencesAppearanceView.swift b/DuckDuckGo/Preferences/View/PreferencesAppearanceView.swift index 606e3955ab..f43f45124c 100644 --- a/DuckDuckGo/Preferences/View/PreferencesAppearanceView.swift +++ b/DuckDuckGo/Preferences/View/PreferencesAppearanceView.swift @@ -99,6 +99,8 @@ extension Preferences { // SECTION 2: Address Bar PreferencePaneSection(UserText.addressBar) { ToggleMenuItem(UserText.showFullWebsiteAddress, isOn: $model.showFullURL) + + ToggleMenuItem(UserText.hideToolbarsOnFullScreen, isOn: $model.hideToolbarsOnFullScreen) } // SECTION 3: New Tab Page diff --git a/UnitTests/Preferences/AppearancePreferencesTests.swift b/UnitTests/Preferences/AppearancePreferencesTests.swift index 0189162ad6..c481a69756 100644 --- a/UnitTests/Preferences/AppearancePreferencesTests.swift +++ b/UnitTests/Preferences/AppearancePreferencesTests.swift @@ -38,6 +38,7 @@ struct AppearancePreferencesPersistorMock: AppearancePreferencesPersistor { var homePageCustomBackground: String? var centerAlignedBookmarksBar: Bool var didDismissHomePagePromotion: Bool + var hideToolbarsOnFullScreen: Bool init( showFullURL: Bool = false, @@ -55,7 +56,8 @@ struct AppearancePreferencesPersistorMock: AppearancePreferencesPersistor { homeButtonPosition: HomeButtonPosition = .right, homePageCustomBackground: String? = nil, centerAlignedBookmarksBar: Bool = true, - didDismissHomePagePromotion: Bool = true + didDismissHomePagePromotion: Bool = true, + hideToolbarsOnFullScreen: Bool = false ) { self.showFullURL = showFullURL self.currentThemeName = currentThemeName @@ -73,6 +75,7 @@ struct AppearancePreferencesPersistorMock: AppearancePreferencesPersistor { self.homePageCustomBackground = homePageCustomBackground self.centerAlignedBookmarksBar = centerAlignedBookmarksBar self.didDismissHomePagePromotion = didDismissHomePagePromotion + self.hideToolbarsOnFullScreen = hideToolbarsOnFullScreen } } @@ -103,6 +106,7 @@ final class AppearancePreferencesTests: XCTestCase { XCTAssertEqual(model.homeButtonPosition, .left) XCTAssertEqual(model.homePageCustomBackground, .gradient(.gradient01)) XCTAssertTrue(model.centerAlignedBookmarksBarBool) + XCTAssertFalse(model.hideToolbarsOnFullScreen) model = AppearancePreferences( persistor: AppearancePreferencesPersistorMock( @@ -115,7 +119,8 @@ final class AppearancePreferencesTests: XCTestCase { isSearchBarVisible: false, homeButtonPosition: .left, homePageCustomBackground: CustomBackground.gradient(.gradient05).description, - centerAlignedBookmarksBar: false + centerAlignedBookmarksBar: false, + hideToolbarsOnFullScreen: true ) ) XCTAssertEqual(model.showFullURL, true) @@ -128,6 +133,7 @@ final class AppearancePreferencesTests: XCTestCase { XCTAssertEqual(model.homeButtonPosition, .left) XCTAssertEqual(model.homePageCustomBackground, .gradient(.gradient05)) XCTAssertFalse(model.centerAlignedBookmarksBarBool) + XCTAssertTrue(model.hideToolbarsOnFullScreen) } func testWhenInitializedWithGarbageThenThemeIsSetToSystemDefault() throws { diff --git a/UnitTests/Sync/Mocks/MockAppearancePreferencesPersistor.swift b/UnitTests/Sync/Mocks/MockAppearancePreferencesPersistor.swift index fdca2ce7ec..a0f563b8c7 100644 --- a/UnitTests/Sync/Mocks/MockAppearancePreferencesPersistor.swift +++ b/UnitTests/Sync/Mocks/MockAppearancePreferencesPersistor.swift @@ -56,4 +56,6 @@ class MockAppearancePreferencesPersistor: AppearancePreferencesPersistor { var centerAlignedBookmarksBar: Bool = false var didDismissHomePagePromotion = true + + var hideToolbarsOnFullScreen: Bool = false }