-
Notifications
You must be signed in to change notification settings - Fork 349
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement SwiftUI UI for UDP TCP Obfuscation port selector view
- Loading branch information
Showing
12 changed files
with
275 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
... controllers/Settings/Obfuscation/TunnelObfuscationSettingsWatchingObservableObject.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// | ||
// TunnelObfuscationSettingsWatchingObservableObject.swift | ||
// MullvadVPN | ||
// | ||
// Created by Andrew Bulhak on 2024-11-07. | ||
// Copyright © 2024 Mullvad VPN AB. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import MullvadSettings | ||
|
||
/// a generic ObservableObject that binds to obfuscation settings in TunnelManager. | ||
/// Used as the basis for ViewModels for SwiftUI interfaces for these settings. | ||
|
||
class TunnelObfuscationSettingsWatchingObservableObject<T: Equatable>: ObservableObject { | ||
let tunnelManager: TunnelManager | ||
let keyPath: WritableKeyPath<WireGuardObfuscationSettings, T> | ||
private var tunnelObserver: TunnelObserver? | ||
|
||
// this is essentially @Published from scratch | ||
var value: T { | ||
willSet(newValue) { | ||
guard newValue != self.value else { return } | ||
objectWillChange.send() | ||
var obfuscationSettings = tunnelManager.settings.wireGuardObfuscation | ||
obfuscationSettings[keyPath: keyPath] = newValue | ||
} | ||
} | ||
|
||
init(tunnelManager: TunnelManager, keyPath: WritableKeyPath<WireGuardObfuscationSettings, T>, _ initialValue: T) { | ||
self.tunnelManager = tunnelManager | ||
self.keyPath = keyPath | ||
self.value = initialValue | ||
tunnelObserver = | ||
TunnelBlockObserver(didUpdateTunnelSettings: { [weak self] _, newSettings in | ||
guard let self else { return } | ||
updateValueFromSettings(newSettings.wireGuardObfuscation) | ||
}) | ||
} | ||
|
||
private func updateValueFromSettings(_ settings: WireGuardObfuscationSettings) { | ||
let newValue = settings | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
ios/MullvadVPN/View controllers/Settings/Obfuscation/UDPTCPObfuscationSettingsView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// | ||
// UDPTCPObfuscationSettingsView.swift | ||
// MullvadVPN | ||
// | ||
// Created by Andrew Bulhak on 2024-10-28. | ||
// Copyright © 2024 Mullvad VPN AB. All rights reserved. | ||
// | ||
|
||
import MullvadSettings | ||
import SwiftUI | ||
|
||
struct UDPTCPObfuscationSettingsView<VM>: View where VM: UDPTCPObfuscationSettingsViewModel { | ||
@StateObject var viewModel: VM | ||
|
||
var body: some View { | ||
SingleChoiceList( | ||
title: "Port", | ||
options: [WireGuardObfuscationUdpOverTcpPort.automatic, .port80, .port5001], | ||
value: $viewModel.value | ||
) | ||
} | ||
} | ||
|
||
#Preview { | ||
var model = MockUDPTCPObfuscationSettingsViewModel(udpTcpPort: .port5001) | ||
return UDPTCPObfuscationSettingsView(viewModel: model) | ||
} |
37 changes: 37 additions & 0 deletions
37
...MullvadVPN/View controllers/Settings/Obfuscation/UDPTCPObfuscationSettingsViewModel.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// | ||
// UDPTCPObfuscationSettingsViewModel.swift | ||
// MullvadVPN | ||
// | ||
// Created by Andrew Bulhak on 2024-11-05. | ||
// Copyright © 2024 Mullvad VPN AB. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import MullvadSettings | ||
|
||
protocol UDPTCPObfuscationSettingsViewModel: ObservableObject { | ||
var value: WireGuardObfuscationUdpOverTcpPort { get set } | ||
} | ||
|
||
/** A simple mock view model for use in Previews and similar */ | ||
class MockUDPTCPObfuscationSettingsViewModel: UDPTCPObfuscationSettingsViewModel { | ||
@Published var value: WireGuardObfuscationUdpOverTcpPort | ||
|
||
init(udpTcpPort: WireGuardObfuscationUdpOverTcpPort = .automatic) { | ||
self.value = udpTcpPort | ||
} | ||
} | ||
|
||
/** The live view model which interfaces with the TunnelManager */ | ||
class TunnelUDPTCPObfuscationSettingsViewModel: TunnelObfuscationSettingsWatchingObservableObject< | ||
WireGuardObfuscationUdpOverTcpPort | ||
>, | ||
UDPTCPObfuscationSettingsViewModel { | ||
init(tunnelManager: TunnelManager) { | ||
super.init( | ||
tunnelManager: tunnelManager, | ||
keyPath: \.udpOverTcpPort, | ||
.automatic | ||
) | ||
} | ||
} |
55 changes: 55 additions & 0 deletions
55
ios/MullvadVPN/View controllers/Settings/SwiftUI components/SingleChoiceList.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// | ||
// SingleChoiceList.swift | ||
// MullvadVPN | ||
// | ||
// Created by Andrew Bulhak on 2024-11-06. | ||
// Copyright © 2024 Mullvad VPN AB. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
|
||
/** | ||
A component presenting a vertical list in the Mullvad style for selecting a single item from a list. | ||
The items can be any Hashable type. | ||
*/ | ||
|
||
struct SingleChoiceList<T>: View where T: Hashable { | ||
let title: String | ||
let options: [T] | ||
var value: Binding<T> | ||
|
||
func row(_ v: T) -> some View { | ||
let isSelected = value.wrappedValue == v | ||
return HStack { | ||
Image("IconTick").opacity(isSelected ? 1.0 : 0.0) | ||
Text(verbatim: "\(v)") | ||
Spacer() | ||
} | ||
.padding(16) | ||
.background(isSelected ? Color(UIColor.Cell.Background.selected) : Color(UIColor.Cell.Background.normal)) | ||
.foregroundColor(Color(UIColor.Cell.titleTextColor)) | ||
.onTapGesture { | ||
value.wrappedValue = v | ||
} | ||
} | ||
|
||
var body: some View { | ||
VStack(spacing: 0) { | ||
HStack { | ||
Text(title) | ||
Spacer() | ||
} | ||
.padding(16) | ||
ForEach(options, id: \.self) { opt in | ||
row(opt) | ||
} | ||
Spacer() | ||
} | ||
.background(Color(.secondaryColor)) | ||
.foregroundColor(Color(.primaryTextColor)) | ||
} | ||
} | ||
|
||
#Preview { | ||
StatefulPreviewWrapper(1) { SingleChoiceList(title: "Test", options: [1, 2, 3], value: $0) } | ||
} |
35 changes: 35 additions & 0 deletions
35
ios/MullvadVPN/View controllers/Settings/SwiftUI components/StatefulPreviewWrapper.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// | ||
// StatefulPreviewWrapper.swift | ||
// MullvadVPN | ||
// | ||
// Created by Andrew Bulhak on 2024-11-06. | ||
// Copyright © 2024 Mullvad VPN AB. All rights reserved. | ||
// | ||
|
||
// This should probably live somewhere more central than `View controllers/Settings/SwiftUI components`. Where exactly is to be determined. | ||
|
||
import SwiftUI | ||
|
||
/** A wrapper for providing a state binding for SwiftUI Views in #Preview. This takes as arguments an initial value for the binding and a block which accepts the binding and returns a View to be previewed | ||
The usage looks like: | ||
|
||
``` | ||
#Preview { | ||
StatefulPreviewWrapper(initvalue) { ComponentToBePreviewed(binding: $0) } | ||
} | ||
``` | ||
*/ | ||
|
||
struct StatefulPreviewWrapper<Value, Content: View>: View { | ||
@State var value: Value | ||
var content: (Binding<Value>) -> Content | ||
|
||
var body: some View { | ||
content($value) | ||
} | ||
|
||
init(_ value: Value, content: @escaping (Binding<Value>) -> Content) { | ||
self._value = State(wrappedValue: value) | ||
self.content = content | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.