Skip to content

Commit 19bb461

Browse files
author
Jon Petersson
committed
Add UI for saving a custom list
1 parent da4e1c2 commit 19bb461

File tree

5 files changed

+127
-0
lines changed

5 files changed

+127
-0
lines changed

ios/MullvadVPN.xcodeproj/project.pbxproj

+16
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,8 @@
464464
58FF9FF02B07C4D300E4C97D /* PersistentAccessMethod+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FF9FEF2B07C4D300E4C97D /* PersistentAccessMethod+ViewModel.swift */; };
465465
58FF9FF42B07C61B00E4C97D /* AccessMethodValidationError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FF9FF32B07C61B00E4C97D /* AccessMethodValidationError.swift */; };
466466
7A02D4EB2A9CEC7A00C19E31 /* MullvadVPNScreenshots.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = 7A02D4EA2A9CEC7A00C19E31 /* MullvadVPNScreenshots.xctestplan */; };
467+
7A038FD82B75033200950251 /* CustomListSaveAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A038FD72B75033200950251 /* CustomListSaveAlert.swift */; };
468+
7A038FDA2B7633A400950251 /* SUIAppButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A038FD92B7633A400950251 /* SUIAppButton.swift */; };
467469
7A09C98129D99215000C2CAC /* String+FuzzyMatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A09C98029D99215000C2CAC /* String+FuzzyMatch.swift */; };
468470
7A0B311E2B303A0D004B12E0 /* AccessbilityIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0B311D2B303A0D004B12E0 /* AccessbilityIdentifier.swift */; };
469471
7A0B311F2B303A11004B12E0 /* AccessbilityIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0B311D2B303A0D004B12E0 /* AccessbilityIdentifier.swift */; };
@@ -1660,6 +1662,8 @@
16601662
58FF9FEF2B07C4D300E4C97D /* PersistentAccessMethod+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PersistentAccessMethod+ViewModel.swift"; sourceTree = "<group>"; };
16611663
58FF9FF32B07C61B00E4C97D /* AccessMethodValidationError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessMethodValidationError.swift; sourceTree = "<group>"; };
16621664
7A02D4EA2A9CEC7A00C19E31 /* MullvadVPNScreenshots.xctestplan */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = MullvadVPNScreenshots.xctestplan; sourceTree = "<group>"; };
1665+
7A038FD72B75033200950251 /* CustomListSaveAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomListSaveAlert.swift; sourceTree = "<group>"; };
1666+
7A038FD92B7633A400950251 /* SUIAppButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SUIAppButton.swift; sourceTree = "<group>"; };
16631667
7A09C98029D99215000C2CAC /* String+FuzzyMatch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+FuzzyMatch.swift"; sourceTree = "<group>"; };
16641668
7A0B311D2B303A0D004B12E0 /* AccessbilityIdentifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccessbilityIdentifier.swift; sourceTree = "<group>"; };
16651669
7A0C0F622A979C4A0058EFCE /* Coordinator+Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Coordinator+Router.swift"; sourceTree = "<group>"; };
@@ -2282,6 +2286,7 @@
22822286
583FE01729C196F3006E85F9 /* SelectLocation */ = {
22832287
isa = PBXGroup;
22842288
children = (
2289+
7A038FD62B75031400950251 /* CustomLists */,
22852290
58435AC129CB2A350099C71B /* LocationCellFactory.swift */,
22862291
583DA21325FA4B5C00318683 /* LocationDataSource.swift */,
22872292
5888AD82227B11080051EB06 /* SelectLocationCell.swift */,
@@ -3306,6 +3311,15 @@
33063311
path = Edit;
33073312
sourceTree = "<group>";
33083313
};
3314+
7A038FD62B75031400950251 /* CustomLists */ = {
3315+
isa = PBXGroup;
3316+
children = (
3317+
7A038FD72B75033200950251 /* CustomListSaveAlert.swift */,
3318+
7A038FD92B7633A400950251 /* SUIAppButton.swift */,
3319+
);
3320+
path = CustomLists;
3321+
sourceTree = "<group>";
3322+
};
33093323
7A2960F72A964A3500389B82 /* Alert */ = {
33103324
isa = PBXGroup;
33113325
children = (
@@ -5023,6 +5037,7 @@
50235037
5827B0B02B0F4CCD00CCBBA1 /* ListAccessMethodViewControllerDelegate.swift in Sources */,
50245038
588D7EE02AF3A595005DF40A /* ListAccessMethodInteractor.swift in Sources */,
50255039
58607A4D2947287800BC467D /* AccountExpiryInAppNotificationProvider.swift in Sources */,
5040+
7A038FDA2B7633A400950251 /* SUIAppButton.swift in Sources */,
50265041
58C8191829FAA2C400DEB1B4 /* NotificationConfiguration.swift in Sources */,
50275042
58FF9FE82B07650A00E4C97D /* ButtonCellContentConfiguration.swift in Sources */,
50285043
5827B0A82B0F49EF00CCBBA1 /* ProxyConfigurationInteractorProtocol.swift in Sources */,
@@ -5129,6 +5144,7 @@
51295144
58EFC76E2AFB3BDA00E9F4CB /* ListAccessMethodCoordinator.swift in Sources */,
51305145
5827B0B92B14A1C700CCBBA1 /* MethodTestingStatusCellContentConfiguration.swift in Sources */,
51315146
7A42DEC92A05164100B209BE /* SettingsInputCell.swift in Sources */,
5147+
7A038FD82B75033200950251 /* CustomListSaveAlert.swift in Sources */,
51325148
5803B4B22940A48700C23744 /* TunnelStore.swift in Sources */,
51335149
586A950F29012BEE007BAF2B /* AddressCacheTracker.swift in Sources */,
51345150
587B753D2666468F00DEF7E9 /* NotificationController.swift in Sources */,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//
2+
// CustomListSaveAlert.swift
3+
// MullvadVPN
4+
//
5+
// Created by Jon Petersson on 2024-02-08.
6+
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
7+
//
8+
9+
import SwiftUI
10+
11+
class CustomListSaveAlertViewModel: ObservableObject {
12+
@Published var inputIsValid: Bool
13+
14+
init(inputIsValid: Bool = true) {
15+
self.inputIsValid = inputIsValid
16+
}
17+
}
18+
19+
struct CustomListSaveAlert: View {
20+
@State private var inputText = ""
21+
@ObservedObject var viewModel: CustomListSaveAlertViewModel
22+
23+
var didTapSave: ((String) -> Void)?
24+
var didTapCancel: (() -> Void)?
25+
26+
var body: some View {
27+
ZStack {
28+
VStack(alignment: .leading, spacing: 8) {
29+
Text("Edit list name")
30+
.font(.system(size: 12, weight: .semibold))
31+
.foregroundColor(.white.opacity(0.8))
32+
TextField("", text: $inputText)
33+
.textFieldStyle(CustomTextFieldStyle())
34+
ErrorLabel(inputIsValid: viewModel.inputIsValid)
35+
VStack(spacing: 16) {
36+
SUIAppButton(text: "Save", style: .success)
37+
.frame(height: 42)
38+
.onTapGesture { didTapSave?(inputText) }
39+
SUIAppButton(text: "Cancel", style: .default)
40+
.frame(height: 42)
41+
.onTapGesture { didTapCancel?() }
42+
}
43+
}
44+
.padding(EdgeInsets(UIMetrics.CustomAlert.containerMargins))
45+
.background(Color(.secondaryColor))
46+
.frame(width: 320)
47+
.cornerRadius(11)
48+
}
49+
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
50+
.background(Color.black.opacity(0.6))
51+
.ignoresSafeArea()
52+
}
53+
}
54+
55+
struct CustomListSaveAlert_Previews: PreviewProvider {
56+
static var previews: some View {
57+
CustomListSaveAlert(viewModel: CustomListSaveAlertViewModel(inputIsValid: true))
58+
CustomListSaveAlert(viewModel: CustomListSaveAlertViewModel(inputIsValid: false))
59+
}
60+
}
61+
62+
private struct CustomTextFieldStyle: TextFieldStyle {
63+
func _body(configuration: TextField<Self._Label>) -> some View {
64+
configuration
65+
.padding(EdgeInsets(top: 6, leading: 8, bottom: 6, trailing: 8))
66+
.background(Color.white)
67+
.cornerRadius(4)
68+
.font(.system(size: 15))
69+
}
70+
}
71+
72+
private struct ErrorLabel: View {
73+
let inputIsValid: Bool
74+
75+
var body: some View {
76+
Text("Name is already taken")
77+
.font(.system(size: 12, weight: .semibold))
78+
.foregroundColor(Color(.dangerColor))
79+
.padding(.bottom, inputIsValid ? 0 : 4)
80+
.opacity(inputIsValid ? 0 : 1)
81+
}
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// SUIAppButton.swift
3+
// MullvadVPN
4+
//
5+
// Created by Jon Petersson on 2024-02-09.
6+
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
7+
//
8+
9+
import MullvadTypes
10+
import SwiftUI
11+
12+
/// SwiftUI wrapper for ``AppButton``.
13+
struct SUIAppButton: UIViewRepresentable {
14+
let text: String
15+
let style: AppButton.Style
16+
17+
func makeUIView(context: Context) -> AppButton {
18+
let button = AppButton(style: style)
19+
button.setTitle(text, for: .normal)
20+
21+
return button
22+
}
23+
24+
func updateUIView(_ appButton: AppButton, context: Context) {}
25+
}

ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import MullvadLogging
1111
import MullvadTypes
1212
import UIKit
1313

14+
import SwiftUI
15+
1416
class TunnelViewController: UIViewController, RootContainment {
1517
private let logger = Logger(label: "TunnelViewController")
1618
private let interactor: TunnelViewControllerInteractor

ios/build-wireguard-go.sh

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ if [ "$SOURCE_PACKAGES_PATH" == "" ]; then
2121
# When archiving, Xcode sets the action to "install"
2222
if [ "$ACTION" == "install" ]; then
2323
SOURCE_PACKAGES_PATH="$BUILD_DIR/../../../../../SourcePackages"
24+
elif [ "$ENABLE_PREVIEWS" == "YES" ]; then
25+
SOURCE_PACKAGES_PATH="$BUILD_DIR/../../../../../SourcePackages"
2426
else
2527
SOURCE_PACKAGES_PATH="$BUILD_DIR/../../SourcePackages"
2628
fi

0 commit comments

Comments
 (0)