diff --git a/Sources/Brave/Frontend/Browser/BrowserViewController.swift b/Sources/Brave/Frontend/Browser/BrowserViewController.swift index 02fc2712fa7..c5bcda2655d 100644 --- a/Sources/Brave/Frontend/Browser/BrowserViewController.swift +++ b/Sources/Brave/Frontend/Browser/BrowserViewController.swift @@ -461,7 +461,8 @@ public class BrowserViewController: UIViewController { self?.tabManager.allTabs.forEach({ guard let url = $0.webView?.url else { return } 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) + + $0.webView?.setValue(zoomLevel, forKey: PageZoomHandler.propertyName) }) } @@ -2285,9 +2286,10 @@ public class BrowserViewController: UIViewController { return } - guard let webView = tabManager.selectedTab?.webView else { return } - let pageZoomBar = UIHostingController(rootView: PageZoomView(webView: webView, isPrivateBrowsing: privateBrowsingManager.isPrivateBrowsing)) - + guard let selectTab = tabManager.selectedTab else { return } + let zoomHandler = PageZoomHandler(tab: selectTab, isPrivateBrowsing: privateBrowsingManager.isPrivateBrowsing) + let pageZoomBar = UIHostingController(rootView: PageZoomView(zoomHandler: zoomHandler)) + pageZoomBar.rootView.dismiss = { [weak self] in guard let self = self else { return } pageZoomBar.view.removeFromSuperview() @@ -2324,7 +2326,7 @@ public class BrowserViewController: UIViewController { let domain = Domain.getPersistedDomain(for: currentURL) let zoomLevel = privateBrowsingManager.isPrivateBrowsing ? 1.0 : domain?.zoom_level?.doubleValue ?? Preferences.General.defaultPageZoomLevel.value - tab.webView?.setValue(zoomLevel, forKey: PageZoomView.propertyName) + tab.webView?.setValue(zoomLevel, forKey: PageZoomHandler.propertyName) } } @@ -3127,7 +3129,7 @@ extension BrowserViewController: PreferencesObserver { tabManager.allTabs.forEach({ guard let url = $0.webView?.url else { return } let zoomLevel = $0.isPrivate ? 1.0 : Domain.getPersistedDomain(for: url)?.zoom_level?.doubleValue ?? Preferences.General.defaultPageZoomLevel.value - $0.webView?.setValue(zoomLevel, forKey: PageZoomView.propertyName) + $0.webView?.setValue(zoomLevel, forKey: PageZoomHandler.propertyName) }) case Preferences.Shields.httpsEverywhere.key: tabManager.reset() diff --git a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+KeyCommands.swift b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+KeyCommands.swift index b43ea8e81c1..d44bf33245c 100644 --- a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+KeyCommands.swift +++ b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+KeyCommands.swift @@ -192,6 +192,22 @@ extension BrowserViewController { RecentlyClosed.remove(with: recentlyClosed.url) } + @objc private func zoomInPageKeyCommand() { + changeZoomLevel(.increment) + } + + @objc private func zoomOutPageKeyCommand() { + changeZoomLevel(.decrement) + } + + private func changeZoomLevel(_ status: PageZoomHandler.ChangeStatus) { + guard let selectTab = tabManager.selectedTab else { return } + let zoomHandler = PageZoomHandler( + tab: selectTab, isPrivateBrowsing: privateBrowsingManager.isPrivateBrowsing) + + zoomHandler.changeZoomLevel(status) + } + // MARK: KeyCommands override public var keyCommands: [UIKeyCommand]? { @@ -216,6 +232,11 @@ extension BrowserViewController { UIKeyCommand(input: "]", modifierFlags: .command, action: #selector(goForwardKeyCommand)), ] + navigationCommands += [ + UIKeyCommand(title: Strings.Hotkey.zoomInTitle, action: #selector(zoomInPageKeyCommand), input: "+", modifierFlags: .command), + UIKeyCommand(title: Strings.Hotkey.zoomOutTitle, action: #selector(zoomOutPageKeyCommand), input: "-", modifierFlags: .command) + ] + // URL Bar - Tab Key Commands navigationCommands += [ UIKeyCommand(title: Strings.Hotkey.selectLocationBarTitle, action: #selector(selectLocationBarKeyCommand), input: "l", modifierFlags: .command), @@ -225,7 +246,8 @@ extension BrowserViewController { if !privateBrowsingManager.isPrivateBrowsing { navigationCommands += [ - UIKeyCommand(title: Strings.Hotkey.recentlyClosedTabTitle, action: #selector(reopenRecentlyClosedTabCommand), input: "t", modifierFlags: [.command, .shift]) + UIKeyCommand(title: Strings.Hotkey.recentlyClosedTabTitle, action: #selector(reopenRecentlyClosedTabCommand), input: "t", modifierFlags: [.command, .shift]), + UIKeyCommand(action: #selector(reopenRecentlyClosedTabCommand), input: "t", modifierFlags: [.control, .shift]) ] } @@ -299,7 +321,8 @@ extension BrowserViewController { // Additional Commands which will have priority over system let additionalPriorityCommandKeys = [ - UIKeyCommand(input: "\t", modifierFlags: .control, action: #selector(nextTabKeyCommand)) + UIKeyCommand(input: "\t", modifierFlags: .control, action: #selector(nextTabKeyCommand)), + UIKeyCommand(input: "\t", modifierFlags: [.control, .shift], action: #selector(previousTabKeyCommand)) ] var keyCommandList = navigationCommands + tabNavigationCommands + bookmarkEditingCommands + shareCommands + findTextCommands + additionalPriorityCommandKeys diff --git a/Sources/Brave/Frontend/Browser/PageZoom/PageZoomHandler.swift b/Sources/Brave/Frontend/Browser/PageZoom/PageZoomHandler.swift new file mode 100644 index 00000000000..f727685131a --- /dev/null +++ b/Sources/Brave/Frontend/Browser/PageZoom/PageZoomHandler.swift @@ -0,0 +1,84 @@ +// Copyright 2023 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import Shared +import Data +import Preferences + +class PageZoomHandler: ObservableObject { + + enum ChangeStatus { + case increment, decrement + } + + private weak var webView: BraveWebView? + let isPrivateBrowsing: Bool + + static let steps = [0.5, 0.75, 0.85, + 1.0, 1.15, 1.25, + 1.50, 1.75, 2.00, + 2.50, 3.0] + static let propertyName = "viewScale" + @Published var currentValue: Double = 1.0 + + required init(tab: Tab?, isPrivateBrowsing: Bool) { + self.webView = tab?.webView + self.isPrivateBrowsing = isPrivateBrowsing + + // Private Browsing on Safari iOS always defaults to 100%, and isn't persistently saved. + if isPrivateBrowsing { + currentValue = 1.0 + return + } + + if let webView = webView { + // Fetch the current value for zoom + if let url = webView.url, let domain = Domain.getPersistedDomain(for: url) { + currentValue = domain.zoom_level?.doubleValue ?? Preferences.General.defaultPageZoomLevel.value + } else { + currentValue = webView.value(forKey: Self.propertyName) as? Double ?? Preferences.General.defaultPageZoomLevel.value + } + } + } + + func changeZoomLevel(_ status: ChangeStatus) { + switch status { + case .increment: + guard let index = Self.steps.firstIndex(of: currentValue), + index + 1 < Self.steps.count else { return } + + currentValue = Self.steps[index + 1] + case .decrement: + guard let index = Self.steps.firstIndex(of: currentValue), + index - 1 >= 0 else { return } + currentValue = Self.steps[index - 1] + } + + // Setting the value + storeChanges() + } + + func reset() { + currentValue = Preferences.General.defaultPageZoomLevel.value + storeChanges() + } + + private func storeChanges() { + guard let webView = webView, + let url = webView.url else { return } + + webView.setValue(currentValue, forKey: PageZoomHandler.propertyName) + + // Do NOT store the changes in the Domain + if !isPrivateBrowsing { + let domain = Domain.getPersistedDomain(for: url)?.then { + $0.zoom_level = currentValue == $0.zoom_level?.doubleValue ? nil : NSNumber(value: currentValue) + } + + try? domain?.managedObjectContext?.save() + } + } +} diff --git a/Sources/Brave/Frontend/Browser/PageZoom/PageZoomSettingsView.swift b/Sources/Brave/Frontend/Browser/PageZoom/PageZoomSettingsView.swift index 5d3bb3e5e1f..f8933466682 100644 --- a/Sources/Brave/Frontend/Browser/PageZoom/PageZoomSettingsView.swift +++ b/Sources/Brave/Frontend/Browser/PageZoom/PageZoomSettingsView.swift @@ -64,7 +64,7 @@ struct PageZoomSettingsView: View { .font(.subheadline) .foregroundColor(Color(.secondaryBraveLabel)) ) { - ForEach(PageZoomView.steps, id: \.self) { step in + ForEach(PageZoomHandler.steps, id: \.self) { step in Button(action: { resetDefaultZoomLevel(zoomLevel: step) }, label: { diff --git a/Sources/Brave/Frontend/Browser/PageZoom/PageZoomView.swift b/Sources/Brave/Frontend/Browser/PageZoom/PageZoomView.swift index 4b02a9cea09..cac212e6e1f 100644 --- a/Sources/Brave/Frontend/Browser/PageZoom/PageZoomView.swift +++ b/Sources/Brave/Frontend/Browser/PageZoom/PageZoomView.swift @@ -75,11 +75,10 @@ private struct ZoomView: View { struct PageZoomView: View { @Environment(\.managedObjectContext) private var context - private var webView: WKWebView? + @ObservedObject private var zoomHandler: PageZoomHandler private let isPrivateBrowsing: Bool @State private var minValue = 0.5 @State private var maxValue = 3.0 - @State private var currentValue: Double public static let percentFormatter = NumberFormatter().then { $0.numberStyle = .percent @@ -89,35 +88,14 @@ struct PageZoomView: View { $0.minimumFractionDigits = 0 } - public static let propertyName = "viewScale" public static let notificationName = Notification.Name(rawValue: "com.brave.pagezoom-change") - public static let steps = [0.5, 0.75, 0.85, - 1.0, 1.15, 1.25, - 1.50, 1.75, 2.00, - 2.50, 3.0] - var dismiss: (() -> Void)? - 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 isPrivateBrowsing { - _currentValue = State(initialValue: 1.0) - return - } + init(zoomHandler: PageZoomHandler) { + self.zoomHandler = zoomHandler + self.isPrivateBrowsing = zoomHandler.isPrivateBrowsing - // We never re-init, so - // it is okay to initialize state here. - if let url = webView?.url, - let domain = Domain.getPersistedDomain(for: url) { - - _currentValue = State(initialValue: domain.zoom_level?.doubleValue ?? Preferences.General.defaultPageZoomLevel.value) - } else { - _currentValue = State(initialValue: webView?.value(forKey: PageZoomView.propertyName) as? Double ?? Preferences.General.defaultPageZoomLevel.value) - } } var body: some View { @@ -127,17 +105,15 @@ struct PageZoomView: View { Text(Strings.PageZoom.zoomViewText) .font(.system(.subheadline)) .frame(maxWidth: .infinity, alignment: .leading) - ZoomView( isPrivateBrowsing: isPrivateBrowsing, minValue: minValue, maxValue: maxValue, - value: $currentValue, + value: $zoomHandler.currentValue, onDecrement: decrement, onReset: reset, onIncrement: increment) - .frame(maxWidth: .infinity) - + .frame(maxWidth: .infinity) Button { dismiss?() } label: { @@ -153,46 +129,23 @@ struct PageZoomView: View { .background(Color(UIColor.braveBackground)) } - private func storeChanges() { - guard let webView = webView, - let url = webView.url else { return } - - webView.setValue(currentValue, forKey: PageZoomView.propertyName) - - // Do NOT store the changes in the Domain - if !isPrivateBrowsing { - let domain = Domain.getPersistedDomain(for: url)?.then { - $0.zoom_level = currentValue == $0.zoom_level?.doubleValue ? nil : NSNumber(value: currentValue) - } - - try? domain?.managedObjectContext?.save() - } - } - private func increment() { - guard let index = PageZoomView.steps.firstIndex(of: currentValue), - index + 1 < PageZoomView.steps.count else { return } - currentValue = PageZoomView.steps[index + 1] - storeChanges() + zoomHandler.changeZoomLevel(.increment) } - + private func reset() { - currentValue = Preferences.General.defaultPageZoomLevel.value - storeChanges() + zoomHandler.reset() } - + private func decrement() { - guard let index = PageZoomView.steps.firstIndex(of: currentValue), - index - 1 >= 0 else { return } - currentValue = PageZoomView.steps[index - 1] - storeChanges() + zoomHandler.changeZoomLevel(.decrement) } } #if DEBUG struct PageZoomView_Previews: PreviewProvider { static var previews: some View { - PageZoomView(webView: nil, isPrivateBrowsing: false) + PageZoomView(zoomHandler: PageZoomHandler(tab: nil, isPrivateBrowsing: false)) .previewLayout(PreviewLayout.sizeThatFits) } } diff --git a/Sources/BraveStrings/BraveStrings.swift b/Sources/BraveStrings/BraveStrings.swift index c5c5b9b1f27..e4ec857bfc4 100644 --- a/Sources/BraveStrings/BraveStrings.swift +++ b/Sources/BraveStrings/BraveStrings.swift @@ -4928,6 +4928,8 @@ extension Strings { public static let reloadPageTitle = NSLocalizedString("ReloadPageTitle", bundle: .module, value: "Reload Page", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") public static let backTitle = NSLocalizedString("BackTitle", bundle: .module, value: "Back", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") public static let forwardTitle = NSLocalizedString("ForwardTitle", bundle: .module, value: "Forward", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") + public static let zoomInTitle = NSLocalizedString("ZoomInTitle", bundle: .module, value: "Zoom In", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") + public static let zoomOutTitle = NSLocalizedString("ZoomOutTitle", bundle: .module, value: "Zoom Out", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") public static let selectLocationBarTitle = NSLocalizedString("SelectLocationBarTitle", bundle: .module, value: "Select Location Bar", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") public static let newTabTitle = NSLocalizedString("NewTabTitle", bundle: .module, value: "New Tab", comment: "Label to display in the Discoverability overlay for keyboard shortcuts") public static let newPrivateTabTitle = NSLocalizedString("NewPrivateTabTitle", bundle: .module, value: "New Private Tab", comment: "Label to display in the Discoverability overlay for keyboard shortcuts")