summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorBug Magnet <marco.nikic@mullvad.net>2024-06-24 14:22:48 +0200
committerBug Magnet <marco.nikic@mullvad.net>2024-06-24 14:22:48 +0200
commit5809c7c669f7d5740d4c755433ff74f9405da2ed (patch)
treef2dbbe8abb9b56b046bd4e3ef9c8ea615dd4403f
parentd304842116557290d2cd0086216aedc6fdbb1a83 (diff)
parent3d3577998bc46260361c0c75cc2834df2e409386 (diff)
downloadmullvadvpn-5809c7c669f7d5740d4c755433ff74f9405da2ed.tar.xz
mullvadvpn-5809c7c669f7d5740d4c755433ff74f9405da2ed.zip
Merge branch 'make-it-look-like-an-iphone-ios-719'
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj32
-rw-r--r--ios/MullvadVPN/Classes/AppRoutes.swift5
-rw-r--r--ios/MullvadVPN/Classes/AutomaticKeyboardResponder.swift92
-rw-r--r--ios/MullvadVPN/Containers/CustomSplitViewController.swift81
-rw-r--r--ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift280
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/ShadowsocksSectionHandler.swift4
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/SocksSectionHandler.swift4
-rw-r--r--ios/MullvadVPN/Presentation controllers/SecondaryContextPresentationController.swift77
-rw-r--r--ios/MullvadVPN/UI appearance/UIMetrics.swift3
-rw-r--r--ios/MullvadVPN/View controllers/Login/LoginViewController.swift20
-rw-r--r--ios/MullvadVPN/View controllers/Tunnel/DisconnectSplitButton.swift17
-rw-r--r--ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift83
-rw-r--r--ios/MullvadVPN/Views/AppButton.swift12
13 files changed, 60 insertions, 650 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index faa02954e7..10e3e3ab8a 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -115,7 +115,6 @@
5838322B2AC3EF9600EA2071 /* EventChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5838322A2AC3EF9600EA2071 /* EventChannel.swift */; };
583D86482A2678DC0060D63B /* DeviceStateAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 583D86472A2678DC0060D63B /* DeviceStateAccessor.swift */; };
583DA21425FA4B5C00318683 /* LocationDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 583DA21325FA4B5C00318683 /* LocationDataSource.swift */; };
- 583FE01029C0F532006E85F9 /* CustomSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 583FE00F29C0F532006E85F9 /* CustomSplitViewController.swift */; };
583FE02429C1ACB3006E85F9 /* RESTCreateApplePaymentResponse+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06FAE67828F83CA50033DD93 /* RESTCreateApplePaymentResponse+Localization.swift */; };
584023222A406BF5007B27AC /* UDPOverTCPObfuscator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 584023212A406BF5007B27AC /* UDPOverTCPObfuscator.swift */; };
584023292A407F5F007B27AC /* libtunnel_obfuscator_proxy.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 584023282A407F5F007B27AC /* libtunnel_obfuscator_proxy.a */; };
@@ -138,8 +137,6 @@
58607A4D2947287800BC467D /* AccountExpiryInAppNotificationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58607A4C2947287800BC467D /* AccountExpiryInAppNotificationProvider.swift */; };
586168692976F6BD00EF8598 /* DisplayError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 586168682976F6BD00EF8598 /* DisplayError.swift */; };
5862805422428EF100F5A6E1 /* TranslucentButtonBlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5862805322428EF100F5A6E1 /* TranslucentButtonBlurView.swift */; };
- 5864859929A0D028006C5743 /* FormsheetPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5864859829A0D028006C5743 /* FormsheetPresentationController.swift */; };
- 5864859B29A0EAF2006C5743 /* SecondaryContextPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5864859A29A0EAF2006C5743 /* SecondaryContextPresentationController.swift */; };
5864AF0729C78843005B0CD9 /* SettingsCellFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5864AF0029C7879B005B0CD9 /* SettingsCellFactory.swift */; };
5864AF0829C78849005B0CD9 /* CellFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5864AF0129C7879B005B0CD9 /* CellFactoryProtocol.swift */; };
5864AF0929C78850005B0CD9 /* VPNSettingsCellFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5864AF0229C7879B005B0CD9 /* VPNSettingsCellFactory.swift */; };
@@ -605,6 +602,7 @@
7ADCB2D82B6A6EB300C88F89 /* AnyRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADCB2D72B6A6EB300C88F89 /* AnyRelay.swift */; };
7ADCB2DA2B6A730400C88F89 /* IPOverrideRepositoryStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADCB2D92B6A730400C88F89 /* IPOverrideRepositoryStub.swift */; };
7AE044BB2A935726003915D8 /* Routing.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A88DCD02A8FABBE00D2FF0E /* Routing.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 7AE2414A2C20682B0076CE33 /* FormsheetPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE241482C20682B0076CE33 /* FormsheetPresentationController.swift */; };
7AED35CC2BD13F60002A67D1 /* ApplicationConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58BFA5CB22A7CE1F00A6173D /* ApplicationConfiguration.swift */; };
7AED35CD2BD13FC4002A67D1 /* ApplicationTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58C76A072A33850E00100D75 /* ApplicationTarget.swift */; };
7AEF7F1A2AD00F52006FE45D /* AppMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEF7F192AD00F52006FE45D /* AppMessageHandler.swift */; };
@@ -1552,7 +1550,6 @@
583E1E292848DF67004838B3 /* OperationObserverTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationObserverTests.swift; sourceTree = "<group>"; };
583E60952A9F6D0800DC61EF /* ConfigurationBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationBuilder.swift; sourceTree = "<group>"; };
583FE00B29C0C7FD006E85F9 /* ModalPresentationConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalPresentationConfiguration.swift; sourceTree = "<group>"; };
- 583FE00F29C0F532006E85F9 /* CustomSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSplitViewController.swift; sourceTree = "<group>"; };
583FE01129C0F99A006E85F9 /* PresentationControllerDismissalInterceptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresentationControllerDismissalInterceptor.swift; sourceTree = "<group>"; };
5840231F2A406BF5007B27AC /* TunnelObfuscation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TunnelObfuscation.framework; sourceTree = BUILT_PRODUCTS_DIR; };
584023212A406BF5007B27AC /* UDPOverTCPObfuscator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UDPOverTCPObfuscator.swift; sourceTree = "<group>"; };
@@ -1585,8 +1582,6 @@
58607A4C2947287800BC467D /* AccountExpiryInAppNotificationProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountExpiryInAppNotificationProvider.swift; sourceTree = "<group>"; };
586168682976F6BD00EF8598 /* DisplayError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayError.swift; sourceTree = "<group>"; };
5862805322428EF100F5A6E1 /* TranslucentButtonBlurView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslucentButtonBlurView.swift; sourceTree = "<group>"; };
- 5864859829A0D028006C5743 /* FormsheetPresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormsheetPresentationController.swift; sourceTree = "<group>"; };
- 5864859A29A0EAF2006C5743 /* SecondaryContextPresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondaryContextPresentationController.swift; sourceTree = "<group>"; };
5864AF0029C7879B005B0CD9 /* SettingsCellFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsCellFactory.swift; sourceTree = "<group>"; };
5864AF0129C7879B005B0CD9 /* CellFactoryProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CellFactoryProtocol.swift; sourceTree = "<group>"; };
5864AF0229C7879B005B0CD9 /* VPNSettingsCellFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VPNSettingsCellFactory.swift; sourceTree = "<group>"; };
@@ -1976,6 +1971,7 @@
7AD0AA202AD6CB0000119E10 /* URLRequestProxyStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLRequestProxyStub.swift; sourceTree = "<group>"; };
7ADCB2D72B6A6EB300C88F89 /* AnyRelay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyRelay.swift; sourceTree = "<group>"; };
7ADCB2D92B6A730400C88F89 /* IPOverrideRepositoryStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPOverrideRepositoryStub.swift; sourceTree = "<group>"; };
+ 7AE241482C20682B0076CE33 /* FormsheetPresentationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormsheetPresentationController.swift; sourceTree = "<group>"; };
7AEF7F192AD00F52006FE45D /* AppMessageHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppMessageHandler.swift; sourceTree = "<group>"; };
7AF10EB12ADE859200C090B9 /* AlertViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertViewController.swift; sourceTree = "<group>"; };
7AF10EB32ADE85BC00C090B9 /* RelayFilterCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RelayFilterCoordinator.swift; sourceTree = "<group>"; };
@@ -3131,15 +3127,6 @@
path = RelayCacheTracker;
sourceTree = "<group>";
};
- 5864859729A0D012006C5743 /* Presentation controllers */ = {
- isa = PBXGroup;
- children = (
- 5864859829A0D028006C5743 /* FormsheetPresentationController.swift */,
- 5864859A29A0EAF2006C5743 /* SecondaryContextPresentationController.swift */,
- );
- path = "Presentation controllers";
- sourceTree = "<group>";
- };
5864AF0629C78816005B0CD9 /* Protocols */ = {
isa = PBXGroup;
children = (
@@ -3402,7 +3389,6 @@
children = (
58D1560C29C0B27600749324 /* Root */,
583FE01329C102EB006E85F9 /* Navigation */,
- 583FE00F29C0F532006E85F9 /* CustomSplitViewController.swift */,
);
path = Containers;
sourceTree = "<group>";
@@ -3574,7 +3560,7 @@
F09D04B82AE94F27003D4F89 /* GeneralAPIs */,
58B26E1F2943516500D5980C /* Notifications */,
586A950B2901250A007BAF2B /* Operations */,
- 5864859729A0D012006C5743 /* Presentation controllers */,
+ 7AE241492C20682B0076CE33 /* Presentation controllers */,
5864AF0629C78816005B0CD9 /* Protocols */,
585DA87526B0249A00B8C587 /* RelayCacheTracker */,
58E25F802837BBBB002CFB2C /* SceneDelegate.swift */,
@@ -3934,6 +3920,14 @@
path = SelectLocation;
sourceTree = "<group>";
};
+ 7AE241492C20682B0076CE33 /* Presentation controllers */ = {
+ isa = PBXGroup;
+ children = (
+ 7AE241482C20682B0076CE33 /* FormsheetPresentationController.swift */,
+ );
+ path = "Presentation controllers";
+ sourceTree = "<group>";
+ };
7AF9BE912A39F47D00DBFEDB /* RelayFilter */ = {
isa = PBXGroup;
children = (
@@ -5667,7 +5661,6 @@
5891BF5125E66B1E006D6FB0 /* UIBarButtonItem+KeyboardNavigation.swift in Sources */,
58E511E628DDDEAC00B0BCDE /* CodingErrors+CustomErrorDescription.swift in Sources */,
58C76A0B2A338E4300100D75 /* BackgroundTask.swift in Sources */,
- 5864859B29A0EAF2006C5743 /* SecondaryContextPresentationController.swift in Sources */,
7A9CCCC32A96302800DD6A34 /* ApplicationCoordinator.swift in Sources */,
5864AF0729C78843005B0CD9 /* SettingsCellFactory.swift in Sources */,
587B75412668FD7800DEF7E9 /* AccountExpirySystemNotificationProvider.swift in Sources */,
@@ -5796,7 +5789,6 @@
586A950E290125F3007BAF2B /* ProductsRequestOperation.swift in Sources */,
7AF9BE902A39F26000DBFEDB /* Collection+Sorting.swift in Sources */,
58F19E35228C15BA00C7710B /* SpinnerActivityIndicatorView.swift in Sources */,
- 5864859929A0D028006C5743 /* FormsheetPresentationController.swift in Sources */,
58CEB3022AFD365600E6E088 /* SwitchCellContentConfiguration.swift in Sources */,
7A9CCCB52A96302800DD6A34 /* AddCreditSucceededCoordinator.swift in Sources */,
7A0C0F632A979C4A0058EFCE /* Coordinator+Router.swift in Sources */,
@@ -5876,6 +5868,7 @@
5807E2C02432038B00F5FF30 /* String+Split.swift in Sources */,
58B26E242943520C00D5980C /* NotificationProviderProtocol.swift in Sources */,
5877F94E2A0A59AA0052D9E9 /* NotificationResponse.swift in Sources */,
+ 7AE2414A2C20682B0076CE33 /* FormsheetPresentationController.swift in Sources */,
7A6389E52B7E4247008E77E1 /* EditCustomListCoordinator.swift in Sources */,
58677712290976FB006F721F /* SettingsInteractor.swift in Sources */,
58EF875D2B1638BF00C098B2 /* ProxyConfigurationTesterProtocol.swift in Sources */,
@@ -5885,7 +5878,6 @@
5878F50029CDA742003D4BE2 /* UIView+AutoLayoutBuilder.swift in Sources */,
7A28826D2BAAC9DE00FD9F20 /* IPOverrideHeaderView.swift in Sources */,
A98502032B627B120061901E /* LocalNetworkProbe.swift in Sources */,
- 583FE01029C0F532006E85F9 /* CustomSplitViewController.swift in Sources */,
7A6F2FA92AFD0842006D0856 /* CustomDNSDataSource.swift in Sources */,
58EF580B25D69D7A00AEBA94 /* ProblemReportSubmissionOverlayView.swift in Sources */,
5892A45E265FABFF00890742 /* EmptyTableViewHeaderFooterView.swift in Sources */,
diff --git a/ios/MullvadVPN/Classes/AppRoutes.swift b/ios/MullvadVPN/Classes/AppRoutes.swift
index 13c087b9e5..108448c424 100644
--- a/ios/MullvadVPN/Classes/AppRoutes.swift
+++ b/ios/MullvadVPN/Classes/AppRoutes.swift
@@ -10,8 +10,7 @@ import Routing
import UIKit
/**
- Enum type describing groups of routes. Each group is a modal layer with horizontal navigation
- inside with exception where primary navigation is a part of root controller on iPhone.
+ Enum type describing groups of routes.
*/
enum AppRouteGroup: AppRouteGroupProtocol {
/**
@@ -47,7 +46,7 @@ enum AppRouteGroup: AppRouteGroupProtocol {
var isModal: Bool {
switch self {
case .primary:
- return UIDevice.current.userInterfaceIdiom == .pad
+ return false
case .selectLocation, .account, .settings, .changelog, .alert:
return true
diff --git a/ios/MullvadVPN/Classes/AutomaticKeyboardResponder.swift b/ios/MullvadVPN/Classes/AutomaticKeyboardResponder.swift
index 7a32ccf022..00defec889 100644
--- a/ios/MullvadVPN/Classes/AutomaticKeyboardResponder.swift
+++ b/ios/MullvadVPN/Classes/AutomaticKeyboardResponder.swift
@@ -15,9 +15,6 @@ class AutomaticKeyboardResponder {
private var lastKeyboardRect: CGRect?
- private let logger = Logger(label: "AutomaticKeyboardResponder")
- private var presentationFrameObserver: NSKeyValueObservation?
-
init<T: UIView>(targetView: T, handler: @escaping (T, CGFloat) -> Void) {
self.targetView = targetView
self.handler = { view, adjustment in
@@ -32,18 +29,6 @@ class AutomaticKeyboardResponder {
name: UIResponder.keyboardWillChangeFrameNotification,
object: nil
)
- NotificationCenter.default.addObserver(
- self,
- selector: #selector(keyboardWillShow(_:)),
- name: UIResponder.keyboardWillShowNotification,
- object: nil
- )
- NotificationCenter.default.addObserver(
- self,
- selector: #selector(keyboardWillHide(_:)),
- name: UIResponder.keyboardWillHideNotification,
- object: nil
- )
}
func updateContentInsets() {
@@ -53,14 +38,6 @@ class AutomaticKeyboardResponder {
// MARK: - Keyboard notifications
- @objc private func keyboardWillShow(_ notification: Notification) {
- addPresentationControllerObserver()
- }
-
- @objc private func keyboardWillHide(_ notification: Notification) {
- presentationFrameObserver = nil
- }
-
@objc private func keyboardWillChangeFrame(_ notification: Notification) {
handleKeyboardNotification(notification)
}
@@ -99,75 +76,6 @@ class AutomaticKeyboardResponder {
}
}
- private func addPresentationControllerObserver() {
- guard isFormSheetPresentation else { return }
-
- // Presentation controller follows the keyboard on iPad.
- // Install the observer to listen for the container view frame and adjust the target view
- // accordingly.
- guard let containerView = presentationContainerView else {
- logger.warning("Cannot determine the container view in form sheet presentation.")
- return
- }
-
- presentationFrameObserver = containerView.observe(
- \.frame,
- options: [.new],
- changeHandler: { [weak self] _, _ in
- guard let self,
- let keyboardFrameValue = lastKeyboardRect else { return }
-
- adjustContentInsets(convertedKeyboardFrameEnd: keyboardFrameValue)
- }
- )
- }
-
- /// Returns the first parent controller in the responder chain
- private var parentViewController: UIViewController? {
- var responder: UIResponder? = targetView
- let iterator = AnyIterator { () -> UIResponder? in
- responder = responder?.next
- return responder
- }
- return iterator.first { $0 is UIViewController } as? UIViewController
- }
-
- /// Returns the presentation container view that's moved along with the keyboard on iPad
- private var presentationContainerView: UIView? {
- var currentView = parentViewController?.view
- let iterator = AnyIterator { () -> UIView? in
- currentView = currentView?.superview
- return currentView
- }
-
- // Find the container view that private `_UIFormSheetPresentationController` moves
- // along with the keyboard.
- return iterator.first { view -> Bool in
- view.description.starts(with: "<UIDropShadowView")
- }
- }
-
- private var isFormSheetPresentation: Bool {
- // Form sheet is only supported on iPad
- guard UIDevice.current.userInterfaceIdiom == .pad else { return false }
-
- // Find the parent controller holding the view
- guard let parent = parentViewController else { return false }
-
- // Determine presentation style within the context
- let presentationStyle: UIModalPresentationStyle
-
- // Use the presentation style of a presented controller,
- // when parent controller is being presented as a child of other modal controller.
- if let presented = parent.presentingViewController?.presentedViewController {
- presentationStyle = presented.modalPresentationStyle
- } else {
- presentationStyle = parent.modalPresentationStyle
- }
-
- return presentationStyle == .formSheet
- }
-
private func adjustContentInsets(convertedKeyboardFrameEnd: CGRect) {
guard let targetView else { return }
diff --git a/ios/MullvadVPN/Containers/CustomSplitViewController.swift b/ios/MullvadVPN/Containers/CustomSplitViewController.swift
deleted file mode 100644
index c4ef61142d..0000000000
--- a/ios/MullvadVPN/Containers/CustomSplitViewController.swift
+++ /dev/null
@@ -1,81 +0,0 @@
-//
-// CustomSplitViewController.swift
-// MullvadVPN
-//
-// Created by pronebird on 07/04/2021.
-// Copyright © 2021 Mullvad VPN AB. All rights reserved.
-//
-
-import UIKit
-
-class CustomSplitViewController: UISplitViewController, RootContainment {
- var preferredHeaderBarPresentation: HeaderBarPresentation {
- for case let viewController as RootContainment in viewControllers {
- return viewController.preferredHeaderBarPresentation
- }
- return .default
- }
-
- var prefersHeaderBarHidden: Bool {
- for case let viewController as RootContainment in viewControllers {
- return viewController.prefersHeaderBarHidden
- }
- return false
- }
-
- var dividerColor: UIColor? {
- didSet {
- if isViewLoaded {
- self.updateDividerColor()
- }
- }
- }
-
- override var childForStatusBarStyle: UIViewController? {
- super.childForStatusBarStyle
- }
-
- override var childForStatusBarHidden: UIViewController? {
- super.childForStatusBarHidden
- }
-
- override func viewDidLayoutSubviews() {
- super.viewDidLayoutSubviews()
-
- updateDividerColor()
- }
-
- private var dividerView: UIView? {
- let subviews = view.subviews.flatMap { view -> [UIView] in
- [view] + view.subviews
- }
-
- return subviews.first { view -> Bool in
- view.description.hasPrefix("<UIPanelBorderView")
- }
- }
-
- private func updateDividerColor() {
- guard let dividerColor else { return }
-
- dividerView?.backgroundColor = dividerColor
- }
-
- override func overrideTraitCollection(forChild childViewController: UIViewController)
- -> UITraitCollection? {
- guard let traitCollection = super.overrideTraitCollection(forChild: childViewController)
- else { return nil }
-
- // Pass the split controller's horizontal size class to the primary controller when split
- // view is expanded.
- if !isCollapsed, childViewController == viewControllers.last {
- let sizeOverrideTraitCollection = UITraitCollection(
- horizontalSizeClass: self.traitCollection.horizontalSizeClass
- )
-
- return UITraitCollection(traitsFrom: [traitCollection, sizeOverrideTraitCollection])
- } else {
- return traitCollection
- }
- }
-}
diff --git a/ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift b/ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift
index 80352cdda2..0201cfd29f 100644
--- a/ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift
+++ b/ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift
@@ -26,44 +26,17 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
private(set) var router: ApplicationRouter<AppRoute>!
/**
- Primary navigation container.
+ Navigation container.
- On iPhone, it is used as a container for horizontal flows (TOS, Login, Revoked, Out-of-time).
-
- On iPad, it is used as a container to hold split view controller. Secondary navigation
- container presented modally is used for horizontal flows.
+ Used as a container for horizontal flows (TOS, Login, Revoked, Out-of-time).
*/
- private let primaryNavigationContainer = RootContainerViewController()
-
- /**
- Secondary navigation container.
-
- On iPad, it is used in place of primary container for horizontal flows and displayed modally
- above primary container. Unused on iPhone.
- */
- private let secondaryNavigationContainer = RootContainerViewController()
+ private let navigationContainer = RootContainerViewController()
/// Posts `preferredAccountNumber` notification when user inputs the account number instead of voucher code
private let preferredAccountNumberSubject = PassthroughSubject<String, Never>()
- private lazy var secondaryRootConfiguration = ModalPresentationConfiguration(
- preferredContentSize: UIMetrics.preferredFormSheetContentSize,
- modalPresentationStyle: .custom,
- isModalInPresentation: true,
- transitioningDelegate: SecondaryContextTransitioningDelegate(adjustViewWhenKeyboardAppears: false)
- )
-
private let notificationController = NotificationController()
- private let splitViewController: CustomSplitViewController = {
- let svc = CustomSplitViewController()
- svc.minimumPrimaryColumnWidth = UIMetrics.minimumSplitViewSidebarWidth
- svc.preferredPrimaryColumnWidthFraction = UIMetrics.maximumSplitViewSidebarWidthFraction
- svc.dividerColor = UIColor.MainSplitView.dividerColor
- svc.primaryEdge = .trailing
- return svc
- }()
-
private var splitTunnelCoordinator: TunnelCoordinator?
private var splitLocationCoordinator: LocationCoordinator?
@@ -84,7 +57,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
private var outOfTimeTimer: Timer?
var rootViewController: UIViewController {
- primaryNavigationContainer
+ navigationContainer
}
init(
@@ -115,8 +88,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
super.init()
- primaryNavigationContainer.delegate = self
- secondaryNavigationContainer.delegate = self
+ navigationContainer.delegate = self
router = ApplicationRouter(self)
@@ -126,11 +98,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
}
func start() {
- if isPad {
- setupSplitView()
- }
-
- setNotificationControllerParent(isPrimary: true)
+ navigationContainer.notificationController = notificationController
continueFlow(animated: false)
}
@@ -189,7 +157,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
if context.isClosing {
switch dismissedRoute.route.routeGroup {
case .primary:
- endHorizontalFlow(animated: context.isAnimated, completion: completion)
+ completion()
context.dismissedRoutes.forEach { $0.coordinator.removeFromParent() }
case .selectLocation, .account, .settings, .changelog, .alert:
@@ -292,19 +260,6 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
private func continueFlow(animated: Bool) {
var nextRoutes = evaluateNextRoutes()
- if isPad {
- /*
- On iPad the main route is always visible as it's a part of root controller hence we never
- ask router to navigate to it. Instead this is when we hide the primary horizontal
- navigation.
- */
- if nextRoutes.contains(.main) {
- router.dismissAll(.primary, animated: animated)
- }
-
- nextRoutes.removeAll { $0 == .main }
- }
-
for nextRoute in nextRoutes {
router.present(nextRoute, animated: animated)
}
@@ -354,165 +309,15 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
}
private func didDismissAccount(_ reason: AccountDismissReason) {
- if isPad {
- router.dismiss(.account, animated: true)
- if reason == .userLoggedOut {
- router.dismissAll(.primary, animated: true)
- continueFlow(animated: true)
- }
- } else {
- if reason == .userLoggedOut {
- router.dismissAll(.primary, animated: false)
- continueFlow(animated: false)
- }
- router.dismiss(.account, animated: true)
- }
- }
-
- /**
- Navigation controller used for horizontal flows.
- */
- private var horizontalFlowController: RootContainerViewController {
- if isPad {
- return secondaryNavigationContainer
- } else {
- return primaryNavigationContainer
- }
- }
-
- /**
- Begins horizontal flow presenting a navigation controller suitable for current user interface
- idiom.
-
- On iPad this takes care of presenting a secondary navigation context using modal presentation.
-
- On iPhone this does nothing.
- */
- private func beginHorizontalFlow(animated: Bool, completion: @escaping () -> Void) {
- if isPad, secondaryNavigationContainer.presentingViewController == nil {
- secondaryRootConfiguration.apply(to: secondaryNavigationContainer)
- addSecondaryContextPresentationStyleObserver()
-
- primaryNavigationContainer.present(
- secondaryNavigationContainer,
- animated: animated,
- completion: completion
- )
- } else {
- completion()
- }
- }
-
- /**
- Marks the end of horizontal flow.
-
- On iPad this method dismisses the modally presented secondary navigation container and
- releases all child view controllers from it.
-
- Does nothing on iPhone.
- */
- private func endHorizontalFlow(animated: Bool = true, completion: (() -> Void)? = nil) {
- if isPad {
- removeSecondaryContextPresentationStyleObserver()
-
- secondaryNavigationContainer.dismiss(animated: animated) {
- // Put notification controller back into primary container.
- self.setNotificationControllerParent(isPrimary: true)
-
- completion?()
- }
- } else {
- completion?()
- }
- }
-
- /**
- Assigns notification controller to either primary or secondary container making sure that only one of them holds
- the reference.
- */
- private func setNotificationControllerParent(isPrimary: Bool) {
- if isPrimary {
- secondaryNavigationContainer.notificationController = nil
- primaryNavigationContainer.notificationController = notificationController
- } else {
- primaryNavigationContainer.notificationController = nil
- secondaryNavigationContainer.notificationController = notificationController
+ if reason == .userLoggedOut {
+ router.dismissAll(.primary, animated: false)
+ continueFlow(animated: false)
}
- }
-
- /**
- Start observing secondary context presentation style which is in compact environment turns into fullscreen
- and otherwise looks like formsheet.
-
- In response to compact environment and fullscreen presentation, the observer re-assigns notification controller
- from primary to secondary context to mimic the look and feel of iPhone app. The opposite is also true, that it
- will make sure that notification controller is presented within primary context when secondary context is in
- formsheet presentation style.
- */
- private func addSecondaryContextPresentationStyleObserver() {
- removeSecondaryContextPresentationStyleObserver()
-
- NotificationCenter.default.addObserver(
- self,
- selector: #selector(formSheetControllerWillChangeFullscreenPresentation(_:)),
- name: FormSheetPresentationController.willChangeFullScreenPresentation,
- object: secondaryNavigationContainer
- )
- }
-
- /**
- Stop observing secondary context presentation style.
- */
- private func removeSecondaryContextPresentationStyleObserver() {
- NotificationCenter.default.removeObserver(
- self,
- name: FormSheetPresentationController.willChangeFullScreenPresentation,
- object: secondaryNavigationContainer
- )
- }
-
- /**
- This method is called in response to changes in fullscreen presentation style of form sheet presentation
- controller.
- */
- @objc private func formSheetControllerWillChangeFullscreenPresentation(_ note: Notification) {
- guard let isFullscreenNumber = note
- .userInfo?[SecondaryContextPresentationController.isFullScreenUserInfoKey] as? NSNumber else { return }
-
- setNotificationControllerParent(isPrimary: !isFullscreenNumber.boolValue)
- }
-
- private var isPad: Bool {
- UIDevice.current.userInterfaceIdiom == .pad
- }
-
- private func setupSplitView() {
- let tunnelCoordinator = makeTunnelCoordinator()
- let locationCoordinator = makeLocationCoordinator(forModalPresentation: false)
-
- addChild(tunnelCoordinator)
- addChild(locationCoordinator)
-
- splitTunnelCoordinator = tunnelCoordinator
- splitLocationCoordinator = locationCoordinator
-
- splitViewController.delegate = self
- splitViewController.viewControllers = [
- locationCoordinator.navigationController,
- tunnelCoordinator.rootViewController,
- ]
-
- primaryNavigationContainer.setViewControllers([splitViewController], animated: false)
-
- primaryNavigationContainer.notificationViewLayoutGuide = tunnelCoordinator.rootViewController.view
- .safeAreaLayoutGuide
-
- tunnelCoordinator.start()
- locationCoordinator.start()
+ router.dismiss(.account, animated: true)
}
private func presentTOS(animated: Bool, completion: @escaping (Coordinator) -> Void) {
- let coordinator = TermsOfServiceCoordinator(navigationController: horizontalFlowController)
+ let coordinator = TermsOfServiceCoordinator(navigationController: navigationContainer)
coordinator.didFinish = { [weak self] _ in
self?.appPreferences.isAgreedToTermsOfService = true
@@ -522,9 +327,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
addChild(coordinator)
coordinator.start()
- beginHorizontalFlow(animated: animated) {
- completion(coordinator)
- }
+ completion(coordinator)
}
private func presentChangeLog(animated: Bool, completion: @escaping (Coordinator) -> Void) {
@@ -543,10 +346,9 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
}
private func presentMain(animated: Bool, completion: @escaping (Coordinator) -> Void) {
- precondition(!isPad)
let tunnelCoordinator = makeTunnelCoordinator()
- horizontalFlowController.pushViewController(
+ navigationContainer.pushViewController(
tunnelCoordinator.rootViewController,
animated: animated
)
@@ -554,14 +356,12 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
addChild(tunnelCoordinator)
tunnelCoordinator.start()
- beginHorizontalFlow(animated: animated) {
- completion(tunnelCoordinator)
- }
+ completion(tunnelCoordinator)
}
private func presentRevoked(animated: Bool, completion: @escaping (Coordinator) -> Void) {
let coordinator = RevokedCoordinator(
- navigationController: horizontalFlowController,
+ navigationController: navigationContainer,
tunnelManager: tunnelManager
)
@@ -572,14 +372,12 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
addChild(coordinator)
coordinator.start(animated: animated)
- beginHorizontalFlow(animated: animated) {
- completion(coordinator)
- }
+ completion(coordinator)
}
private func presentOutOfTime(animated: Bool, completion: @escaping (Coordinator) -> Void) {
let coordinator = OutOfTimeCoordinator(
- navigationController: horizontalFlowController,
+ navigationController: navigationContainer,
storePaymentManager: storePaymentManager,
tunnelManager: tunnelManager
)
@@ -596,14 +394,12 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
addChild(coordinator)
coordinator.start(animated: animated)
- beginHorizontalFlow(animated: animated) {
- completion(coordinator)
- }
+ completion(coordinator)
}
private func presentWelcome(animated: Bool, completion: @escaping (Coordinator) -> Void) {
let coordinator = WelcomeCoordinator(
- navigationController: horizontalFlowController,
+ navigationController: navigationContainer,
storePaymentManager: storePaymentManager,
tunnelManager: tunnelManager,
accountsProxy: accountsProxy
@@ -624,9 +420,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
addChild(coordinator)
coordinator.start(animated: animated)
- beginHorizontalFlow(animated: animated) {
- completion(coordinator)
- }
+ completion(coordinator)
}
private func shouldDismissOutOfTime() -> Bool {
@@ -644,7 +438,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
private func presentLogin(animated: Bool, completion: @escaping (Coordinator) -> Void) {
let coordinator = LoginCoordinator(
- navigationController: horizontalFlowController,
+ navigationController: navigationContainer,
tunnelManager: tunnelManager,
devicesProxy: devicesProxy
)
@@ -661,9 +455,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
addChild(coordinator)
coordinator.start(animated: animated)
- beginHorizontalFlow(animated: animated) {
- completion(coordinator)
- }
+ completion(coordinator)
}
private func presentAlert(
@@ -743,11 +535,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
presentChild(
coordinator,
- animated: animated,
- configuration: ModalPresentationConfiguration(
- preferredContentSize: UIMetrics.preferredFormSheetContentSize,
- modalPresentationStyle: .formSheet
- )
+ animated: animated
) { [weak self] in
completion(coordinator)
@@ -795,11 +583,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
presentChild(
coordinator,
- animated: animated,
- configuration: ModalPresentationConfiguration(
- preferredContentSize: UIMetrics.preferredFormSheetContentSize,
- modalPresentationStyle: .formSheet
- )
+ animated: animated
) {
completion(coordinator)
}
@@ -824,12 +608,9 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
self.tunnelObserver = tunnelObserver
updateDeviceInfo(deviceState: tunnelManager.deviceState)
-
- splitViewController.preferredDisplayMode = tunnelManager.deviceState.splitViewMode
}
private func deviceStateDidChange(_ deviceState: DeviceState, previousDeviceState: DeviceState) {
- splitViewController.preferredDisplayMode = deviceState.splitViewMode
updateDeviceInfo(deviceState: deviceState)
switch deviceState {
@@ -867,8 +648,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
isPresentingAccountExpiryBanner: isPresentingAccountExpiryBanner,
deviceState: deviceState
)
- self.primaryNavigationContainer.update(configuration: rootDeviceInfoViewModel.configuration)
- self.secondaryNavigationContainer.update(configuration: rootDeviceInfoViewModel.configuration)
+ self.navigationContainer.update(configuration: rootDeviceInfoViewModel.configuration)
}
// MARK: - Out of time
@@ -968,11 +748,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
func rootContainerViewSupportedInterfaceOrientations(_ controller: RootContainerViewController)
-> UIInterfaceOrientationMask {
- if isPad {
- return [.landscape, .portrait]
- } else {
- return [.portrait]
- }
+ return [.portrait]
}
func rootContainerViewAccessibilityPerformMagicTap(_ controller: RootContainerViewController)
@@ -1019,7 +795,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
// MARK: - Presenting
var presentationContext: UIViewController {
- primaryNavigationContainer.presentedViewController ?? primaryNavigationContainer
+ navigationContainer.presentedViewController ?? navigationContainer
}
}
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/ShadowsocksSectionHandler.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/ShadowsocksSectionHandler.swift
index 1f5fc64527..81d9e9fc02 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/ShadowsocksSectionHandler.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/ShadowsocksSectionHandler.swift
@@ -47,9 +47,7 @@ struct ShadowsocksSectionHandler {
contentConfiguration.inputFilter = .digitsOnly
contentConfiguration.editingEvents.onChange = subject.bindTextAction(to: \.shadowsocks.port)
contentConfiguration.textFieldProperties = .withSmartFeaturesDisabled()
- if case .phone = cell.traitCollection.userInterfaceIdiom {
- contentConfiguration.textFieldProperties.keyboardType = .numberPad
- }
+ contentConfiguration.textFieldProperties.keyboardType = .numberPad
cell.contentConfiguration = contentConfiguration
}
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/SocksSectionHandler.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/SocksSectionHandler.swift
index e2dd45f9d6..c1bcf9ca52 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/SocksSectionHandler.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/SocksSectionHandler.swift
@@ -50,9 +50,7 @@ struct SocksSectionHandler {
contentConfiguration.inputFilter = .digitsOnly
contentConfiguration.editingEvents.onChange = subject.bindTextAction(to: \.socks.port)
contentConfiguration.textFieldProperties = .withSmartFeaturesDisabled()
- if case .phone = cell.traitCollection.userInterfaceIdiom {
- contentConfiguration.textFieldProperties.keyboardType = .numberPad
- }
+ contentConfiguration.textFieldProperties.keyboardType = .numberPad
cell.accessibilityIdentifier = .socks5PortCell
cell.contentConfiguration = contentConfiguration
}
diff --git a/ios/MullvadVPN/Presentation controllers/SecondaryContextPresentationController.swift b/ios/MullvadVPN/Presentation controllers/SecondaryContextPresentationController.swift
deleted file mode 100644
index f218104074..0000000000
--- a/ios/MullvadVPN/Presentation controllers/SecondaryContextPresentationController.swift
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-// SecondaryContextPresentationController.swift
-// MullvadVPN
-//
-// Created by pronebird on 18/02/2023.
-// Copyright © 2023 Mullvad VPN AB. All rights reserved.
-//
-
-import UIKit
-
-/**
- This is a presentation controller class used for presentation of secondary navigation context
- in application coordinator.
- */
-class SecondaryContextPresentationController: FormSheetPresentationController {
- override func presentationTransitionWillBegin() {
- super.presentationTransitionWillBegin()
-
- updateHeaderBarHidden()
-
- if let containerView,
- let rootContainer = presentingViewController as? RootContainerViewController {
- rootContainer.addTrailingButtonsToPresentationContainer(containerView)
- }
- }
-
- override func dismissalTransitionDidEnd(_ completed: Bool) {
- super.dismissalTransitionDidEnd(completed)
-
- if let rootContainer = presentingViewController as? RootContainerViewController, completed {
- rootContainer.removeTrailingButtonsFromPresentationContainer()
- }
- }
-
- override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
- super.traitCollectionDidChange(previousTraitCollection)
-
- updateHeaderBarHidden()
- }
-
- private func updateHeaderBarHidden() {
- let presentedController = presentedViewController as? RootContainerViewController
-
- presentedController?.setOverrideHeaderBarHidden(
- isInFullScreenPresentation ? nil : true,
- animated: false
- )
- }
-}
-
-class SecondaryContextTransitioningDelegate: FormSheetTransitioningDelegate {
- convenience init(adjustViewWhenKeyboardAppears: Bool) {
- let option = FormSheetPresentationOptions(
- useFullScreenPresentationInCompactWidth: true,
- adjustViewWhenKeyboardAppears: adjustViewWhenKeyboardAppears
- )
- self.init(options: option)
- }
-
- private override init(options: FormSheetPresentationOptions) {
- super.init(options: options)
- }
-
- override func presentationController(
- forPresented presented: UIViewController,
- presenting: UIViewController?,
- source: UIViewController
- ) -> UIPresentationController? {
- let presentationController = SecondaryContextPresentationController(
- presentedViewController: presented,
- presenting: source,
- options: options
- )
-
- return presentationController
- }
-}
diff --git a/ios/MullvadVPN/UI appearance/UIMetrics.swift b/ios/MullvadVPN/UI appearance/UIMetrics.swift
index c3fbe48cff..aa6502d126 100644
--- a/ios/MullvadVPN/UI appearance/UIMetrics.swift
+++ b/ios/MullvadVPN/UI appearance/UIMetrics.swift
@@ -104,8 +104,7 @@ enum UIMetrics {
}
enum DisconnectSplitButton {
- static let secondaryButtonPhone = CGSize(width: 42, height: 42)
- static let secondaryButtonPad = CGSize(width: 52, height: 52)
+ static let secondaryButton = CGSize(width: 42, height: 42)
}
enum FilterView {
diff --git a/ios/MullvadVPN/View controllers/Login/LoginViewController.swift b/ios/MullvadVPN/View controllers/Login/LoginViewController.swift
index 64d4ad01dc..bf6c2d1401 100644
--- a/ios/MullvadVPN/View controllers/Login/LoginViewController.swift
+++ b/ios/MullvadVPN/View controllers/Login/LoginViewController.swift
@@ -178,17 +178,6 @@ class LoginViewController: UIViewController, RootContainment {
)
}
- override var disablesAutomaticKeyboardDismissal: Bool {
- // Allow dismissing the keyboard in .formSheet presentation style
- false
- }
-
- override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
- if traitCollection.userInterfaceIdiom != previousTraitCollection?.userInterfaceIdiom {
- updateCreateButtonEnabled()
- }
- }
-
// MARK: - Public
func start(action: LoginAction) {
@@ -320,14 +309,7 @@ class LoginViewController: UIViewController, RootContainment {
switch loginState {
case .failure, .default:
- // Disable "Create account" button on iPad as user types in the account token,
- // however leave it enabled on iPhone to avoid confusion to why it's being disabled
- // since it's likely overlaid by keyboard.
- if case .pad = traitCollection.userInterfaceIdiom {
- isEnabled = contentView.accountInputGroup.textField.text?.isEmpty ?? true
- } else {
- isEnabled = true
- }
+ isEnabled = true
case .success, .authenticating:
isEnabled = false
diff --git a/ios/MullvadVPN/View controllers/Tunnel/DisconnectSplitButton.swift b/ios/MullvadVPN/View controllers/Tunnel/DisconnectSplitButton.swift
index 8baa2eaac7..0fcdf7efd1 100644
--- a/ios/MullvadVPN/View controllers/Tunnel/DisconnectSplitButton.swift
+++ b/ios/MullvadVPN/View controllers/Tunnel/DisconnectSplitButton.swift
@@ -11,14 +11,7 @@ import UIKit
class DisconnectSplitButton: UIView {
private var secondaryButtonSize: CGSize {
- switch traitCollection.userInterfaceIdiom {
- case .phone:
- return UIMetrics.DisconnectSplitButton.secondaryButtonPhone
- case .pad:
- return UIMetrics.DisconnectSplitButton.secondaryButtonPad
- default:
- return .zero
- }
+ UIMetrics.DisconnectSplitButton.secondaryButton
}
let primaryButton = AppButton(style: .translucentDangerSplitLeft)
@@ -71,14 +64,6 @@ class DisconnectSplitButton: UIView {
fatalError("init(coder:) has not been implemented")
}
- override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
- super.traitCollectionDidChange(previousTraitCollection)
-
- if traitCollection.userInterfaceIdiom != previousTraitCollection?.userInterfaceIdiom {
- updateTraitConstraints()
- }
- }
-
private func updateTraitConstraints() {
let newSize = secondaryButtonSize
secondaryButtonWidthConstraint.constant = newSize.width
diff --git a/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift b/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift
index 16fd69b25b..584a3c7ff3 100644
--- a/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift
+++ b/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift
@@ -129,21 +129,6 @@ final class TunnelControlView: UIView {
fatalError("init(coder:) has not been implemented")
}
- override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
- super.traitCollectionDidChange(previousTraitCollection)
-
- if traitCollection.userInterfaceIdiom != previousTraitCollection?.userInterfaceIdiom {
- updateTraitConstraints()
- }
-
- if previousTraitCollection?.userInterfaceIdiom != traitCollection.userInterfaceIdiom ||
- previousTraitCollection?.horizontalSizeClass != traitCollection.horizontalSizeClass {
- if let viewModel {
- updateActionButtons(tunnelState: viewModel.tunnelStatus.state)
- }
- }
- }
-
func update(with model: TunnelControlViewModel) {
viewModel = model
let tunnelState = model.tunnelStatus.state
@@ -355,30 +340,9 @@ final class TunnelControlView: UIView {
private func updateTraitConstraints() {
var layoutConstraints = [NSLayoutConstraint]()
- switch traitCollection.userInterfaceIdiom {
- case .pad:
- // Max container width is 70% width of iPad in portrait mode
- let maxWidth = min(
- UIScreen.main.nativeBounds.width * 0.7,
- UIMetrics.maximumSplitViewContentContainerWidth
- )
-
- layoutConstraints.append(contentsOf: [
- containerView.trailingAnchor.constraint(
- lessThanOrEqualTo: layoutMarginsGuide.trailingAnchor
- ),
- containerView.widthAnchor.constraint(equalToConstant: maxWidth)
- .withPriority(.defaultHigh),
- ])
-
- case .phone:
- layoutConstraints.append(
- containerView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor)
- )
-
- default:
- break
- }
+ layoutConstraints.append(
+ containerView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor)
+ )
removeConstraints(traitConstraints)
traitConstraints = layoutConstraints
@@ -456,40 +420,19 @@ final class TunnelControlView: UIView {
private extension TunnelState {
func actionButtons(traitCollection: UITraitCollection) -> [TunnelControlActionButton] {
- switch (traitCollection.userInterfaceIdiom, traitCollection.horizontalSizeClass) {
- case (.phone, _), (.pad, .compact):
- switch self {
- case .disconnected, .disconnecting(.nothing), .waitingForConnectivity(.noNetwork):
- [.selectLocation, .connect]
-
- case .connecting, .pendingReconnect, .disconnecting(.reconnect),
- .waitingForConnectivity(.noConnection):
- [.selectLocation, .cancel]
+ switch self {
+ case .disconnected, .disconnecting(.nothing), .waitingForConnectivity(.noNetwork):
+ [.selectLocation, .connect]
- case .negotiatingPostQuantumKey:
- [.selectLocation, .cancel]
+ case .connecting, .pendingReconnect, .disconnecting(.reconnect),
+ .waitingForConnectivity(.noConnection):
+ [.selectLocation, .cancel]
- case .connected, .reconnecting, .error:
- [.selectLocation, .disconnect]
- }
+ case .negotiatingPostQuantumKey:
+ [.selectLocation, .cancel]
- case (.pad, .regular):
- switch self {
- case .disconnected, .disconnecting(.nothing), .waitingForConnectivity(.noNetwork):
- [.connect]
-
- case .connecting, .pendingReconnect, .disconnecting(.reconnect),
- .waitingForConnectivity(.noConnection):
- [.cancel]
-
- case .negotiatingPostQuantumKey:
- [.cancel]
- case .connected, .reconnecting, .error:
- [.disconnect]
- }
-
- default:
- []
+ case .connected, .reconnecting, .error:
+ [.selectLocation, .disconnect]
}
}
diff --git a/ios/MullvadVPN/Views/AppButton.swift b/ios/MullvadVPN/Views/AppButton.swift
index c2581d5c71..3209828d12 100644
--- a/ios/MullvadVPN/Views/AppButton.swift
+++ b/ios/MullvadVPN/Views/AppButton.swift
@@ -156,16 +156,4 @@ class AppButton: CustomButton {
guard let directionalEdgeInsets = innerDirectionalContentEdgeInsets else { return }
super.contentEdgeInsets = directionalEdgeInsets.toEdgeInsets(effectiveUserInterfaceLayoutDirection)
}
-
- override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
- super.traitCollectionDidChange(previousTraitCollection)
-
- if traitCollection.userInterfaceIdiom != previousTraitCollection?.userInterfaceIdiom {
- if overrideContentEdgeInsets {
- updateContentEdgeInsetsFromDirectional()
- } else {
- contentEdgeInsets = defaultContentInsets
- }
- }
- }
}