summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorBug Magnet <marco.nikic@mullvad.net>2025-01-16 15:25:58 +0100
committerBug Magnet <marco.nikic@mullvad.net>2025-01-20 08:49:28 +0100
commit1482b26664c6450dd33eeac5e1d18788cbc0d4a3 (patch)
tree449c94c071bda8ee4bd0d7dfd735773862932dc8
parent5b3b433809f9fcadba1cc12d616a3edc67592356 (diff)
downloadmullvadvpn-1482b26664c6450dd33eeac5e1d18788cbc0d4a3.tar.xz
mullvadvpn-1482b26664c6450dd33eeac5e1d18788cbc0d4a3.zip
Move the Progress view away from the ConnectionView
-rw-r--r--ios/MullvadVPN/View controllers/Tunnel/ActivityIndicator.swift12
-rw-r--r--ios/MullvadVPN/View controllers/Tunnel/ConnectionView/ConnectionView.swift3
-rw-r--r--ios/MullvadVPN/View controllers/Tunnel/FeatureIndicators/FI_TunnelViewController.swift221
-rw-r--r--ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift23
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())
}
}