diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2023-01-19 08:36:32 +0100 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2023-01-20 08:59:06 +0100 |
| commit | d7bd37a8ff6b0f816833ee2e3512efca6cc7093d (patch) | |
| tree | 30f68eddd8c4975661217b2a73920024c290a402 | |
| parent | 013a636d57813594cf89f9a2ab045f5f3edebade (diff) | |
| download | mullvadvpn-d7bd37a8ff6b0f816833ee2e3512efca6cc7093d.tar.xz mullvadvpn-d7bd37a8ff6b0f816833ee2e3512efca6cc7093d.zip | |
Drop custom navigation controller
Removes redundant ConditionalNavigation protocol that is not used for
anything more than disabling pop gesture in problem reports when editing.
Pop gesture can be disabled directly from within problem report view controller.
| -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) { |
