diff options
8 files changed, 114 insertions, 25 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index b09c0452aa..2aa72ee4fb 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -2811,6 +2811,7 @@ 7A42DEC82A05164100B209BE /* SettingsInputCell.swift */, 58677711290976FB006F721F /* SettingsInteractor.swift */, 5867770F290975E8006F721F /* SettingsInteractorFactory.swift */, + F041BE4E2C983C2B0083EC28 /* SettingsPromptAlertItem.swift */, 58ACF64A26553C3F00ACE4B7 /* SettingsSwitchCell.swift */, 58CCA01122424D11004F3011 /* SettingsViewController.swift */, 7A27E3CA2CAE86170088BCFF /* SettingsViewModel.swift */, diff --git a/ios/MullvadVPN/Coordinators/LocationCoordinator.swift b/ios/MullvadVPN/Coordinators/LocationCoordinator.swift index de38e6c811..76171ca47c 100644 --- a/ios/MullvadVPN/Coordinators/LocationCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/LocationCoordinator.swift @@ -64,7 +64,7 @@ class LocationCoordinator: Coordinator, Presentable, Presenting { customListRepository: customListRepository, constraints: tunnelManager.settings.relayConstraints, multihopEnabled: tunnelManager.settings.tunnelMultihopState.isEnabled, - daitaEnabled: tunnelManager.settings.daita.daitaState.isEnabled, + daitaSettings: tunnelManager.settings.daita, startContext: startContext ) locationViewControllerWrapper.delegate = self diff --git a/ios/MullvadVPN/View controllers/Alert/AlertPresenter.swift b/ios/MullvadVPN/View controllers/Alert/AlertPresenter.swift index db2c0ff971..854076784f 100644 --- a/ios/MullvadVPN/View controllers/Alert/AlertPresenter.swift +++ b/ios/MullvadVPN/View controllers/Alert/AlertPresenter.swift @@ -9,9 +9,11 @@ import Routing struct AlertPresenter { - let context: any Presenting + weak var context: (any Presenting)? func showAlert(presentation: AlertPresentation, animated: Bool) { + guard let context else { return } + context.applicationRouter?.presentAlert( route: .alert(presentation.id), animated: animated, @@ -20,7 +22,7 @@ struct AlertPresenter { } func dismissAlert(presentation: AlertPresentation, animated: Bool) { - context.applicationRouter?.dismiss(.alert(presentation.id), animated: animated) + context?.applicationRouter?.dismiss(.alert(presentation.id), animated: animated) } } diff --git a/ios/MullvadVPN/View controllers/SelectLocation/LocationViewController.swift b/ios/MullvadVPN/View controllers/SelectLocation/LocationViewController.swift index 587f5ab146..fb0ff50e5b 100644 --- a/ios/MullvadVPN/View controllers/SelectLocation/LocationViewController.swift +++ b/ios/MullvadVPN/View controllers/SelectLocation/LocationViewController.swift @@ -26,7 +26,7 @@ final class LocationViewController: UIViewController { private var relaysWithLocation: LocationRelays? private var filter = RelayFilter() private var selectedRelays: RelaySelection - private var daitaEnabled: Bool + private var shouldFilterDaita: Bool weak var delegate: LocationViewControllerDelegate? var customListRepository: CustomListRepositoryProtocol @@ -35,17 +35,17 @@ final class LocationViewController: UIViewController { } var filterViewShouldBeHidden: Bool { - !daitaEnabled && (filter.ownership == .any) && (filter.providers == .any) + !shouldFilterDaita && (filter.ownership == .any) && (filter.providers == .any) } init( customListRepository: CustomListRepositoryProtocol, selectedRelays: RelaySelection, - daitaEnabled: Bool = false + shouldFilterDaita: Bool ) { self.customListRepository = customListRepository self.selectedRelays = selectedRelays - self.daitaEnabled = daitaEnabled + self.shouldFilterDaita = shouldFilterDaita super.init(nibName: nil, bundle: nil) } @@ -154,7 +154,7 @@ final class LocationViewController: UIViewController { topContentView.addArrangedSubview(searchBar) filterView.isHidden = filterViewShouldBeHidden - filterView.setDaita(daitaEnabled) + filterView.setDaita(shouldFilterDaita) filterView.didUpdateFilter = { [weak self] in self?.delegate?.didUpdateFilter(filter: $0) diff --git a/ios/MullvadVPN/View controllers/SelectLocation/LocationViewControllerWrapper.swift b/ios/MullvadVPN/View controllers/SelectLocation/LocationViewControllerWrapper.swift index 4f8147f746..02f8194248 100644 --- a/ios/MullvadVPN/View controllers/SelectLocation/LocationViewControllerWrapper.swift +++ b/ios/MullvadVPN/View controllers/SelectLocation/LocationViewControllerWrapper.swift @@ -52,7 +52,7 @@ final class LocationViewControllerWrapper: UIViewController { private var selectedExit: UserSelectedRelays? private let multihopEnabled: Bool private var multihopContext: MultihopContext = .exit - private let daitaEnabled: Bool + private let daitaSettings: DAITASettings weak var delegate: LocationViewControllerWrapperDelegate? @@ -60,11 +60,11 @@ final class LocationViewControllerWrapper: UIViewController { customListRepository: CustomListRepositoryProtocol, constraints: RelayConstraints, multihopEnabled: Bool, - daitaEnabled: Bool, + daitaSettings: DAITASettings, startContext: MultihopContext ) { self.multihopEnabled = multihopEnabled - self.daitaEnabled = daitaEnabled + self.daitaSettings = daitaSettings multihopContext = startContext selectedEntry = constraints.entryLocations.value @@ -73,13 +73,16 @@ final class LocationViewControllerWrapper: UIViewController { entryLocationViewController = LocationViewController( customListRepository: customListRepository, selectedRelays: RelaySelection(), - daitaEnabled: multihopEnabled && daitaEnabled + shouldFilterDaita: daitaSettings.daitaState.isEnabled + && daitaSettings.directOnlyState.isEnabled ) exitLocationViewController = LocationViewController( customListRepository: customListRepository, selectedRelays: RelaySelection(), - daitaEnabled: !multihopEnabled && daitaEnabled + shouldFilterDaita: !multihopEnabled + && daitaSettings.daitaState.isEnabled + && daitaSettings.directOnlyState.isEnabled ) super.init(nibName: nil, bundle: nil) @@ -109,7 +112,7 @@ final class LocationViewControllerWrapper: UIViewController { func setRelaysWithLocation(_ relaysWithLocation: LocationRelays, filter: RelayFilter) { var daitaFilteredRelays = relaysWithLocation - if daitaEnabled { + if daitaSettings.daitaState.isEnabled && daitaSettings.directOnlyState.isEnabled { daitaFilteredRelays.relays = relaysWithLocation.relays.filter { relay in relay.daita == true } diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsDataSource.swift b/ios/MullvadVPN/View controllers/Settings/SettingsDataSource.swift index eb9236bc58..59219e6205 100644 --- a/ios/MullvadVPN/View controllers/Settings/SettingsDataSource.swift +++ b/ios/MullvadVPN/View controllers/Settings/SettingsDataSource.swift @@ -25,11 +25,17 @@ final class SettingsDataSource: UITableViewDiffableDataSource<SettingsDataSource } } - private enum HeaderFooterReuseIdentifier: String, CaseIterable { + private enum HeaderFooterReuseIdentifier: String, CaseIterable, HeaderFooterIdentifierProtocol { + case primary case spacer - var reusableViewClass: AnyClass { - EmptyTableViewHeaderFooterView.self + var headerFooterClass: AnyClass { + switch self { + case .primary: + UITableViewHeaderFooterView.self + case .spacer: + EmptyTableViewHeaderFooterView.self + } } } @@ -38,6 +44,20 @@ final class SettingsDataSource: UITableViewDiffableDataSource<SettingsDataSource case main case version case problemReport + + var sectionFooter: String? { + switch self { + case .daita: + NSLocalizedString( + "SETTINGS_DAITA_SECTION_FOOTER", + tableName: "Settings", + value: "Makes it possible to use DAITA with any server and is automatically enabled.", + comment: "" + ) + default: + nil + } + } } enum Item: String { @@ -130,16 +150,43 @@ final class SettingsDataSource: UITableViewDiffableDataSource<SettingsDataSource ) } - func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { - nil + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + let sectionIdentifier = snapshot().sectionIdentifiers[section] + + return switch sectionIdentifier { + case .main: + 0 + case .daita, .version, .problemReport: + UITableView.automaticDimension + } } - func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - return UIMetrics.TableView.sectionSpacing + func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { + let sectionIdentifier = snapshot().sectionIdentifiers[section] + guard let sectionFooterText = sectionIdentifier.sectionFooter else { return nil } + + guard let headerView = tableView + .dequeueReusableView(withIdentifier: HeaderFooterReuseIdentifier.primary) + else { return nil } + + var contentConfiguration = UIListContentConfiguration.mullvadGroupedFooter(tableStyle: .plain) + contentConfiguration.text = sectionFooterText + + headerView.contentConfiguration = contentConfiguration +// headerView.directionalLayoutMargins = UIMetrics.SettingsCell.apiAccessInsetLayoutMargins + + return headerView } func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { - 0 + let sectionIdentifier = snapshot().sectionIdentifiers[section] + + return switch sectionIdentifier { + case .daita: + UITableView.automaticDimension + case .main, .version, .problemReport: + 0 + } } // MARK: - Private @@ -154,7 +201,7 @@ final class SettingsDataSource: UITableViewDiffableDataSource<SettingsDataSource HeaderFooterReuseIdentifier.allCases.forEach { reuseIdentifier in tableView?.register( - reuseIdentifier.reusableViewClass, + reuseIdentifier.headerFooterClass, forHeaderFooterViewReuseIdentifier: reuseIdentifier.rawValue ) } diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsInteractor.swift b/ios/MullvadVPN/View controllers/Settings/SettingsInteractor.swift index 78a5a6dd43..32ef2e7b53 100644 --- a/ios/MullvadVPN/View controllers/Settings/SettingsInteractor.swift +++ b/ios/MullvadVPN/View controllers/Settings/SettingsInteractor.swift @@ -46,7 +46,11 @@ final class SettingsInteractor { var tunnelSettings = tunnelSettings tunnelSettings.daita = settings - guard let selectedRelays = try? tunnelManager.selectRelays(tunnelSettings: tunnelSettings) else { return nil } - return tunnelSettings.tunnelMultihopState.isEnabled ? .multihop : .singlehop + // Return error if no relays could be selected. + guard (try? tunnelManager.selectRelays(tunnelSettings: tunnelSettings)) != nil else { + return tunnelSettings.tunnelMultihopState.isEnabled ? .multihop : .singlehop + } + + return nil } } diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsPromptAlertItem.swift b/ios/MullvadVPN/View controllers/Settings/SettingsPromptAlertItem.swift new file mode 100644 index 0000000000..e69be4e4a1 --- /dev/null +++ b/ios/MullvadVPN/View controllers/Settings/SettingsPromptAlertItem.swift @@ -0,0 +1,32 @@ +// +// SettingsPromptAlertItem.swift +// MullvadVPN +// +// Created by Mojgan on 2024-09-16. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +enum DAITASettingsPromptItem: CustomStringConvertible { + case daitaSettingIncompatibleWithSinglehop + case daitaSettingIncompatibleWithMultihop + + var description: String { + switch self { + case .daitaSettingIncompatibleWithSinglehop: + """ + DAITA isn’t available on the current server. After enabling, please go to the Switch \ + location view and select a location that supports DAITA. + Attention: Since this increases your total network traffic, be cautious if you have a \ + limited data plan. It can also negatively impact your network speed and battery usage. + """ + case .daitaSettingIncompatibleWithMultihop: + """ + DAITA isn’t available on the current entry server. After enabling, please go to the Switch \ + location view and select an entry location that supports DAITA. + Attention: Since this increases your total network traffic, be cautious if you have a \ + limited data plan. It can also negatively impact your network speed and battery usage. + """ + } + } +} |
