summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2023-01-19 08:36:32 +0100
committerAndrej Mihajlov <and@mullvad.net>2023-01-20 08:59:06 +0100
commitd7bd37a8ff6b0f816833ee2e3512efca6cc7093d (patch)
tree30f68eddd8c4975661217b2a73920024c290a402
parent013a636d57813594cf89f9a2ab045f5f3edebade (diff)
downloadmullvadvpn-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.pbxproj4
-rw-r--r--ios/MullvadVPN/CustomNavigationController.swift122
-rw-r--r--ios/MullvadVPN/ProblemReportViewController.swift37
-rw-r--r--ios/MullvadVPN/SettingsNavigationController.swift45
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) {