Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor location data type and dependencies #5872

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ios/.swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- type_body_length
- opening_brace # Differs from Google swift guidelines enforced by swiftformat
- trailing_comma
- switch_case_alignment # Enables expressions such as [return switch location {}]

Check warning on line 10 in ios/.swiftlint.yml

View workflow job for this annotation

GitHub Actions / check-formatting

10:27 [comments] too few spaces before comment
opt_in_rules:
- empty_count

Expand Down
78 changes: 53 additions & 25 deletions ios/MullvadVPN.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

24 changes: 12 additions & 12 deletions ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
}()

private var splitTunnelCoordinator: TunnelCoordinator?
private var splitLocationCoordinator: SelectLocationCoordinator?
private var splitLocationCoordinator: LocationCoordinator?

private let tunnelManager: TunnelManager
private let storePaymentManager: StorePaymentManager
Expand Down Expand Up @@ -488,17 +488,17 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo

private func setupSplitView() {
let tunnelCoordinator = makeTunnelCoordinator()
let selectLocationCoordinator = makeSelectLocationCoordinator(forModalPresentation: false)
let locationCoordinator = makeLocationCoordinator(forModalPresentation: false)

addChild(tunnelCoordinator)
addChild(selectLocationCoordinator)
addChild(locationCoordinator)

splitTunnelCoordinator = tunnelCoordinator
splitLocationCoordinator = selectLocationCoordinator
splitLocationCoordinator = locationCoordinator

splitViewController.delegate = self
splitViewController.viewControllers = [
selectLocationCoordinator.navigationController,
locationCoordinator.navigationController,
tunnelCoordinator.rootViewController,
]

Expand All @@ -508,7 +508,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
.safeAreaLayoutGuide

tunnelCoordinator.start()
selectLocationCoordinator.start()
locationCoordinator.start()
}

private func presentTOS(animated: Bool, completion: @escaping (Coordinator) -> Void) {
Expand Down Expand Up @@ -634,7 +634,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
}

private func presentSelectLocation(animated: Bool, completion: @escaping (Coordinator) -> Void) {
let coordinator = makeSelectLocationCoordinator(forModalPresentation: true)
let coordinator = makeLocationCoordinator(forModalPresentation: true)
coordinator.start()

presentChild(coordinator, animated: animated) {
Expand Down Expand Up @@ -702,24 +702,24 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
return tunnelCoordinator
}

private func makeSelectLocationCoordinator(forModalPresentation isModalPresentation: Bool)
-> SelectLocationCoordinator {
private func makeLocationCoordinator(forModalPresentation isModalPresentation: Bool)
-> LocationCoordinator {
let navigationController = CustomNavigationController()
navigationController.isNavigationBarHidden = !isModalPresentation

let selectLocationCoordinator = SelectLocationCoordinator(
let locationCoordinator = LocationCoordinator(
navigationController: navigationController,
tunnelManager: tunnelManager,
relayCacheTracker: relayCacheTracker
)

selectLocationCoordinator.didFinish = { [weak self] _, _ in
locationCoordinator.didFinish = { [weak self] _ in
if isModalPresentation {
self?.router.dismiss(.selectLocation, animated: true)
}
}

return selectLocationCoordinator
return locationCoordinator
}

private func presentAccount(animated: Bool, completion: @escaping (Coordinator) -> Void) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// SelectLocationCoordinator.swift
// LocationCoordinator.swift
// MullvadVPN
//
// Created by pronebird on 29/01/2023.
Expand All @@ -11,9 +11,7 @@ import MullvadTypes
import Routing
import UIKit

import MullvadSettings

class SelectLocationCoordinator: Coordinator, Presentable, Presenting, RelayCacheTrackerObserver {
class LocationCoordinator: Coordinator, Presentable, Presenting, RelayCacheTrackerObserver {
private let tunnelManager: TunnelManager
private let relayCacheTracker: RelayCacheTracker
private var cachedRelays: CachedRelays?
Expand All @@ -24,10 +22,10 @@ class SelectLocationCoordinator: Coordinator, Presentable, Presenting, RelayCach
navigationController
}

var selectLocationViewController: SelectLocationViewController? {
var selectLocationViewController: LocationViewController? {
return navigationController.viewControllers.first {
$0 is SelectLocationViewController
} as? SelectLocationViewController
$0 is LocationViewController
} as? LocationViewController
}

var relayFilter: RelayFilter {
Expand All @@ -39,7 +37,7 @@ class SelectLocationCoordinator: Coordinator, Presentable, Presenting, RelayCach
}
}

var didFinish: ((SelectLocationCoordinator, RelayLocation?) -> Void)?
var didFinish: ((LocationCoordinator) -> Void)?

init(
navigationController: UINavigationController,
Expand All @@ -52,22 +50,19 @@ class SelectLocationCoordinator: Coordinator, Presentable, Presenting, RelayCach
}

func start() {
let selectLocationViewController = SelectLocationViewController()
let selectLocationViewController = LocationViewController()

selectLocationViewController.didSelectRelay = { [weak self] relay in
selectLocationViewController.didSelectRelays = { [weak self] locations in
guard let self else { return }

var relayConstraints = tunnelManager.settings.relayConstraints
relayConstraints.locations = .only(RelayLocations(
locations: [relay],
customListId: nil
))
relayConstraints.locations = .only(locations)

tunnelManager.updateSettings([.relayConstraints(relayConstraints)]) {
self.tunnelManager.startTunnel()
}

didFinish?(self, relay)
didFinish?(self)
}

selectLocationViewController.navigateToFilter = { [weak self] in
Expand All @@ -91,7 +86,7 @@ class SelectLocationCoordinator: Coordinator, Presentable, Presenting, RelayCach
selectLocationViewController.didFinish = { [weak self] in
guard let self else { return }

didFinish?(self, nil)
didFinish?(self)
}

relayCacheTracker.addObserver(self)
Expand All @@ -101,8 +96,7 @@ class SelectLocationCoordinator: Coordinator, Presentable, Presenting, RelayCach
selectLocationViewController.setCachedRelays(cachedRelays, filter: relayFilter)
}

selectLocationViewController.relayLocation =
tunnelManager.settings.relayConstraints.locations.value?.locations.first
selectLocationViewController.relayLocations = tunnelManager.settings.relayConstraints.locations.value

navigationController.pushViewController(selectLocationViewController, animated: false)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// SettingsValidationErrorConfiguration.swift
// MullvadVPN
//
// Created by Jon Petersson on 2024-02-16.
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
//

import UIKit

struct SettingsValidationErrorConfiguration: UIContentConfiguration, Equatable {
var errors: [CustomListFieldValidationError] = []
var directionalLayoutMargins: NSDirectionalEdgeInsets = UIMetrics.SettingsCell.settingsValidationErrorLayoutMargins

func makeContentView() -> UIView & UIContentView {
return SettingsValidationErrorContentView(configuration: self)
}

func updated(for state: UIConfigurationState) -> Self {
return self
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//
// SettingsValidationErrorContentView.swift
// MullvadVPN
//
// Created by Jon Petersson on 2024-02-16.
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
//

import UIKit

class SettingsValidationErrorContentView: UIView, UIContentView {
let contentView = UIStackView()

var icon: UIImageView {
let view = UIImageView(image: UIImage(resource: .iconAlert).withTintColor(.dangerColor))
view.heightAnchor.constraint(equalToConstant: 14).isActive = true
view.widthAnchor.constraint(equalTo: view.heightAnchor, multiplier: 1).isActive = true
return view
}

var configuration: UIContentConfiguration {
get {
actualConfiguration
}
set {
guard let newConfiguration = newValue as? SettingsValidationErrorConfiguration else { return }

let previousConfiguration = actualConfiguration
actualConfiguration = newConfiguration

configureSubviews(previousConfiguration: previousConfiguration)
}
}

private var actualConfiguration: SettingsValidationErrorConfiguration

func supports(_ configuration: UIContentConfiguration) -> Bool {
configuration is SettingsValidationErrorConfiguration
}

init(configuration: SettingsValidationErrorConfiguration) {
actualConfiguration = configuration

super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 44))

addSubviews()
configureSubviews()
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

private func addSubviews() {
contentView.axis = .vertical
contentView.spacing = 6

addConstrainedSubviews([contentView]) {
contentView.pinEdgesToSuperviewMargins()
}
}

private func configureSubviews(previousConfiguration: SettingsValidationErrorConfiguration? = nil) {
guard actualConfiguration != previousConfiguration else { return }

configureLayoutMargins()

contentView.arrangedSubviews.forEach { view in
view.removeFromSuperview()
}

actualConfiguration.errors.forEach { error in
let label = UILabel()
label.text = error.errorDescription
label.numberOfLines = 0
label.font = .systemFont(ofSize: 13)
label.textColor = .white.withAlphaComponent(0.6)

let stackView = UIStackView(arrangedSubviews: [icon, label])
stackView.alignment = .top
stackView.spacing = 6

contentView.addArrangedSubview(stackView)
}
}

private func configureLayoutMargins() {
directionalLayoutMargins = actualConfiguration.directionalLayoutMargins
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ extension UIBackgroundConfiguration {
/// - Returns: a background configuration
static func mullvadListPlainCell() -> UIBackgroundConfiguration {
var config = listPlainCell()
config.backgroundColor = UIColor.Cell.backgroundColor
config.backgroundColor = UIColor.Cell.Background.normal
return config
}

/// Returns the corresponding grouped cell background configuration adapted for Mullvad UI.
/// - Returns: a background configuration
static func mullvadListGroupedCell() -> UIBackgroundConfiguration {
var config = listGroupedCell()
config.backgroundColor = UIColor.Cell.backgroundColor
config.backgroundColor = UIColor.Cell.Background.normal
return config
}

Expand Down Expand Up @@ -58,20 +58,20 @@ extension UICellConfigurationState {
switch selectionType {
case .dimmed:
if isSelected || isHighlighted {
UIColor.Cell.selectedAltBackgroundColor
UIColor.Cell.Background.selectedAlt
} else if isDisabled {
UIColor.Cell.disabledBackgroundColor
UIColor.Cell.Background.disabled
} else {
UIColor.Cell.backgroundColor
UIColor.Cell.Background.normal
}

case .green:
if isSelected || isHighlighted {
UIColor.Cell.selectedBackgroundColor
UIColor.Cell.Background.selected
} else if isDisabled {
UIColor.Cell.disabledBackgroundColor
UIColor.Cell.Background.disabled
} else {
UIColor.Cell.backgroundColor
UIColor.Cell.Background.normal
}
}
}
Expand Down
27 changes: 13 additions & 14 deletions ios/MullvadVPN/UI appearance/UIColor+Palette.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,18 @@ extension UIColor {

// Cells
enum Cell {
static let backgroundColor = primaryColor
static let disabledBackgroundColor = backgroundColor.darkened(by: 0.3)!

static let selectedBackgroundColor = successColor
static let disabledSelectedBackgroundColor = selectedBackgroundColor.darkened(by: 0.3)!

static let selectedAltBackgroundColor = backgroundColor.darkened(by: 0.2)!
enum Background {
static let indentationLevelZero = primaryColor
static let indentationLevelOne = UIColor(red: 0.15, green: 0.23, blue: 0.33, alpha: 1.0)
static let indentationLevelTwo = UIColor(red: 0.13, green: 0.20, blue: 0.30, alpha: 1.0)
static let indentationLevelThree = UIColor(red: 0.11, green: 0.17, blue: 0.27, alpha: 1.0)

static let normal = indentationLevelZero
static let disabled = normal.darkened(by: 0.3)!
static let selected = successColor
static let disabledSelected = selected.darkened(by: 0.3)!
static let selectedAlt = normal.darkened(by: 0.2)!
}

static let titleTextColor = UIColor.white
static let detailTextColor = UIColor(white: 1.0, alpha: 0.8)
Expand All @@ -109,13 +114,7 @@ extension UIColor {
static let footerTextColor = UIColor(white: 1.0, alpha: 0.6)
}

enum SubCell {
static let backgroundColor = UIColor(red: 0.15, green: 0.23, blue: 0.33, alpha: 1.0)
}

enum SubSubCell {
static let backgroundColor = UIColor(red: 0.13, green: 0.20, blue: 0.30, alpha: 1.0)
}
enum SettingsCellBackground {}

enum HeaderBar {
static let defaultBackgroundColor = primaryColor
Expand Down
2 changes: 1 addition & 1 deletion ios/MullvadVPN/UI appearance/UIMetrics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ extension UIMetrics {
static let contentInsets = UIEdgeInsets(top: 24, left: 24, bottom: 24, right: 24)

/// Common layout margins for location cell presentation
static let selectLocationCellLayoutMargins = NSDirectionalEdgeInsets(top: 16, leading: 28, bottom: 16, trailing: 12)
static let locationCellLayoutMargins = NSDirectionalEdgeInsets(top: 16, leading: 28, bottom: 16, trailing: 12)

/// Layout margins used by content heading displayed below the large navigation title.
static let contentHeadingLayoutMargins = NSDirectionalEdgeInsets(top: 8, leading: 24, bottom: 24, trailing: 24)
Expand Down
Loading
Loading