diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2023-01-20 08:59:41 +0100 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2023-01-20 08:59:41 +0100 |
| commit | 08154bbb8463d74e145ce7831027eb5c9717cb78 (patch) | |
| tree | 30f68eddd8c4975661217b2a73920024c290a402 | |
| parent | 013a636d57813594cf89f9a2ab045f5f3edebade (diff) | |
| parent | d7bd37a8ff6b0f816833ee2e3512efca6cc7093d (diff) | |
| download | mullvadvpn-08154bbb8463d74e145ce7831027eb5c9717cb78.tar.xz mullvadvpn-08154bbb8463d74e145ce7831027eb5c9717cb78.zip | |
Merge branch 'drop-custom-nav'
| -rw-r--r-- | ios/MullvadVPN.xcodeproj/project.pbxproj | 4 | ||||
| -rw-r--r-- | ios/MullvadVPN/CustomNavigationController.swift | 122 | ||||
| -rw-r--r-- | ios/MullvadVPN/ProblemReportViewController.swift | 37 | ||||
| -rw-r--r-- | ios/MullvadVPN/SettingsNavigationController.swift | 45 |
4 files changed, 54 insertions, 154 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index d999398e2b..1994428b55 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -86,7 +86,6 @@ 58293FAE2510CA58005D0BB5 /* ProblemReportViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58293FAC2510CA58005D0BB5 /* ProblemReportViewController.swift */; }; 58293FB125124117005D0BB5 /* CustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58293FB025124117005D0BB5 /* CustomTextField.swift */; }; 58293FB3251241B4005D0BB5 /* CustomTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58293FB2251241B3005D0BB5 /* CustomTextView.swift */; }; - 58293FB725138B88005D0BB5 /* CustomNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58293FB625138B88005D0BB5 /* CustomNavigationController.swift */; }; 582A8A3A28BCE19B00D0F9FB /* FixedWidthIntegerArithmeticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 582A8A3928BCE19B00D0F9FB /* FixedWidthIntegerArithmeticsTests.swift */; }; 582AE3102440A6CA00E6733A /* AccountTokenInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 582AE30F2440A6CA00E6733A /* AccountTokenInput.swift */; }; 582AE3122440CA0D00E6733A /* AccountTokenInputTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 582AE3112440CA0D00E6733A /* AccountTokenInputTests.swift */; }; @@ -680,7 +679,6 @@ 58293FAC2510CA58005D0BB5 /* ProblemReportViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProblemReportViewController.swift; sourceTree = "<group>"; }; 58293FB025124117005D0BB5 /* CustomTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextField.swift; sourceTree = "<group>"; }; 58293FB2251241B3005D0BB5 /* CustomTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextView.swift; sourceTree = "<group>"; }; - 58293FB625138B88005D0BB5 /* CustomNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomNavigationController.swift; sourceTree = "<group>"; }; 582A8A3928BCE19B00D0F9FB /* FixedWidthIntegerArithmeticsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FixedWidthIntegerArithmeticsTests.swift; sourceTree = "<group>"; }; 582AE30F2440A6CA00E6733A /* AccountTokenInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountTokenInput.swift; sourceTree = "<group>"; }; 582AE3112440CA0D00E6733A /* AccountTokenInputTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountTokenInputTests.swift; sourceTree = "<group>"; }; @@ -1400,7 +1398,6 @@ 5871FB95254ADE4E0051A0A4 /* ConsolidatedApplicationLog.swift */, 5896AE83246D5889005B36CB /* CustomDateComponentsFormatting.swift */, 582BB1B0229569620055B6EF /* CustomNavigationBar.swift */, - 58293FB625138B88005D0BB5 /* CustomNavigationController.swift */, 5868BD32261DCD2600E6027F /* CustomSplitViewController.swift */, 58ACF64C26567A4F00ACE4B7 /* CustomSwitch.swift */, 58ACF64E26567A7100ACE4B7 /* CustomSwitchContainer.swift */, @@ -2424,7 +2421,6 @@ 584EBDBD2747C98F00A0C9FD /* NSAttributedString+Markdown.swift in Sources */, 5875960A26F371FC00BF6711 /* Tunnel+Messaging.swift in Sources */, 063687BA28EB234F00BE7161 /* PacketTunnelTransport.swift in Sources */, - 58293FB725138B88005D0BB5 /* CustomNavigationController.swift in Sources */, 587425C12299833500CA2045 /* RootContainerViewController.swift in Sources */, 5896AE84246D5889005B36CB /* CustomDateComponentsFormatting.swift in Sources */, 5871167F2910035700D41AAC /* PreferencesInteractor.swift in Sources */, diff --git a/ios/MullvadVPN/CustomNavigationController.swift b/ios/MullvadVPN/CustomNavigationController.swift deleted file mode 100644 index 098ba7042f..0000000000 --- a/ios/MullvadVPN/CustomNavigationController.swift +++ /dev/null @@ -1,122 +0,0 @@ -// -// CustomNavigationController.swift -// MullvadVPN -// -// Created by pronebird on 17/09/2020. -// Copyright © 2020 Mullvad VPN AB. All rights reserved. -// - -import Foundation -import UIKit - -enum NavigationPopTrigger { - case backButton - case interactiveGesture -} - -protocol ConditionalNavigation: AnyObject { - func shouldPopNavigationItem(_ navigationItem: UINavigationItem, trigger: NavigationPopTrigger) - -> Bool -} - -class CustomNavigationController: UINavigationController, UINavigationBarDelegate { - private static let classInit: Void = { - swizzleMethod( - aClass: CustomNavigationController.self, - originalSelector: #selector(UINavigationBarDelegate.navigationBar(_:shouldPop:)), - newSelector: #selector(customNavigationController_navigationBar(_:shouldPop:)) - ) - }() - - private var popGestureRecognizerDelegate: CustomPopGestureRecognizerDelegate? - - override func viewDidLoad() { - super.viewDidLoad() - - _ = Self.classInit - - popGestureRecognizerDelegate = CustomPopGestureRecognizerDelegate( - navigationController: self, - systemGestureRecognizerDelegate: interactivePopGestureRecognizer?.delegate - ) - - // Replace the system interactive gesture recognizer - interactivePopGestureRecognizer?.delegate = popGestureRecognizerDelegate - } - - @objc dynamic func customNavigationController_navigationBar( - _ navigationBar: UINavigationBar, - shouldPop item: UINavigationItem - ) -> Bool { - var shouldPop = true - - if let conformingViewController = topViewController as? ConditionalNavigation { - shouldPop = conformingViewController.shouldPopNavigationItem(item, trigger: .backButton) - } - - // Only call super implementation when we want to pop the controller - if shouldPop { - willPop(navigationItem: item) - - // Call super implementation - return customNavigationController_navigationBar(navigationBar, shouldPop: item) - } else { - return shouldPop - } - } - - func willPop(navigationItem: UINavigationItem) { - // Override in subclasses - } -} - -private class CustomPopGestureRecognizerDelegate: NSObject, UIGestureRecognizerDelegate { - private let systemGestureRecognizerDelegate: UIGestureRecognizerDelegate? - private weak var navigationController: UINavigationController? - - init( - navigationController: UINavigationController, - systemGestureRecognizerDelegate: UIGestureRecognizerDelegate? - ) { - self.navigationController = navigationController - self.systemGestureRecognizerDelegate = systemGestureRecognizerDelegate - } - - override func responds(to aSelector: Selector!) -> Bool { - if Self.instancesRespond(to: aSelector) { - return true - } else { - return systemGestureRecognizerDelegate?.responds(to: aSelector) ?? false - } - } - - override func forwardingTarget(for aSelector: Selector!) -> Any? { - let shouldForward = systemGestureRecognizerDelegate?.responds(to: aSelector) ?? false - - if shouldForward { - return systemGestureRecognizerDelegate - } else { - return nil - } - } - - // MARK: - UIGestureRecognizerDelegate - - func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { - let shouldBegin = systemGestureRecognizerDelegate? - .gestureRecognizerShouldBegin?(gestureRecognizer) ?? true - - guard let navigationController = navigationController, - let topItem = navigationController.navigationBar.topItem, - let conformingViewController = navigationController - .topViewController as? ConditionalNavigation - else { - return shouldBegin - } - - return shouldBegin && conformingViewController.shouldPopNavigationItem( - topItem, - trigger: .interactiveGesture - ) - } -} diff --git a/ios/MullvadVPN/ProblemReportViewController.swift b/ios/MullvadVPN/ProblemReportViewController.swift index 622cc1600c..c894664679 100644 --- a/ios/MullvadVPN/ProblemReportViewController.swift +++ b/ios/MullvadVPN/ProblemReportViewController.swift @@ -11,7 +11,7 @@ import MullvadTypes import Operations import UIKit -class ProblemReportViewController: UIViewController, UITextFieldDelegate, ConditionalNavigation { +final class ProblemReportViewController: UIViewController, UITextFieldDelegate { private let interactor: ProblemReportInteractor private var textViewKeyboardResponder: AutomaticKeyboardResponder? @@ -629,6 +629,10 @@ class ProblemReportViewController: UIViewController, UITextFieldDelegate, Condit validateForm() } + private func setPopGestureEnabled(_ isEnabled: Bool) { + navigationController?.interactivePopGestureRecognizer?.isEnabled = isEnabled + } + private func clearPersistentViewModel() { Self.persistentViewModel = ViewModel() } @@ -684,14 +688,16 @@ class ProblemReportViewController: UIViewController, UITextFieldDelegate, Condit } } - // MARK: - Input fields' notifications + // MARK: - Input fields notifications @objc private func messageTextViewDidBeginEditing() { setDescriptionFieldExpanded(true) + setPopGestureEnabled(false) } @objc private func messageTextViewDidEndEditing() { setDescriptionFieldExpanded(false) + setPopGestureEnabled(true) } @objc private func messageTextViewDidChange() { @@ -704,27 +710,16 @@ class ProblemReportViewController: UIViewController, UITextFieldDelegate, Condit // MARK: - UITextFieldDelegate - func textFieldShouldReturn(_ textField: UITextField) -> Bool { - messageTextView.becomeFirstResponder() - return false + func textFieldDidBeginEditing(_ textField: UITextField) { + setPopGestureEnabled(false) } - // MARK: - ConditionalNavigation - - func shouldPopNavigationItem( - _ navigationItem: UINavigationItem, - trigger: NavigationPopTrigger - ) -> Bool { - switch trigger { - case .interactiveGesture: - // Disable swipe when editing - return !emailTextField.isFirstResponder && !messageTextView.isFirstResponder + func textFieldDidEndEditing(_ textField: UITextField) { + setPopGestureEnabled(true) + } - case .backButton: - // Dismiss the keyboard to fix a visual glitch when moving back to the previous - // controller - view.endEditing(true) - return true - } + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + messageTextView.becomeFirstResponder() + return false } } diff --git a/ios/MullvadVPN/SettingsNavigationController.swift b/ios/MullvadVPN/SettingsNavigationController.swift index c43da954cc..a8812419e5 100644 --- a/ios/MullvadVPN/SettingsNavigationController.swift +++ b/ios/MullvadVPN/SettingsNavigationController.swift @@ -32,10 +32,12 @@ protocol SettingsNavigationControllerDelegate: AnyObject { ) } -class SettingsNavigationController: CustomNavigationController, SettingsViewControllerDelegate, - AccountViewControllerDelegate, UIAdaptivePresentationControllerDelegate +class SettingsNavigationController: UINavigationController, SettingsViewControllerDelegate, + AccountViewControllerDelegate, UIAdaptivePresentationControllerDelegate, + UINavigationControllerDelegate { private let interactorFactory: SettingsInteractorFactory + private var currentRoutes: [SettingsNavigationRoute] = [.root] weak var settingsDelegate: SettingsNavigationControllerDelegate? @@ -56,17 +58,26 @@ class SettingsNavigationController: CustomNavigationController, SettingsViewCont // Navigation controller ignores `prefersLargeTitles` when using `setViewControllers()`. pushViewController(makeViewController(for: .root), animated: false) + + delegate = self } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } - override func willPop(navigationItem: UINavigationItem) { - let index = viewControllers.firstIndex { $0.navigationItem == navigationItem } + // MARK: - UINavigationControllerDelegate + + func navigationController( + _ navigationController: UINavigationController, + willShow viewController: UIViewController, + animated: Bool + ) { + let newRoutes = viewControllers.compactMap { route(for: $0) } - if viewControllers.count > 1, index == 1 { - settingsDelegate?.settingsNavigationController(self, willNavigateTo: .root) + if currentRoutes != newRoutes, let nextRoute = newRoutes.last { + currentRoutes = newRoutes + settingsDelegate?.settingsNavigationController(self, willNavigateTo: nextRoute) } } @@ -95,8 +106,13 @@ class SettingsNavigationController: CustomNavigationController, SettingsViewCont let nextViewController = makeViewController(for: route) if let rootController = viewControllers.first, viewControllers.count > 1 { - setViewControllers([rootController, nextViewController], animated: animated) + let newChildren = [rootController, nextViewController] + let newRoutes = newChildren.compactMap { self.route(for: $0) } + + currentRoutes = newRoutes + setViewControllers(newChildren, animated: animated) } else { + currentRoutes.append(route) pushViewController(nextViewController, animated: animated) } } @@ -129,6 +145,21 @@ class SettingsNavigationController: CustomNavigationController, SettingsViewCont } } + private func route(for viewController: UIViewController) -> SettingsNavigationRoute? { + switch viewController { + case is SettingsViewController: + return .root + case is AccountViewController: + return .account + case is PreferencesViewController: + return .preferences + case is ProblemReportViewController: + return .problemReport + default: + return nil + } + } + // MARK: - UIAdaptivePresentationControllerDelegate func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { |
