From f04e278d61a16e64844dbdc0302011f61fbb5aba Mon Sep 17 00:00:00 2001 From: Soner YUKSEL Date: Wed, 29 Nov 2023 16:53:01 -0500 Subject: [PATCH] Fix #8484: Portrait Orientation Locking on Phone is not working (#8485) --- .../Browser/BrowserViewController.swift | 16 ++--- ...rowserViewController+ToolbarDelegate.swift | 13 ++++ .../Tabs/TabTray/TabTrayController.swift | 18 +++--- .../Menu/MenuViewController.swift | 12 ++++ .../SettingsNavigationController.swift | 12 ++-- .../Settings/SettingsViewController.swift | 2 +- .../Frontend/Sync/SyncViewController.swift | 18 ++++++ .../WalletHostingViewController.swift | 7 ++- .../WalletPanelHostingController.swift | 1 + Sources/Shared/DeviceOrientation.swift | 62 +++++++++++++++++++ .../Extensions/UIDeviceExtensions.swift | 9 --- 11 files changed, 138 insertions(+), 32 deletions(-) create mode 100644 Sources/Shared/DeviceOrientation.swift diff --git a/Sources/Brave/Frontend/Browser/BrowserViewController.swift b/Sources/Brave/Frontend/Browser/BrowserViewController.swift index d14d6188c3a..e922adac645 100644 --- a/Sources/Brave/Frontend/Browser/BrowserViewController.swift +++ b/Sources/Brave/Frontend/Browser/BrowserViewController.swift @@ -1497,15 +1497,15 @@ public class BrowserViewController: UIViewController { } guard let vc = BraveVPN.vpnState.enableVPNDestinationVC else { return } - let nav = SettingsNavigationController(rootViewController: vc) - nav.navigationBar.topItem?.leftBarButtonItem = - .init(barButtonSystemItem: .cancel, target: nav, action: #selector(nav.done)) + let navigationController = SettingsNavigationController(rootViewController: vc) + navigationController.navigationBar.topItem?.leftBarButtonItem = + .init(barButtonSystemItem: .cancel, target: navigationController, action: #selector(navigationController.done)) let idiom = UIDevice.current.userInterfaceIdiom - UIDevice.current.forcePortraitIfIphone(for: UIApplication.shared) - - nav.modalPresentationStyle = idiom == .phone ? .pageSheet : .formSheet - present(nav, animated: true) + DeviceOrientation.shared.changeOrientationToPortraitOnPhone() + + navigationController.modalPresentationStyle = idiom == .phone ? .pageSheet : .formSheet + present(navigationController, animated: true) } func updateInContentHomePanel(_ url: URL?) { @@ -2085,7 +2085,7 @@ public class BrowserViewController: UIViewController { UIBarButtonItem(barButtonSystemItem: .done, target: settingsNavigationController, action: #selector(settingsNavigationController.done)) // All menu views should be opened in portrait on iPhones. - UIDevice.current.forcePortraitIfIphone(for: UIApplication.shared) + DeviceOrientation.shared.changeOrientationToPortraitOnPhone() present(settingsNavigationController, animated: true) } diff --git a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+ToolbarDelegate.swift b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+ToolbarDelegate.swift index 981683d519e..2f8563896b1 100644 --- a/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+ToolbarDelegate.swift +++ b/Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController+ToolbarDelegate.swift @@ -50,6 +50,7 @@ extension BrowserViewController: TopToolbarDelegate { $0.toolbarUrlActionsDelegate = self } let container = UINavigationController(rootViewController: tabTrayController) + container.delegate = self if !UIAccessibility.isReduceMotionEnabled { if !isExternallyPresented { @@ -1009,3 +1010,15 @@ extension BrowserViewController: UIContextMenuInteractionDelegate { return UIMenu(options: .displayInline, children: children) } } + +// MARK: UINavigationControllerDelegate + +extension BrowserViewController: UINavigationControllerDelegate { + public func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask { + return navigationController.visibleViewController?.supportedInterfaceOrientations ?? navigationController.supportedInterfaceOrientations + } + + public func navigationControllerPreferredInterfaceOrientationForPresentation(_ navigationController: UINavigationController) -> UIInterfaceOrientation { + return navigationController.visibleViewController?.preferredInterfaceOrientationForPresentation ?? navigationController.preferredInterfaceOrientationForPresentation + } +} diff --git a/Sources/Brave/Frontend/Browser/Tabs/TabTray/TabTrayController.swift b/Sources/Brave/Frontend/Browser/Tabs/TabTray/TabTrayController.swift index e2be7b2c558..a8618b707d3 100644 --- a/Sources/Brave/Frontend/Browser/Tabs/TabTray/TabTrayController.swift +++ b/Sources/Brave/Frontend/Browser/Tabs/TabTray/TabTrayController.swift @@ -746,14 +746,14 @@ class TabTrayController: AuthenticationController { return } - let syncSettingsScreen = SyncSettingsTableViewController( - isModallyPresented: true, - syncAPI: braveCore.syncAPI, - syncProfileService: braveCore.syncProfileService, - tabManager: tabManager, - windowProtection: windowProtection) - - syncSettingsScreen.syncStatusDelegate = self + let syncSettingsScreen = SyncSettingsTableViewController( + isModallyPresented: true, + syncAPI: braveCore.syncAPI, + syncProfileService: braveCore.syncProfileService, + tabManager: tabManager, + windowProtection: windowProtection) + + syncSettingsScreen.syncStatusDelegate = self openInsideSettingsNavigation(with: syncSettingsScreen) default: @@ -772,7 +772,7 @@ class TabTrayController: AuthenticationController { settingsNavigationController.navigationBar.topItem?.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: settingsNavigationController, action: #selector(settingsNavigationController.done)) - UIDevice.current.forcePortraitIfIphone(for: UIApplication.shared) + DeviceOrientation.shared.changeOrientationToPortraitOnPhone() present(settingsNavigationController, animated: true) } diff --git a/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/MenuViewController.swift b/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/MenuViewController.swift index f3661b50b0d..e88eb7e41ac 100644 --- a/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/MenuViewController.swift +++ b/Sources/Brave/Frontend/Browser/Toolbars/BottomToolbar/Menu/MenuViewController.swift @@ -214,6 +214,8 @@ class MenuViewController: UINavigationController, UIPopoverPresentationControlle } } +// MARK: PanModalPresentable + extension MenuViewController: PanModalPresentable { var panScrollable: UIScrollView? { // For SwiftUI: @@ -337,6 +339,8 @@ private class MenuHostingController: UIHostingController UIInterfaceOrientationMask { + return navigationController.visibleViewController?.supportedInterfaceOrientations ?? navigationController.supportedInterfaceOrientations + } + + public func navigationControllerPreferredInterfaceOrientationForPresentation(_ navigationController: UINavigationController) -> UIInterfaceOrientation { + return navigationController.visibleViewController?.preferredInterfaceOrientationForPresentation ?? navigationController.preferredInterfaceOrientationForPresentation + } } private class InnerMenuNavigationController: UINavigationController { diff --git a/Sources/Brave/Frontend/Settings/SettingsNavigationController.swift b/Sources/Brave/Frontend/Settings/SettingsNavigationController.swift index eee8c804516..645548fcea4 100644 --- a/Sources/Brave/Frontend/Settings/SettingsNavigationController.swift +++ b/Sources/Brave/Frontend/Settings/SettingsNavigationController.swift @@ -7,6 +7,14 @@ import UIKit class SettingsNavigationController: UINavigationController { var popoverDelegate: PresentingModalViewControllerDelegate? + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + if #available(iOS 16.0, *) { + self.setNeedsUpdateOfSupportedInterfaceOrientations() + } + } + @objc func done() { if let delegate = popoverDelegate { delegate.dismissPresentedModalViewController(self, animated: true) @@ -29,10 +37,6 @@ class SettingsNavigationController: UINavigationController { override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return .portrait } - - override var shouldAutorotate: Bool { - return false - } } protocol PresentingModalViewControllerDelegate { diff --git a/Sources/Brave/Frontend/Settings/SettingsViewController.swift b/Sources/Brave/Frontend/Settings/SettingsViewController.swift index c758b72a84e..40eafcbcf83 100644 --- a/Sources/Brave/Frontend/Settings/SettingsViewController.swift +++ b/Sources/Brave/Frontend/Settings/SettingsViewController.swift @@ -355,7 +355,7 @@ class SettingsViewController: TableViewController { syncProfileService: syncProfileServices, tabManager: tabManager, - windowProtection: windowProtection) + windowProtection: windowProtection) self.navigationController? .pushViewController(syncSettingsViewController, animated: true) diff --git a/Sources/Brave/Frontend/Sync/SyncViewController.swift b/Sources/Brave/Frontend/Sync/SyncViewController.swift index f2cac3fd5e1..4a21dad648d 100644 --- a/Sources/Brave/Frontend/Sync/SyncViewController.swift +++ b/Sources/Brave/Frontend/Sync/SyncViewController.swift @@ -83,3 +83,21 @@ class SyncViewController: AuthenticationController { } } } + +// MARK: - InterfaceOrientation + +extension SyncViewController { + + override var supportedInterfaceOrientations: UIInterfaceOrientationMask { + return .portrait + } + + override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { + return .portrait + } + + override var shouldAutorotate: Bool { + return false + } +} + diff --git a/Sources/BraveWallet/WalletHostingViewController.swift b/Sources/BraveWallet/WalletHostingViewController.swift index 14e202d37e5..0fe5347617a 100644 --- a/Sources/BraveWallet/WalletHostingViewController.swift +++ b/Sources/BraveWallet/WalletHostingViewController.swift @@ -8,6 +8,7 @@ import SwiftUI import BraveCore import Combine import BraveUI +import Shared /// Methods for handling actions that occur while the user is interacting with Brave Wallet that require /// some integration with the browser @@ -120,7 +121,11 @@ public class WalletHostingViewController: UIHostingController { public override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) view.window?.addGestureRecognizer(gesture) - UIDevice.current.forcePortraitIfIphone(for: UIApplication.shared) + + DeviceOrientation.shared.changeOrientationToPortraitOnPhone() + if #available(iOS 16.0, *) { + self.setNeedsUpdateOfSupportedInterfaceOrientations() + } } public override func viewDidLoad() { diff --git a/Sources/BraveWallet/WalletPanelHostingController.swift b/Sources/BraveWallet/WalletPanelHostingController.swift index 314dd56cdaf..5610672d1e0 100644 --- a/Sources/BraveWallet/WalletPanelHostingController.swift +++ b/Sources/BraveWallet/WalletPanelHostingController.swift @@ -9,6 +9,7 @@ import BraveCore import SwiftUI import Combine import BraveUI +import Shared /// Displays a summary of the users wallet when they are visiting a webpage that wants to connect with the /// users wallet diff --git a/Sources/Shared/DeviceOrientation.swift b/Sources/Shared/DeviceOrientation.swift new file mode 100644 index 00000000000..bb863692667 --- /dev/null +++ b/Sources/Shared/DeviceOrientation.swift @@ -0,0 +1,62 @@ +// 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 UIKit + +public final class DeviceOrientation { + + private var windowScene: UIWindowScene? { + return UIApplication.shared.connectedScenes.first as? UIWindowScene + } + + public static let shared: DeviceOrientation = DeviceOrientation() + + public func changeOrientation(_ orientationMask: UIInterfaceOrientationMask) { + if #available(iOS 16.0, *) { + windowScene?.requestGeometryUpdate(.iOS(interfaceOrientations: orientationMask)) + } else { + var orientation: UIInterfaceOrientation? + + switch orientationMask { + case .portrait: + orientation = UIInterfaceOrientation.portrait + case .portraitUpsideDown: + orientation = UIInterfaceOrientation.portraitUpsideDown + case .landscapeRight: + orientation = UIInterfaceOrientation.landscapeRight + case .landscapeLeft: + orientation = UIInterfaceOrientation.landscapeLeft + default: + orientation = UIInterfaceOrientation.unknown + } + + if let orientation = orientation { + UIDevice.current.setValue(orientation.rawValue, forKey: "orientation") + } + } + } + + private var isLandscape: Bool { + if #available(iOS 16.0, *) { + return windowScene?.interfaceOrientation.isLandscape ?? false + } + + return UIDevice.current.orientation.isLandscape + } + + private var isPortrait: Bool { + if #available(iOS 16.0, *) { + return windowScene?.interfaceOrientation.isPortrait ?? false + } + return UIDevice.current.orientation.isPortrait + } + + public func changeOrientationToPortraitOnPhone() { + if UIDevice.current.userInterfaceIdiom != .pad && isLandscape { + changeOrientation(.portrait) + } + } +} + diff --git a/Sources/Shared/Extensions/UIDeviceExtensions.swift b/Sources/Shared/Extensions/UIDeviceExtensions.swift index b60b8edd7a6..4be5557d678 100644 --- a/Sources/Shared/Extensions/UIDeviceExtensions.swift +++ b/Sources/Shared/Extensions/UIDeviceExtensions.swift @@ -62,13 +62,4 @@ public extension UIDevice { static var isPhone: Bool { return UIDevice.current.userInterfaceIdiom == .phone } - - // Dev note: UIApplication.shared cannot be used in application extensions. - func forcePortraitIfIphone(for application: UIApplication) { - if userInterfaceIdiom != .pad && application.statusBarOrientation.isLandscape { - let value = UIInterfaceOrientation.portrait.rawValue - UIDevice.current.setValue(value, forKey: "orientation") - } - } - }