Skip to content

Commit

Permalink
Update API access methods functionality UI to conform with designs
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon Petersson committed Jan 23, 2024
1 parent e0d794c commit af91671
Show file tree
Hide file tree
Showing 74 changed files with 1,850 additions and 2,123 deletions.
55 changes: 30 additions & 25 deletions ios/MullvadSettings/AccessMethodRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,27 @@

import Combine
import Foundation
import MullvadLogging

public class AccessMethodRepository: AccessMethodRepositoryProtocol {
let passthroughSubject: CurrentValueSubject<[PersistentAccessMethod], Never> = CurrentValueSubject([])
private let logger = Logger(label: "AccessMethodRepository")

private let direct = PersistentAccessMethod(
id: UUID(uuidString: "C9DB7457-2A55-42C3-A926-C07F82131994")!,
name: "",
name: "Direct",
isEnabled: true,
proxyConfiguration: .direct
)

private let bridge = PersistentAccessMethod(
id: UUID(uuidString: "8586E75A-CA7B-4432-B70D-EE65F3F95084")!,
name: "",
name: "Mullvad bridges",
isEnabled: true,
proxyConfiguration: .bridges
)

let passthroughSubject: CurrentValueSubject<[PersistentAccessMethod], Never> = CurrentValueSubject([])

public var publisher: AnyPublisher<[PersistentAccessMethod], Never> {
passthroughSubject.eraseToAnyPublisher()
}
Expand All @@ -36,35 +41,19 @@ public class AccessMethodRepository: AccessMethodRepositoryProtocol {
add([direct, bridge])
}

public func add(_ method: PersistentAccessMethod) {
add([method])
}

public func add(_ methods: [PersistentAccessMethod]) {
public func save(_ method: PersistentAccessMethod) {
var storedMethods = fetchAll()

methods.forEach { method in
guard !storedMethods.contains(where: { $0.id == method.id }) else { return }
if let index = storedMethods.firstIndex(where: { $0.id == method.id }) {
storedMethods[index] = method
} else {
storedMethods.append(method)
}

do {
try writeApiAccessMethods(storedMethods)
} catch {
print("Could not add access method(s): \(methods) \nError: \(error)")
}
}

public func update(_ method: PersistentAccessMethod) {
var methods = fetchAll()

guard let index = methods.firstIndex(where: { $0.id == method.id }) else { return }
methods[index] = method

do {
try writeApiAccessMethods(methods)
} catch {
print("Could not update access method: \(method) \nError: \(error)")
logger.error("Could not update access methods: \(storedMethods) \nError: \(error)")
}
}

Expand All @@ -81,7 +70,7 @@ public class AccessMethodRepository: AccessMethodRepositoryProtocol {
do {
try writeApiAccessMethods(methods)
} catch {
print("Could not delete access method with id: \(id) \nError: \(error)")
logger.error("Could not delete access method with id: \(id) \nError: \(error)")
}
}

Expand All @@ -97,6 +86,22 @@ public class AccessMethodRepository: AccessMethodRepositoryProtocol {
add([direct, bridge])
}

private func add(_ methods: [PersistentAccessMethod]) {
var storedMethods = fetchAll()

methods.forEach { method in
if !storedMethods.contains(where: { $0.id == method.id }) {
storedMethods.append(method)
}
}

do {
try writeApiAccessMethods(storedMethods)
} catch {
logger.error("Could not update access methods: \(storedMethods) \nError: \(error)")
}
}

private func readApiAccessMethods() throws -> [PersistentAccessMethod] {
let parser = makeParser()
let data = try SettingsManager.store.read(key: .apiAccessMethods)
Expand Down
7 changes: 1 addition & 6 deletions ios/MullvadSettings/AccessMethodRepositoryProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
//

import Combine
import Foundation

public protocol AccessMethodRepositoryDataSource {
/// Publisher that propagates a snapshot of persistent store upon modifications.
Expand All @@ -19,11 +18,7 @@ public protocol AccessMethodRepositoryDataSource {
public protocol AccessMethodRepositoryProtocol: AccessMethodRepositoryDataSource {
/// Add new access method.
/// - Parameter method: persistent access method model.
func add(_ method: PersistentAccessMethod)

/// Persist modified access method locating existing entry by id.
/// - Parameter method: persistent access method model.
func update(_ method: PersistentAccessMethod)
func save(_ method: PersistentAccessMethod)

/// Delete access method by id.
/// - Parameter id: an access method id.
Expand Down
166 changes: 50 additions & 116 deletions ios/MullvadVPN.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class ProxyConfigurationTester: ProxyConfigurationTesterProtocol {
}

func cancel() {
cancellable?.cancel()
cancellable = nil
}
}
6 changes: 1 addition & 5 deletions ios/MullvadVPN/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
let relayCache = RelayCache(cacheDirectory: containerURL)
relayCacheTracker = RelayCacheTracker(relayCache: relayCache, application: application, apiProxy: apiProxy)

addressCacheTracker = AddressCacheTracker(
application: application,
apiProxy: apiProxy,
store: addressCache
)
addressCacheTracker = AddressCacheTracker(application: application, apiProxy: apiProxy, store: addressCache)

tunnelStore = TunnelStore(application: application)
tunnelManager = createTunnelManager(application: application)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,19 @@

import UIKit

/// View controller used for presenting a detailed information on some topic using markdown in a scrollable text view.
/// View controller used for presenting a detailed information on some topic using a scrollable stack view.
class AboutViewController: UIViewController {
private let textView = UITextView()
private let markdown: String
private let scrollView = UIScrollView()
private let contentView = UIStackView()
private let header: String?
private let preamble: String?
private let body: [String]

init(header: String?, preamble: String?, body: [String]) {
self.header = header
self.preamble = preamble
self.body = body

init(markdown: String) {
self.markdown = markdown
super.init(nibName: nil, bundle: nil)
}

Expand All @@ -25,20 +31,62 @@ class AboutViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.paragraphSpacing = 16
view.backgroundColor = .secondaryColor
navigationController?.navigationBar.configureCustomAppeareance()

setUpContentView()

scrollView.addConstrainedSubviews([contentView]) {
contentView.pinEdgesToSuperview()
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
}

view.addConstrainedSubviews([scrollView]) {
scrollView.pinEdgesToSuperview()
}
}

private func setUpContentView() {
contentView.axis = .vertical
contentView.spacing = 15
contentView.layoutMargins = UIMetrics.contentInsets
contentView.isLayoutMarginsRelativeArrangement = true

if let header {
let label = UILabel()

label.text = header
label.font = .systemFont(ofSize: 28, weight: .bold)
label.textColor = .white
label.numberOfLines = 0
label.textAlignment = .center

contentView.addArrangedSubview(label)
contentView.setCustomSpacing(32, after: label)
}

if let preamble {
let label = UILabel()

label.text = preamble
label.font = .systemFont(ofSize: 18)
label.textColor = .white
label.numberOfLines = 0
label.textAlignment = .center

contentView.addArrangedSubview(label)
contentView.setCustomSpacing(24, after: label)
}

let stylingOptions = MarkdownStylingOptions(
font: .systemFont(ofSize: 17),
paragraphStyle: paragraphStyle
)
for text in body {
let label = UILabel()

textView.attributedText = NSAttributedString(markdownString: markdown, options: stylingOptions)
textView.textContainerInset = UIMetrics.contentInsets
textView.isEditable = false
label.text = text
label.font = .systemFont(ofSize: 15)
label.textColor = .white
label.numberOfLines = 0

view.addConstrainedSubviews([textView]) {
textView.pinEdgesToSuperview()
contentView.addArrangedSubview(label)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,60 +11,89 @@ import MullvadSettings
import Routing
import UIKit

class AddAccessMethodCoordinator: Coordinator, Presentable {
class AddAccessMethodCoordinator: Coordinator, Presentable, Presenting {
private let subject: CurrentValueSubject<AccessMethodViewModel, Never> = .init(AccessMethodViewModel())

let navigationController: UINavigationController
let accessMethodRepository: AccessMethodRepositoryProtocol
let proxyConfigurationTester: ProxyConfigurationTesterProtocol

var presentedViewController: UIViewController {
navigationController
}

let navigationController: UINavigationController
let accessMethodRepo: AccessMethodRepositoryProtocol
let proxyConfigurationTester: ProxyConfigurationTesterProtocol

init(
navigationController: UINavigationController,
accessMethodRepo: AccessMethodRepositoryProtocol,
proxyConfigurationTester: ProxyConfigurationTesterProtocol
) {
self.navigationController = navigationController
self.accessMethodRepo = accessMethodRepo
self.accessMethodRepository = accessMethodRepo
self.proxyConfigurationTester = proxyConfigurationTester
}

func start() {
let controller = AddAccessMethodViewController(
let controller = MethodSettingsViewController(
subject: subject,
interactor: AddAccessMethodInteractor(
interactor: EditAccessMethodInteractor(
subject: subject,
repo: accessMethodRepo,
repository: accessMethodRepository,
proxyConfigurationTester: proxyConfigurationTester
)
),
alertPresenter: AlertPresenter(context: self)
)

setUpControllerNavigationItem(controller)
controller.delegate = self

navigationController.pushViewController(controller, animated: false)
}
}

extension AddAccessMethodCoordinator: AddAccessMethodViewControllerDelegate {
func controllerDidAdd(_ controller: AddAccessMethodViewController) {
dismiss(animated: true)
private func setUpControllerNavigationItem(_ controller: MethodSettingsViewController) {
controller.navigationItem.prompt = NSLocalizedString(
"METHOD_SETTINGS_NAVIGATION_ADD_PROMPT",
tableName: "APIAccess",
value: "The app will test the method before saving.",
comment: ""
)

controller.navigationItem.title = NSLocalizedString(
"METHOD_SETTINGS_NAVIGATION_ADD_TITLE",
tableName: "APIAccess",
value: "Add access method",
comment: ""
)

controller.saveBarButton.title = NSLocalizedString(
"METHOD_SETTINGS_NAVIGATION_ADD_BUTTON",
tableName: "APIAccess",
value: "Add",
comment: ""
)

controller.navigationItem.leftBarButtonItem = UIBarButtonItem(
systemItem: .cancel,
primaryAction: UIAction(handler: { [weak self] _ in
self?.dismiss(animated: true)
})
)
}
}

func controllerDidCancel(_ controller: AddAccessMethodViewController) {
extension AddAccessMethodCoordinator: MethodSettingsViewControllerDelegate {
func viewModelDidSave(_ viewModel: AccessMethodViewModel) {
dismiss(animated: true)
}

func controllerShouldShowProtocolPicker(_ controller: AddAccessMethodViewController) {
func controllerShouldShowProtocolPicker(_ controller: MethodSettingsViewController) {
let picker = AccessMethodProtocolPicker(navigationController: navigationController)

picker.present(currentValue: subject.value.method) { [weak self] newMethod in
self?.subject.value.method = newMethod
}
}

func controllerShouldShowShadowsocksCipherPicker(_ controller: AddAccessMethodViewController) {
func controllerShouldShowShadowsocksCipherPicker(_ controller: MethodSettingsViewController) {
let picker = ShadowsocksCipherPicker(navigationController: navigationController)

picker.present(currentValue: subject.value.shadowsocks.cipher) { [weak self] selectedCipher in
Expand Down

This file was deleted.

Loading

0 comments on commit af91671

Please sign in to comment.