Skip to content

Commit d143b39

Browse files
author
Jon Petersson
committed
Create view with custom lists to edit
1 parent 1b1fd65 commit d143b39

14 files changed

+417
-76
lines changed

ios/MullvadSettings/CustomListRepository.swift

+7-17
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,17 @@ public struct CustomListRepository: CustomListRepositoryProtocol {
4141

4242
public init() {}
4343

44-
public func create(_ name: String, locations: [RelayLocation]) throws -> CustomList {
44+
public func save(list: CustomList) throws {
4545
var lists = fetchAll()
46-
if lists.contains(where: { $0.name == name }) {
46+
47+
if let index = lists.firstIndex(where: { $0.id == list.id }) {
48+
lists[index] = list
49+
try write(lists)
50+
} else if lists.contains(where: { $0.name == list.name }) {
4751
throw CustomRelayListError.duplicateName
4852
} else {
49-
let item = CustomList(id: UUID(), name: name, locations: locations)
50-
lists.append(item)
53+
lists.append(list)
5154
try write(lists)
52-
return item
5355
}
5456
}
5557

@@ -72,18 +74,6 @@ public struct CustomListRepository: CustomListRepositoryProtocol {
7274
public func fetchAll() -> [CustomList] {
7375
(try? read()) ?? []
7476
}
75-
76-
public func update(_ list: CustomList) {
77-
do {
78-
var lists = fetchAll()
79-
if let index = lists.firstIndex(where: { $0.id == list.id }) {
80-
lists[index] = list
81-
try write(lists)
82-
}
83-
} catch {
84-
logger.error(error: error)
85-
}
86-
}
8777
}
8878

8979
extension CustomListRepository {

ios/MullvadSettings/CustomListRepositoryProtocol.swift

+3-9
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ public protocol CustomListRepositoryProtocol {
1313
/// Publisher that propagates a snapshot of persistent store upon modifications.
1414
var publisher: AnyPublisher<[CustomList], Never> { get }
1515

16-
/// Persist modified custom list locating existing entry by id.
17-
/// - Parameter list: persistent custom list model.
18-
func update(_ list: CustomList)
16+
/// Save a custom list. If the list doesn't already exist, it must have a unique name.
17+
/// - Parameter list: a custom list.
18+
func save(list: CustomList) throws
1919

2020
/// Delete custom list by id.
2121
/// - Parameter id: an access method id.
@@ -26,12 +26,6 @@ public protocol CustomListRepositoryProtocol {
2626
/// - Returns: a persistent custom list model upon success, otherwise `nil`.
2727
func fetch(by id: UUID) -> CustomList?
2828

29-
/// Create a custom list by unique name.
30-
/// - Parameter name: a custom list name.
31-
/// - Parameter locations: locations in a custom list.
32-
/// - Returns: a persistent custom list model upon success, otherwise throws `Error`.
33-
func create(_ name: String, locations: [RelayLocation]) throws -> CustomList
34-
3529
/// Fetch all custom list.
3630
/// - Returns: all custom list model .
3731
func fetchAll() -> [CustomList]

ios/MullvadVPN.xcodeproj/project.pbxproj

+8
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,8 @@
595595
7ADCB2D82B6A6EB300C88F89 /* AnyRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADCB2D72B6A6EB300C88F89 /* AnyRelay.swift */; };
596596
7ADCB2DA2B6A730400C88F89 /* IPOverrideRepositoryStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADCB2D92B6A730400C88F89 /* IPOverrideRepositoryStub.swift */; };
597597
7AE044BB2A935726003915D8 /* Routing.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A88DCD02A8FABBE00D2FF0E /* Routing.h */; settings = {ATTRIBUTES = (Public, ); }; };
598+
7AE7E81D2B985EB000E66F4E /* ListCustomListCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE7E81C2B985EB000E66F4E /* ListCustomListCoordinator.swift */; };
599+
7AE7E81F2B98637B00E66F4E /* ListCustomListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE7E81E2B98637B00E66F4E /* ListCustomListViewController.swift */; };
598600
7AEF7F1A2AD00F52006FE45D /* AppMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEF7F192AD00F52006FE45D /* AppMessageHandler.swift */; };
599601
7AF10EB22ADE859200C090B9 /* AlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF10EB12ADE859200C090B9 /* AlertViewController.swift */; };
600602
7AF10EB42ADE85BC00C090B9 /* RelayFilterCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF10EB32ADE85BC00C090B9 /* RelayFilterCoordinator.swift */; };
@@ -1821,6 +1823,8 @@
18211823
7AD0AA202AD6CB0000119E10 /* URLRequestProxyStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLRequestProxyStub.swift; sourceTree = "<group>"; };
18221824
7ADCB2D72B6A6EB300C88F89 /* AnyRelay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyRelay.swift; sourceTree = "<group>"; };
18231825
7ADCB2D92B6A730400C88F89 /* IPOverrideRepositoryStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPOverrideRepositoryStub.swift; sourceTree = "<group>"; };
1826+
7AE7E81C2B985EB000E66F4E /* ListCustomListCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListCustomListCoordinator.swift; sourceTree = "<group>"; };
1827+
7AE7E81E2B98637B00E66F4E /* ListCustomListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListCustomListViewController.swift; sourceTree = "<group>"; };
18241828
7AEF7F192AD00F52006FE45D /* AppMessageHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppMessageHandler.swift; sourceTree = "<group>"; };
18251829
7AF10EB12ADE859200C090B9 /* AlertViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertViewController.swift; sourceTree = "<group>"; };
18261830
7AF10EB32ADE85BC00C090B9 /* RelayFilterCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RelayFilterCoordinator.swift; sourceTree = "<group>"; };
@@ -3468,6 +3472,8 @@
34683472
7A6389E62B7E42BE008E77E1 /* CustomListViewController.swift */,
34693473
7A6389D32B7E3BD6008E77E1 /* CustomListViewModel.swift */,
34703474
7A6389E42B7E4247008E77E1 /* EditCustomListCoordinator.swift */,
3475+
7AE7E81C2B985EB000E66F4E /* ListCustomListCoordinator.swift */,
3476+
7AE7E81E2B98637B00E66F4E /* ListCustomListViewController.swift */,
34713477
);
34723478
path = CustomLists;
34733479
sourceTree = "<group>";
@@ -5240,6 +5246,7 @@
52405246
58CE5E66224146200008646E /* LoginViewController.swift in Sources */,
52415247
F0C6FA852A6A733700F521F0 /* InAppPurchaseInteractor.swift in Sources */,
52425248
58CEB2F92AFD136E00E6E088 /* UIBackgroundConfiguration+Extensions.swift in Sources */,
5249+
7AE7E81D2B985EB000E66F4E /* ListCustomListCoordinator.swift in Sources */,
52435250
5878F50029CDA742003D4BE2 /* UIView+AutoLayoutBuilder.swift in Sources */,
52445251
A98502032B627B120061901E /* LocalNetworkProbe.swift in Sources */,
52455252
583FE01029C0F532006E85F9 /* CustomSplitViewController.swift in Sources */,
@@ -5313,6 +5320,7 @@
53135320
58CCA01E2242787B004F3011 /* AccountTextField.swift in Sources */,
53145321
586E54FB27A2DF6D0029B88B /* SendTunnelProviderMessageOperation.swift in Sources */,
53155322
584592612639B4A200EF967F /* TermsOfServiceContentView.swift in Sources */,
5323+
7AE7E81F2B98637B00E66F4E /* ListCustomListViewController.swift in Sources */,
53165324
5875960A26F371FC00BF6711 /* Tunnel+Messaging.swift in Sources */,
53175325
586C0D912B03D8A400E7CDD7 /* AccessMethodHeaderFooterReuseIdentifier.swift in Sources */,
53185326
7A2960F62A963F7500389B82 /* AlertCoordinator.swift in Sources */,

ios/MullvadVPN/Coordinators/CustomLists/AddCustomListCoordinator.swift

+11-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import UIKit
1313

1414
class AddCustomListCoordinator: Coordinator, Presentable, Presenting {
1515
let navigationController: UINavigationController
16-
let customListInteractor: CustomListInteractorProtocol
16+
let interactor: CustomListInteractorProtocol
1717

1818
var presentedViewController: UIViewController {
1919
navigationController
@@ -23,10 +23,10 @@ class AddCustomListCoordinator: Coordinator, Presentable, Presenting {
2323

2424
init(
2525
navigationController: UINavigationController,
26-
customListInteractor: CustomListInteractorProtocol
26+
interactor: CustomListInteractorProtocol
2727
) {
2828
self.navigationController = navigationController
29-
self.customListInteractor = customListInteractor
29+
self.interactor = interactor
3030
}
3131

3232
func start() {
@@ -35,7 +35,7 @@ class AddCustomListCoordinator: Coordinator, Presentable, Presenting {
3535
)
3636

3737
let controller = CustomListViewController(
38-
interactor: customListInteractor,
38+
interactor: interactor,
3939
subject: subject,
4040
alertPresenter: AlertPresenter(context: self)
4141
)
@@ -55,6 +55,13 @@ class AddCustomListCoordinator: Coordinator, Presentable, Presenting {
5555
comment: ""
5656
)
5757

58+
controller.navigationItem.leftBarButtonItem = UIBarButtonItem(
59+
systemItem: .cancel,
60+
primaryAction: UIAction(handler: { _ in
61+
self.didFinish?()
62+
})
63+
)
64+
5865
navigationController.pushViewController(controller, animated: false)
5966
}
6067
}

ios/MullvadVPN/Coordinators/CustomLists/CustomListInteractor.swift

+6-6
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,20 @@
99
import MullvadSettings
1010

1111
protocol CustomListInteractorProtocol {
12-
func createCustomList(viewModel: CustomListViewModel) throws
13-
func updateCustomList(viewModel: CustomListViewModel)
12+
func fetchAllCustomLists() -> [CustomList]
13+
func saveCustomList(viewModel: CustomListViewModel) throws
1414
func deleteCustomList(id: UUID)
1515
}
1616

1717
struct CustomListInteractor: CustomListInteractorProtocol {
1818
let repository: CustomListRepositoryProtocol
1919

20-
func createCustomList(viewModel: CustomListViewModel) throws {
21-
try _ = repository.create(viewModel.name, locations: viewModel.locations)
20+
func fetchAllCustomLists() -> [CustomList] {
21+
repository.fetchAll()
2222
}
2323

24-
func updateCustomList(viewModel: CustomListViewModel) {
25-
repository.update(viewModel.customList)
24+
func saveCustomList(viewModel: CustomListViewModel) throws {
25+
try _ = repository.save(list: viewModel.customList)
2626
}
2727

2828
func deleteCustomList(id: UUID) {

ios/MullvadVPN/Coordinators/CustomLists/CustomListViewController.swift

+1-9
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,6 @@ class CustomListViewController: UIViewController {
9191
}
9292

9393
private func configureNavigationItem() {
94-
navigationItem.leftBarButtonItem = UIBarButtonItem(
95-
systemItem: .cancel,
96-
primaryAction: UIAction(handler: { _ in
97-
self.dismiss(animated: true)
98-
})
99-
)
100-
10194
navigationItem.rightBarButtonItem = saveBarButton
10295
}
10396

@@ -149,7 +142,7 @@ class CustomListViewController: UIViewController {
149142

150143
private func onSave() {
151144
do {
152-
try interactor.createCustomList(viewModel: subject.value)
145+
try interactor.saveCustomList(viewModel: subject.value)
153146
delegate?.customListDidSave()
154147
} catch {
155148
validationErrors.insert(.name)
@@ -183,7 +176,6 @@ class CustomListViewController: UIViewController {
183176
style: .destructive,
184177
handler: {
185178
self.interactor.deleteCustomList(id: self.subject.value.id)
186-
self.dismiss(animated: true)
187179
self.delegate?.customListDidDelete()
188180
}
189181
),

ios/MullvadVPN/Coordinators/CustomLists/EditCustomListCoordinator.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class EditCustomListCoordinator: Coordinator, Presentable, Presenting {
5656
comment: ""
5757
)
5858

59-
navigationController.pushViewController(controller, animated: false)
59+
navigationController.pushViewController(controller, animated: true)
6060
}
6161
}
6262

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//
2+
// ListCustomListCoordinator.swift
3+
// MullvadVPN
4+
//
5+
// Created by Jon Petersson on 2024-03-06.
6+
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
7+
//
8+
9+
import MullvadSettings
10+
import Routing
11+
import UIKit
12+
13+
class ListCustomListCoordinator: Coordinator, Presentable, Presenting {
14+
let navigationController: UINavigationController
15+
let interactor: CustomListInteractorProtocol
16+
let listViewController: ListCustomListViewController
17+
18+
var presentedViewController: UIViewController {
19+
navigationController
20+
}
21+
22+
var didFinish: (() -> Void)?
23+
24+
init(
25+
navigationController: UINavigationController,
26+
interactor: CustomListInteractorProtocol
27+
) {
28+
self.navigationController = navigationController
29+
self.interactor = interactor
30+
listViewController = ListCustomListViewController(interactor: interactor)
31+
}
32+
33+
func start() {
34+
listViewController.didFinish = didFinish
35+
listViewController.didSelectItem = {
36+
self.edit(list: $0)
37+
}
38+
39+
navigationController.pushViewController(listViewController, animated: false)
40+
}
41+
42+
private func edit(list: CustomList) {
43+
// Remove previous edit coordinator to prevent accumulation.
44+
childCoordinators.filter { $0 is EditCustomListCoordinator }.forEach { $0.removeFromParent() }
45+
46+
let coordinator = EditCustomListCoordinator(
47+
navigationController: navigationController,
48+
customListInteractor: interactor,
49+
customList: list
50+
)
51+
52+
coordinator.didFinish = {
53+
self.popToList()
54+
coordinator.removeFromParent()
55+
56+
self.listViewController.updateDataSource()
57+
}
58+
59+
coordinator.start()
60+
addChild(coordinator)
61+
}
62+
63+
private func popToList() {
64+
guard let listController = navigationController.viewControllers
65+
.first(where: { $0 is ListCustomListViewController }) else { return }
66+
67+
navigationController.popToViewController(listController, animated: true)
68+
}
69+
}

0 commit comments

Comments
 (0)