Skip to content

Commit

Permalink
Add state to new connection view
Browse files Browse the repository at this point in the history
  • Loading branch information
rablador committed Dec 13, 2024
1 parent 9573f3e commit c61b7d4
Show file tree
Hide file tree
Showing 15 changed files with 661 additions and 117 deletions.
29 changes: 29 additions & 0 deletions ios/MullvadVPN.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,9 @@
7A0C0F632A979C4A0058EFCE /* Coordinator+Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0C0F622A979C4A0058EFCE /* Coordinator+Router.swift */; };
7A0EAE9A2D01B41500D3EB8B /* MainButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0EAE992D01B41500D3EB8B /* MainButtonStyle.swift */; };
7A0EAE9E2D01BCBF00D3EB8B /* View+Size.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0EAE9D2D01BCBF00D3EB8B /* View+Size.swift */; };
7A0EAEA02D0333CE00D3EB8B /* Color+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0EAE9F2D0333CB00D3EB8B /* Color+Helpers.swift */; };
7A0EAEA22D033D5D00D3EB8B /* BlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0EAEA12D033D5A00D3EB8B /* BlurView.swift */; };
7A0EAEA42D06DF8C00D3EB8B /* ConnectionViewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0EAEA32D06DF8200D3EB8B /* ConnectionViewViewModel.swift */; };
7A11DD0B2A9495D400098CD8 /* AppRoutes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5802EBC42A8E44AC00E5CE4C /* AppRoutes.swift */; };
7A12D0762B062D5C00E9602D /* URLSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A12D0752B062D5C00E9602D /* URLSessionProtocol.swift */; };
7A12D0772B062D6500E9602D /* URLSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A12D0752B062D5C00E9602D /* URLSessionProtocol.swift */; };
Expand Down Expand Up @@ -658,6 +661,8 @@
7AF9BE972A41C71F00DBFEDB /* ChipViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF9BE962A41C71F00DBFEDB /* ChipViewCell.swift */; };
7AFBE38B2D09AAFF002335FC /* SinglehopPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AFBE38A2D09AAFF002335FC /* SinglehopPicker.swift */; };
7AFBE38D2D09AB2E002335FC /* MultihopPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AFBE38C2D09AB2E002335FC /* MultihopPicker.swift */; };
7AFBE3872D084C9D002335FC /* ActivityIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AFBE3862D084C96002335FC /* ActivityIndicator.swift */; };
7AFBE3892D089163002335FC /* FI_TunnelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AFBE3882D08915D002335FC /* FI_TunnelViewController.swift */; };
850201DB2B503D7700EF8C96 /* RelayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850201DA2B503D7700EF8C96 /* RelayTests.swift */; };
850201DD2B503D8C00EF8C96 /* SelectLocationPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850201DC2B503D8C00EF8C96 /* SelectLocationPage.swift */; };
850201DF2B5040A500EF8C96 /* TunnelControlPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850201DE2B5040A500EF8C96 /* TunnelControlPage.swift */; };
Expand Down Expand Up @@ -1843,6 +1848,9 @@
7A0C0F622A979C4A0058EFCE /* Coordinator+Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Coordinator+Router.swift"; sourceTree = "<group>"; };
7A0EAE992D01B41500D3EB8B /* MainButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainButtonStyle.swift; sourceTree = "<group>"; };
7A0EAE9D2D01BCBF00D3EB8B /* View+Size.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Size.swift"; sourceTree = "<group>"; };
7A0EAE9F2D0333CB00D3EB8B /* Color+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Helpers.swift"; sourceTree = "<group>"; };
7A0EAEA12D033D5A00D3EB8B /* BlurView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurView.swift; sourceTree = "<group>"; };
7A0EAEA32D06DF8200D3EB8B /* ConnectionViewViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionViewViewModel.swift; sourceTree = "<group>"; };
7A12D0752B062D5C00E9602D /* URLSessionProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLSessionProtocol.swift; sourceTree = "<group>"; };
7A1A26422A2612AE00B978AA /* PaymentAlertPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentAlertPresenter.swift; sourceTree = "<group>"; };
7A1A26442A29CEF700B978AA /* RelayFilterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayFilterViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2014,6 +2022,8 @@
7AF9BE962A41C71F00DBFEDB /* ChipViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChipViewCell.swift; sourceTree = "<group>"; };
7AFBE38A2D09AAFF002335FC /* SinglehopPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SinglehopPicker.swift; sourceTree = "<group>"; };
7AFBE38C2D09AB2E002335FC /* MultihopPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultihopPicker.swift; sourceTree = "<group>"; };
7AFBE3862D084C96002335FC /* ActivityIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityIndicator.swift; sourceTree = "<group>"; };
7AFBE3882D08915D002335FC /* FI_TunnelViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FI_TunnelViewController.swift; sourceTree = "<group>"; };
85006A8E2B73EF67004AD8FB /* MullvadVPNUITestsSmoke.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = MullvadVPNUITestsSmoke.xctestplan; sourceTree = "<group>"; };
850201DA2B503D7700EF8C96 /* RelayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayTests.swift; sourceTree = "<group>"; };
850201DC2B503D8C00EF8C96 /* SelectLocationPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectLocationPage.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3015,6 +3025,7 @@
isa = PBXGroup;
children = (
7A5869962B32EA4500640D27 /* AppButton.swift */,
7A0EAEA12D033D5A00D3EB8B /* BlurView.swift */,
7A9FA1412A2E3306000B728D /* CheckboxView.swift */,
5868585424054096000B8131 /* CustomButton.swift */,
58ACF64C26567A4F00ACE4B7 /* CustomSwitch.swift */,
Expand Down Expand Up @@ -3085,6 +3096,7 @@
587EB669270EFACB00123C75 /* CharacterSet+IPAddress.swift */,
58E511E528DDDEAC00B0BCDE /* CodingErrors+CustomErrorDescription.swift */,
7AF9BE8F2A39F26000DBFEDB /* Collection+Sorting.swift */,
7A0EAE9F2D0333CB00D3EB8B /* Color+Helpers.swift */,
7A0C0F622A979C4A0058EFCE /* Coordinator+Router.swift */,
5811DE4F239014550011EB53 /* NEVPNStatus+Debug.swift */,
58DFF7CF2B02560400F864E0 /* NSAttributedString+Extensions.swift */,
Expand Down Expand Up @@ -3612,6 +3624,7 @@
A9D9A4C12C36D53C004088DD /* MullvadRustRuntimeTests */,
58CE5E61224146200008646E /* Products */,
584F991F2902CBDD001F858D /* Frameworks */,
7A0EAE982D01B29E00D3EB8B /* Recovered References */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -3912,6 +3925,14 @@
path = Edit;
sourceTree = "<group>";
};
7A0EAE982D01B29E00D3EB8B /* Recovered References */ = {
isa = PBXGroup;
children = (
7AA1309C2D0072F900640DF9 /* View+Size.swift */,
);
name = "Recovered References";
sourceTree = "<group>";
};
7A2960F72A964A3500389B82 /* Alert */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -4046,7 +4067,10 @@
7AA130972CFF364F00640DF9 /* FeatureIndicators */ = {
isa = PBXGroup;
children = (
7AFBE3862D084C96002335FC /* ActivityIndicator.swift */,
7AA130982CFF365A00640DF9 /* ConnectionView.swift */,
7A0EAEA32D06DF8200D3EB8B /* ConnectionViewViewModel.swift */,
7AFBE3882D08915D002335FC /* FI_TunnelViewController.swift */,
);
path = FeatureIndicators;
sourceTree = "<group>";
Expand Down Expand Up @@ -5817,6 +5841,7 @@
F0ADC3742CD3C47400A1AD97 /* ChipFlowLayout.swift in Sources */,
587B75412668FD7800DEF7E9 /* AccountExpirySystemNotificationProvider.swift in Sources */,
587988C728A2A01F00E3DF54 /* AccountDataThrottling.swift in Sources */,
7AFBE3872D084C9D002335FC /* ActivityIndicator.swift in Sources */,
F04FBE612A8379EE009278D7 /* AppPreferences.swift in Sources */,
58DFF7D82B02774C00F864E0 /* ListItemPickerViewController.swift in Sources */,
5896CEF226972DEB00B0FAE8 /* AccountContentView.swift in Sources */,
Expand All @@ -5838,6 +5863,7 @@
7A8A19142CEF2548000BCB5B /* DAITATunnelSettingsViewModel.swift in Sources */,
7A8A18F92CE34EA8000BCB5B /* SettingsMultihopView.swift in Sources */,
44BB5F972BE527F4002520EB /* TunnelState+UI.swift in Sources */,
7AFBE3892D089163002335FC /* FI_TunnelViewController.swift in Sources */,
7A11DD0B2A9495D400098CD8 /* AppRoutes.swift in Sources */,
5827B0902B0CAA0500CCBBA1 /* EditAccessMethodCoordinator.swift in Sources */,
5846227126E229F20035F7C2 /* StoreSubscription.swift in Sources */,
Expand Down Expand Up @@ -5872,6 +5898,7 @@
7AA1309B2D0048D800640DF9 /* MainButton.swift in Sources */,
58A1AA8C23F5584C009F7EA6 /* ConnectionPanelView.swift in Sources */,
5878A27B2909649A0096FC88 /* CustomOverlayRenderer.swift in Sources */,
7A0EAEA02D0333CE00D3EB8B /* Color+Helpers.swift in Sources */,
7A8A19052CE4E9A9000BCB5B /* SwitchRowView.swift in Sources */,
A91614D62B10B26B00F416EB /* TunnelControlViewModel.swift in Sources */,
7A5869972B32EA4500640D27 /* AppButton.swift in Sources */,
Expand Down Expand Up @@ -6061,6 +6088,8 @@
7A6F2FA92AFD0842006D0856 /* CustomDNSDataSource.swift in Sources */,
58EF580B25D69D7A00AEBA94 /* ProblemReportSubmissionOverlayView.swift in Sources */,
5892A45E265FABFF00890742 /* EmptyTableViewHeaderFooterView.swift in Sources */,
7A0EAEA42D06DF8C00D3EB8B /* ConnectionViewViewModel.swift in Sources */,
7A0EAEA22D033D5D00D3EB8B /* BlurView.swift in Sources */,
580909D32876D09A0078138D /* RevokedDeviceViewController.swift in Sources */,
58FF9FF02B07C4D300E4C97D /* PersistentAccessMethod+ViewModel.swift in Sources */,
7A8A19162CEF269E000BCB5B /* MultihopTunnelSettingsViewModel.swift in Sources */,
Expand Down
10 changes: 10 additions & 0 deletions ios/MullvadVPN/Coordinators/TunnelCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ import UIKit

class TunnelCoordinator: Coordinator, Presenting {
private let tunnelManager: TunnelManager

#if DEBUG
private let controller: FI_TunnelViewController
#else
private let controller: TunnelViewController
#endif

private var tunnelObserver: TunnelObserver?

Expand All @@ -35,7 +40,12 @@ class TunnelCoordinator: Coordinator, Presenting {
tunnelManager: tunnelManager,
outgoingConnectionService: outgoingConnectionService
)

#if DEBUG
controller = FI_TunnelViewController(interactor: interactor)
#else
controller = TunnelViewController(interactor: interactor)
#endif

super.init()

Expand Down
16 changes: 16 additions & 0 deletions ios/MullvadVPN/Extensions/Color+Helpers.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// Color.swift
// MullvadVPN
//
// Created by Jon Petersson on 2024-12-06.
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
//

import SwiftUI

extension Color {
/// Returns the color darker by the given percent (in range from 0..1)
func darkened(by percent: CGFloat) -> Color? {
UIColor(self).darkened(by: percent)?.color
}
}
97 changes: 75 additions & 22 deletions ios/MullvadVPN/TunnelManager/TunnelState+UI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@
import UIKit

extension TunnelState {
enum TunnelControlActionButton {
case connect
case disconnect
case cancel
}

var textColorForSecureLabel: UIColor {
switch self {
case .connecting, .reconnecting, .waitingForConnectivity(.noConnection), .negotiatingEphemeralPeer:
.white

case .connected:
.successColor

case .disconnecting, .disconnected, .pendingReconnect, .waitingForConnectivity(.noNetwork), .error:
.dangerColor
}
Expand Down Expand Up @@ -65,6 +69,7 @@ extension TunnelState {
comment: ""
)
}

case let .connected(_, isPostQuantum, _):
if isPostQuantum {
NSLocalizedString(
Expand All @@ -77,7 +82,7 @@ extension TunnelState {
NSLocalizedString(
"TUNNEL_STATE_CONNECTED",
tableName: "Main",
value: "Secure connection",
value: "Connected",
comment: ""
)
}
Expand All @@ -89,6 +94,7 @@ extension TunnelState {
value: "Disconnecting",
comment: ""
)

case .disconnecting(.reconnect), .pendingReconnect:
NSLocalizedString(
"TUNNEL_STATE_PENDING_RECONNECT",
Expand Down Expand Up @@ -123,7 +129,7 @@ extension TunnelState {
}
}

var localizedTitleForSelectLocationButton: String? {
var localizedTitleForSelectLocationButton: String {
switch self {
case .disconnecting(.reconnect), .pendingReconnect:
NSLocalizedString(
Expand Down Expand Up @@ -159,24 +165,6 @@ extension TunnelState {
}
}

func secureConnectionLabel(isPostQuantum: Bool) -> String {
if isPostQuantum {
NSLocalizedString(
"TUNNEL_STATE_PQ_CONNECTING_ACCESSIBILITY_LABEL",
tableName: "Main",
value: "Creating quantum secure connection",
comment: ""
)
} else {
NSLocalizedString(
"TUNNEL_STATE_CONNECTING_ACCESSIBILITY_LABEL",
tableName: "Main",
value: "Creating secure connection",
comment: ""
)
}
}

var localizedAccessibilityLabel: String {
switch self {
case let .connecting(_, isPostQuantum, _):
Expand Down Expand Up @@ -263,4 +251,69 @@ extension TunnelState {
)
}
}

var actionButton: TunnelControlActionButton {
switch self {
case .disconnected, .disconnecting(.nothing), .waitingForConnectivity(.noNetwork):
.connect
case .connecting, .pendingReconnect, .disconnecting(.reconnect), .waitingForConnectivity(.noConnection):
.cancel
case .negotiatingEphemeralPeer:
.cancel
case .connected, .reconnecting, .error:
.disconnect
}
}

var titleForCountryAndCity: String? {
guard isSecured, let tunnelRelays = relays else {
return nil
}

return "\(tunnelRelays.exit.location.country), \(tunnelRelays.exit.location.city)"
}

func titleForServer(daitaEnabled: Bool) -> String? {
guard isSecured, let tunnelRelays = relays else {
return nil
}

let exitName = tunnelRelays.exit.hostname
let entryName = tunnelRelays.entry?.hostname
let usingDaita = daitaEnabled == true

return if let entryName {
String(format: NSLocalizedString(
"CONNECT_PANEL_TITLE",
tableName: "Main",
value: "%@ via %@\(usingDaita ? " using DAITA" : "")",
comment: ""
), exitName, entryName)
} else {
String(format: NSLocalizedString(
"CONNECT_PANEL_TITLE",
tableName: "Main",
value: "%@\(usingDaita ? " using DAITA" : "")",
comment: ""
), exitName)
}
}

func secureConnectionLabel(isPostQuantum: Bool) -> String {
if isPostQuantum {
NSLocalizedString(
"TUNNEL_STATE_PQ_CONNECTING_ACCESSIBILITY_LABEL",
tableName: "Main",
value: "Creating quantum secure connection",
comment: ""
)
} else {
NSLocalizedString(
"TUNNEL_STATE_CONNECTING_ACCESSIBILITY_LABEL",
tableName: "Main",
value: "Creating secure connection",
comment: ""
)
}
}
}
16 changes: 8 additions & 8 deletions ios/MullvadVPN/TunnelManager/TunnelState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ enum TunnelState: Equatable, CustomStringConvertible {
case let .connecting(tunnelRelays, isPostQuantum, isDaita):
if let tunnelRelays {
"""
connecting \(isPostQuantum ? "(PQ) " : "")\
daita: \(isDaita) \
connecting \(isPostQuantum ? "(PQ) " : ""), \
daita: \(isDaita), \
to \(tunnelRelays.exit.hostname)\
\(tunnelRelays.entry.flatMap { " via \($0.hostname)" } ?? "")
"""
Expand All @@ -94,8 +94,8 @@ enum TunnelState: Equatable, CustomStringConvertible {
}
case let .connected(tunnelRelays, isPostQuantum, isDaita):
"""
connected \(isPostQuantum ? "(PQ) " : "")\
daita: \(isDaita) \
connected \(isPostQuantum ? "(PQ) " : ""), \
daita: \(isDaita), \
to \(tunnelRelays.exit.hostname)\
\(tunnelRelays.entry.flatMap { " via \($0.hostname)" } ?? "")
"""
Expand All @@ -105,8 +105,8 @@ enum TunnelState: Equatable, CustomStringConvertible {
"disconnected"
case let .reconnecting(tunnelRelays, isPostQuantum, isDaita):
"""
reconnecting \(isPostQuantum ? "(PQ) " : "")\
daita: \(isDaita) \
reconnecting \(isPostQuantum ? "(PQ) " : ""), \
daita: \(isDaita), \
to \(tunnelRelays.exit.hostname)\
\(tunnelRelays.entry.flatMap { " via \($0.hostname)" } ?? "")
"""
Expand All @@ -117,8 +117,8 @@ enum TunnelState: Equatable, CustomStringConvertible {
case let .negotiatingEphemeralPeer(tunnelRelays, _, isPostQuantum, isDaita):
"""
negotiating key with exit relay: \(tunnelRelays.exit.hostname)\
\(tunnelRelays.entry.flatMap { " via \($0.hostname)" } ?? "")\
, isPostQuantum: \(isPostQuantum), isDaita: \(isDaita)
\(tunnelRelays.entry.flatMap { " via \($0.hostname)" } ?? ""), \
isPostQuantum: \(isPostQuantum), isDaita: \(isDaita)
"""
}
}
Expand Down
Loading

0 comments on commit c61b7d4

Please sign in to comment.