diff options
| author | Bug Magnet <marco.nikic@mullvad.net> | 2025-01-16 15:25:58 +0100 |
|---|---|---|
| committer | Bug Magnet <marco.nikic@mullvad.net> | 2025-01-20 08:49:28 +0100 |
| commit | 1482b26664c6450dd33eeac5e1d18788cbc0d4a3 (patch) | |
| tree | 449c94c071bda8ee4bd0d7dfd735773862932dc8 | |
| parent | 5b3b433809f9fcadba1cc12d616a3edc67592356 (diff) | |
| download | mullvadvpn-1482b26664c6450dd33eeac5e1d18788cbc0d4a3.tar.xz mullvadvpn-1482b26664c6450dd33eeac5e1d18788cbc0d4a3.zip | |
Move the Progress view away from the ConnectionView
4 files changed, 32 insertions, 227 deletions
diff --git a/ios/MullvadVPN/View controllers/Tunnel/ActivityIndicator.swift b/ios/MullvadVPN/View controllers/Tunnel/ActivityIndicator.swift index 9b42bab8e6..241515798c 100644 --- a/ios/MullvadVPN/View controllers/Tunnel/ActivityIndicator.swift +++ b/ios/MullvadVPN/View controllers/Tunnel/ActivityIndicator.swift @@ -11,6 +11,7 @@ import SwiftUI struct CustomProgressView: View { var style: Style @State private var angle: Double = 0 + @ObservedObject var connectionViewModel: ConnectionViewViewModel var body: some View { Image(.iconSpinner) @@ -22,12 +23,19 @@ struct CustomProgressView: View { angle = 360 } } + .onDisappear { + withAnimation(Animation.linear(duration: 0.6).repeatForever(autoreverses: false)) { + angle = 0 + } + } +// .showIf(connectionViewModel.showsActivityIndicator) } } #Preview { - CustomProgressView(style: .large) - .background(UIColor.secondaryColor.color) + ConnectionViewComponentPreview(showIndicators: true, isExpanded: true) { _, viewModel, _ in + CustomProgressView(style: .large, connectionViewModel: viewModel) + } } extension CustomProgressView { diff --git a/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ConnectionView.swift b/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ConnectionView.swift index 6dfee3abed..51a6b99eff 100644 --- a/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ConnectionView.swift +++ b/ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ConnectionView.swift @@ -22,9 +22,6 @@ struct ConnectionView: View { .accessibilityIdentifier(AccessibilityIdentifier.connectionView.asString) VStack(spacing: 22) { - CustomProgressView(style: .large) - .showIf(connectionViewModel.showsActivityIndicator) - ZStack { BlurView(style: .dark) diff --git a/ios/MullvadVPN/View controllers/Tunnel/FeatureIndicators/FI_TunnelViewController.swift b/ios/MullvadVPN/View controllers/Tunnel/FeatureIndicators/FI_TunnelViewController.swift deleted file mode 100644 index bb754a0c25..0000000000 --- a/ios/MullvadVPN/View controllers/Tunnel/FeatureIndicators/FI_TunnelViewController.swift +++ /dev/null @@ -1,221 +0,0 @@ -// -// FI_TunnelViewController.swift -// MullvadVPN -// -// Created by Jon Petersson on 2024-12-10. -// Copyright © 2024 Mullvad VPN AB. All rights reserved. -// - -import Combine -import MapKit -import MullvadLogging -import MullvadSettings -import MullvadTypes -import SwiftUI - -// NOTE: This ViewController will replace TunnelViewController once feature indicators work is done. - -class FI_TunnelViewController: UIViewController, RootContainment { - private let logger = Logger(label: "TunnelViewController") - private let interactor: TunnelViewControllerInteractor - private var tunnelState: TunnelState = .disconnected - private var connectionViewViewModel: ConnectionViewViewModel - private var indicatorsViewViewModel: FeatureIndicatorsViewModel - private var connectionView: ConnectionView - private var connectionController: UIHostingController<ConnectionView>? - - var shouldShowSelectLocationPicker: (() -> Void)? - var shouldShowCancelTunnelAlert: (() -> Void)? - - private let mapViewController = MapViewController() - - override var preferredStatusBarStyle: UIStatusBarStyle { - .lightContent - } - - var preferredHeaderBarPresentation: HeaderBarPresentation { - switch interactor.deviceState { - case .loggedIn, .revoked: - return HeaderBarPresentation( - style: tunnelState.isSecured ? .secured : .unsecured, - showsDivider: false - ) - case .loggedOut: - return HeaderBarPresentation(style: .default, showsDivider: true) - } - } - - var prefersHeaderBarHidden: Bool { - false - } - - init(interactor: TunnelViewControllerInteractor) { - self.interactor = interactor - - tunnelState = interactor.tunnelStatus.state - connectionViewViewModel = ConnectionViewViewModel(tunnelStatus: interactor.tunnelStatus) - indicatorsViewViewModel = FeatureIndicatorsViewModel( - tunnelSettings: interactor.tunnelSettings, - ipOverrides: interactor.ipOverrides - ) - - connectionView = ConnectionView( - connectionViewModel: self.connectionViewViewModel, - indicatorsViewModel: self.indicatorsViewViewModel - ) - - super.init(nibName: nil, bundle: nil) - - // When content size is updated in SwiftUI we need to explicitly tell UIKit to - // update its view size. This is not necessary on iOS 16 where we can set - // hostingController.sizingOptions instead. - connectionView.onContentUpdate = { [weak self] in - self?.connectionController?.view.setNeedsUpdateConstraints() - } - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - interactor.didUpdateDeviceState = { [weak self] _, _ in - self?.setNeedsHeaderBarStyleAppearanceUpdate() - } - - interactor.didUpdateTunnelStatus = { [weak self] tunnelStatus in - self?.connectionViewViewModel.tunnelStatus = tunnelStatus - self?.setTunnelState(tunnelStatus.state, animated: true) - self?.view.setNeedsLayout() - } - - interactor.didGetOutgoingAddress = { [weak self] connectionInfo in - self?.connectionViewViewModel.outgoingConnectionInfo = connectionInfo - } - - interactor.didUpdateTunnelSettings = { [weak self] tunnelSettings in - self?.indicatorsViewViewModel.tunnelSettings = tunnelSettings - } - - interactor.didUpdateIpOverrides = { [weak self] overrides in - self?.indicatorsViewViewModel.ipOverrides = overrides - } - - connectionView.action = { [weak self] action in - switch action { - case .connect: - self?.interactor.startTunnel() - - case .cancel: - if case .waitingForConnectivity(.noConnection) = self?.interactor.tunnelStatus.state { - self?.shouldShowCancelTunnelAlert?() - } else { - self?.interactor.stopTunnel() - } - - case .disconnect: - self?.interactor.stopTunnel() - - case .reconnect: - self?.interactor.reconnectTunnel(selectNewRelay: true) - - case .selectLocation: - self?.shouldShowSelectLocationPicker?() - } - } - - addMapController() - addContentView() - updateMap(animated: false) - } - - func setMainContentHidden(_ isHidden: Bool, animated: Bool) { - let actions = { - _ = self.connectionView.opacity(isHidden ? 0 : 1) - } - - if animated { - UIView.animate(withDuration: 0.25, animations: actions) - } else { - actions() - } - } - - // MARK: - Private - - private func setTunnelState(_ tunnelState: TunnelState, animated: Bool) { - self.tunnelState = tunnelState - - setNeedsHeaderBarStyleAppearanceUpdate() - - guard isViewLoaded else { return } - - updateMap(animated: animated) - } - - private func updateMap(animated: Bool) { - switch tunnelState { - case let .connecting(tunnelRelays, _, _): - mapViewController.removeLocationMarker() - mapViewController.setCenter(tunnelRelays?.exit.location.geoCoordinate, animated: animated) - connectionViewViewModel.showsActivityIndicator = true - - case let .reconnecting(tunnelRelays, _, _), let .negotiatingEphemeralPeer(tunnelRelays, _, _, _): - mapViewController.removeLocationMarker() - mapViewController.setCenter(tunnelRelays.exit.location.geoCoordinate, animated: animated) - connectionViewViewModel.showsActivityIndicator = true - - case let .connected(tunnelRelays, _, _): - let center = tunnelRelays.exit.location.geoCoordinate - mapViewController.setCenter(center, animated: animated) { - self.connectionViewViewModel.showsActivityIndicator = false - - // Connection can change during animation, so make sure we're still connected before adding marker. - if case .connected = self.tunnelState { - self.mapViewController.addLocationMarker(coordinate: center) - } - } - - case .pendingReconnect: - mapViewController.removeLocationMarker() - connectionViewViewModel.showsActivityIndicator = true - - case .waitingForConnectivity, .error: - mapViewController.removeLocationMarker() - connectionViewViewModel.showsActivityIndicator = false - - case .disconnected, .disconnecting: - mapViewController.removeLocationMarker() - mapViewController.setCenter(nil, animated: animated) - connectionViewViewModel.showsActivityIndicator = false - } - } - - private func addMapController() { - let mapView = mapViewController.view! - - addChild(mapViewController) - mapViewController.didMove(toParent: self) - - view.addConstrainedSubviews([mapView]) { - mapView.pinEdgesToSuperview() - } - } - - private func addContentView() { - let connectionController = UIHostingController(rootView: connectionView) - self.connectionController = connectionController - - let connectionViewProxy = connectionController.view! - connectionViewProxy.backgroundColor = .clear - - addChild(connectionController) - connectionController.didMove(toParent: self) - - view.addConstrainedSubviews([connectionViewProxy]) { - connectionViewProxy.pinEdgesToSuperview(.all()) - } - } -} diff --git a/ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift b/ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift index a486014e72..846b460837 100644 --- a/ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift +++ b/ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift @@ -21,6 +21,8 @@ class TunnelViewController: UIViewController, RootContainment { private var indicatorsViewViewModel: FeatureIndicatorsViewModel private var connectionView: ConnectionView private var connectionController: UIHostingController<ConnectionView>? + private var progressView: CustomProgressView + private var progressViewController: UIHostingController<CustomProgressView>? var shouldShowSelectLocationPicker: (() -> Void)? var shouldShowCancelTunnelAlert: (() -> Void)? @@ -61,6 +63,10 @@ class TunnelViewController: UIViewController, RootContainment { connectionViewModel: self.connectionViewViewModel, indicatorsViewModel: self.indicatorsViewViewModel ) + progressView = CustomProgressView( + style: .large, + connectionViewModel: connectionViewViewModel + ) super.init(nibName: nil, bundle: nil) @@ -69,6 +75,7 @@ class TunnelViewController: UIViewController, RootContainment { // hostingController.sizingOptions instead. connectionView.onContentUpdate = { [weak self] in self?.connectionController?.view.setNeedsUpdateConstraints() + self?.progressViewController?.view.setNeedsUpdateConstraints() } } @@ -212,7 +219,21 @@ class TunnelViewController: UIViewController, RootContainment { addChild(connectionController) connectionController.didMove(toParent: self) - view.addConstrainedSubviews([connectionViewProxy]) { + let progressViewController = UIHostingController(rootView: progressView) + self.progressViewController = progressViewController + + let progressViewProxy = progressViewController.view! + progressViewProxy.backgroundColor = .clear + + addChild(progressViewController) + progressViewController.didMove(toParent: self) + + let verticalCenteredAnchor = progressViewProxy.centerYAnchor.anchorWithOffset(to: view.centerYAnchor) + view.addConstrainedSubviews([progressViewProxy, connectionViewProxy]) { + progressViewProxy.centerXAnchor.constraint(equalTo: view.centerXAnchor) + // Align the progress view to 2/3 of the height of the map + verticalCenteredAnchor.constraint(equalTo: progressViewProxy.heightAnchor, multiplier: 3.0 / 2.0) + connectionViewProxy.pinEdgesToSuperview(.all()) } } |
