summaryrefslogtreecommitdiffhomepage
path: root/ios
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2021-10-19 14:05:30 +0200
committerAndrej Mihajlov <and@mullvad.net>2021-11-04 10:54:05 +0100
commit9879cb94b2b6a0d9ee5c873e8b46bc726ea88dc1 (patch)
tree1437278383a69a42160405a498cd245dc1e32e75 /ios
parent198861449e9aab65e6de496c3aa3eeaa4a89aefa (diff)
downloadmullvadvpn-9879cb94b2b6a0d9ee5c873e8b46bc726ea88dc1.tar.xz
mullvadvpn-9879cb94b2b6a0d9ee5c873e8b46bc726ea88dc1.zip
Settings: implement data source
Diffstat (limited to 'ios')
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj14
-rw-r--r--ios/MullvadVPN/EmptyTableViewHeaderFooterView.swift2
-rw-r--r--ios/MullvadVPN/SettingsDataSource.swift210
-rw-r--r--ios/MullvadVPN/SettingsDataSourceDelegate.swift13
-rw-r--r--ios/MullvadVPN/SettingsViewController.swift148
-rw-r--r--ios/MullvadVPN/StaticTableViewDataSource.swift127
6 files changed, 259 insertions, 255 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index ec6cdb1084..2657cd46b5 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -48,7 +48,6 @@
5819C2142726CC8D00D6EC38 /* DataSourceSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5819C2132726CC8D00D6EC38 /* DataSourceSnapshotTests.swift */; };
5819C2152726CC9400D6EC38 /* DataSourceSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 587EB66F27143B6500123C75 /* DataSourceSnapshot.swift */; };
5819C2172729595500D6EC38 /* SettingsAddDNSEntryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5819C2162729595500D6EC38 /* SettingsAddDNSEntryCell.swift */; };
- 581CBCEE229826FD00727D7F /* StaticTableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581CBCED229826FD00727D7F /* StaticTableViewDataSource.swift */; };
581FC4FA2695ACE100AA97BA /* Account.strings in Resources */ = {isa = PBXBuildFile; fileRef = 581FC4F82695ACE100AA97BA /* Account.strings */; };
5820674926E63EC900655B05 /* Promise+BackgroundTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5820674826E63EC800655B05 /* Promise+BackgroundTask.swift */; };
5820674E26E6510200655B05 /* REST.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5820674D26E6510200655B05 /* REST.swift */; };
@@ -259,6 +258,8 @@
58E1336E26D2BE7500CC316B /* AnyResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E1336C26D2BE7500CC316B /* AnyResult.swift */; };
58E1336F26D2BE7500CC316B /* AnyResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E1336C26D2BE7500CC316B /* AnyResult.swift */; };
58E6771F24ADFE7800AA26E7 /* SettingsNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E6771E24ADFE7800AA26E7 /* SettingsNavigationController.swift */; };
+ 58EE2E3A272FF814003BFF93 /* SettingsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58EE2E38272FF814003BFF93 /* SettingsDataSource.swift */; };
+ 58EE2E3B272FF814003BFF93 /* SettingsDataSourceDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58EE2E39272FF814003BFF93 /* SettingsDataSourceDelegate.swift */; };
58EF580B25D69D7A00AEBA94 /* ProblemReportSubmissionOverlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58EF580A25D69D7A00AEBA94 /* ProblemReportSubmissionOverlayView.swift */; };
58EF581125D69DB400AEBA94 /* StatusImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58EF581025D69DB400AEBA94 /* StatusImageView.swift */; };
58F19E35228C15BA00C7710B /* SpinnerActivityIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F19E34228C15BA00C7710B /* SpinnerActivityIndicatorView.swift */; };
@@ -365,7 +366,6 @@
581503A524D6F4AE00C9C50E /* Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = "<group>"; };
5819C2132726CC8D00D6EC38 /* DataSourceSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataSourceSnapshotTests.swift; sourceTree = "<group>"; };
5819C2162729595500D6EC38 /* SettingsAddDNSEntryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAddDNSEntryCell.swift; sourceTree = "<group>"; };
- 581CBCED229826FD00727D7F /* StaticTableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticTableViewDataSource.swift; sourceTree = "<group>"; };
581FC4F92695ACE100AA97BA /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Account.strings; sourceTree = "<group>"; };
5820674826E63EC800655B05 /* Promise+BackgroundTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Promise+BackgroundTask.swift"; sourceTree = "<group>"; };
5820674D26E6510200655B05 /* REST.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = REST.swift; sourceTree = "<group>"; };
@@ -523,6 +523,8 @@
58E6771E24ADFE7800AA26E7 /* SettingsNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsNavigationController.swift; sourceTree = "<group>"; };
58E973DD24850EB600096F90 /* AsyncOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncOperation.swift; sourceTree = "<group>"; };
58ECD29123F178FD004298B6 /* Screenshots.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Screenshots.xcconfig; sourceTree = "<group>"; };
+ 58EE2E38272FF814003BFF93 /* SettingsDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsDataSource.swift; sourceTree = "<group>"; };
+ 58EE2E39272FF814003BFF93 /* SettingsDataSourceDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsDataSourceDelegate.swift; sourceTree = "<group>"; };
58EF580A25D69D7A00AEBA94 /* ProblemReportSubmissionOverlayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProblemReportSubmissionOverlayView.swift; sourceTree = "<group>"; };
58EF581025D69DB400AEBA94 /* StatusImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusImageView.swift; sourceTree = "<group>"; };
58F19E34228C15BA00C7710B /* SpinnerActivityIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpinnerActivityIndicatorView.swift; sourceTree = "<group>"; };
@@ -881,7 +883,10 @@
5857F24624C882D700CF6F47 /* SelectLocationNavigationController.swift */,
5888AD86227B17950051EB06 /* SelectLocationViewController.swift */,
582BB1B2229574F40055B6EF /* SettingsAccountCell.swift */,
+ 5819C2162729595500D6EC38 /* SettingsAddDNSEntryCell.swift */,
582BB1AE229566420055B6EF /* SettingsCell.swift */,
+ 58EE2E38272FF814003BFF93 /* SettingsDataSource.swift */,
+ 58EE2E39272FF814003BFF93 /* SettingsDataSourceDelegate.swift */,
584D26C5270C8741004EA533 /* SettingsDNSTextCell.swift */,
58E6771E24ADFE7800AA26E7 /* SettingsNavigationController.swift */,
584D26C1270C8542004EA533 /* SettingsStaticTextFooterView.swift */,
@@ -891,7 +896,6 @@
587A01FB23F1F0BE00B68763 /* SimulatorTunnelProviderHost.swift */,
58FD5BEF24238EB300112C88 /* SKProduct+Formatting.swift */,
58F19E34228C15BA00C7710B /* SpinnerActivityIndicatorView.swift */,
- 581CBCED229826FD00727D7F /* StaticTableViewDataSource.swift */,
58EF581025D69DB400AEBA94 /* StatusImageView.swift */,
5807E2BF2432038B00F5FF30 /* String+Split.swift */,
5871FB8225498CA20051A0A4 /* Swizzle.swift */,
@@ -908,7 +912,6 @@
58B8743122B25A7600015324 /* WireguardAssociatedAddresses.swift */,
58F7CA872692E34000FC59FD /* WireguardKeysContentView.swift */,
5877152F23981F7B001F8237 /* WireguardKeysViewController.swift */,
- 5819C2162729595500D6EC38 /* SettingsAddDNSEntryCell.swift */,
);
path = MullvadVPN;
sourceTree = "<group>";
@@ -1329,6 +1332,7 @@
5871FB8325498CA20051A0A4 /* Swizzle.swift in Sources */,
58EF581125D69DB400AEBA94 /* StatusImageView.swift in Sources */,
58907D9524D17B4E00CFC3F5 /* DisconnectSplitButton.swift in Sources */,
+ 58EE2E3B272FF814003BFF93 /* SettingsDataSourceDelegate.swift in Sources */,
5823FA5426CE49F700283BF8 /* TunnelObserver.swift in Sources */,
5888AD87227B17950051EB06 /* SelectLocationViewController.swift in Sources */,
5820676026E75A4D00655B05 /* Promise+Delay.swift in Sources */,
@@ -1390,11 +1394,11 @@
5815039724D6ECAE00C9C50E /* CustomFormatLogHandler.swift in Sources */,
5820675E26E6839900655B05 /* PresentAlertOperation.swift in Sources */,
5815039D24D6ECE600C9C50E /* TextFileOutputStream.swift in Sources */,
- 581CBCEE229826FD00727D7F /* StaticTableViewDataSource.swift in Sources */,
58CE5E64224146200008646E /* AppDelegate.swift in Sources */,
588DD76B26FCB49E006F6233 /* Cancellable.swift in Sources */,
58ACF64F26567A7100ACE4B7 /* CustomSwitchContainer.swift in Sources */,
5857F24324C8662600CF6F47 /* SelectLocationHeaderView.swift in Sources */,
+ 58EE2E3A272FF814003BFF93 /* SettingsDataSource.swift in Sources */,
58AEEF652344A36000C9BBD5 /* KeychainError.swift in Sources */,
581503A624D6F4AE00C9C50E /* Logging.swift in Sources */,
58CCA01222424D11004F3011 /* SettingsViewController.swift in Sources */,
diff --git a/ios/MullvadVPN/EmptyTableViewHeaderFooterView.swift b/ios/MullvadVPN/EmptyTableViewHeaderFooterView.swift
index 0d047ab045..78c30b5e15 100644
--- a/ios/MullvadVPN/EmptyTableViewHeaderFooterView.swift
+++ b/ios/MullvadVPN/EmptyTableViewHeaderFooterView.swift
@@ -10,8 +10,6 @@ import UIKit
class EmptyTableViewHeaderFooterView: UITableViewHeaderFooterView {
- static var reuseIdentifier = "EmptyTableViewHeaderFooterView"
-
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
diff --git a/ios/MullvadVPN/SettingsDataSource.swift b/ios/MullvadVPN/SettingsDataSource.swift
new file mode 100644
index 0000000000..9d1d48be6b
--- /dev/null
+++ b/ios/MullvadVPN/SettingsDataSource.swift
@@ -0,0 +1,210 @@
+//
+// SettingsDataSource.swift
+// MullvadVPN
+//
+// Created by pronebird on 19/10/2021.
+// Copyright © 2021 Mullvad VPN AB. All rights reserved.
+//
+
+import UIKit
+
+class SettingsDataSource: NSObject, AccountObserver, UITableViewDataSource, UITableViewDelegate {
+ private enum CellReuseIdentifiers: String, CaseIterable {
+ case accountCell
+ case basicCell
+
+ var reusableViewClass: AnyClass {
+ switch self {
+ case .accountCell:
+ return SettingsAccountCell.self
+ case .basicCell:
+ return SettingsCell.self
+ }
+ }
+ }
+
+ private enum HeaderFooterReuseIdentifier: String, CaseIterable {
+ case spacer
+
+ var reusableViewClass: AnyClass {
+ switch self {
+ case .spacer:
+ return EmptyTableViewHeaderFooterView.self
+ }
+ }
+ }
+
+ enum Section: String {
+ case main
+ case version
+ case problemReport
+ }
+
+ enum Item: String {
+ case account
+ case preferences
+ case wireguardKey
+ case version
+ case problemReport
+ }
+
+ private var snapshot = DataSourceSnapshot<Section, Item>()
+
+ weak var delegate: SettingsDataSourceDelegate?
+
+ weak var tableView: UITableView? {
+ didSet {
+ tableView?.delegate = self
+ tableView?.dataSource = self
+
+ registerClasses()
+ }
+ }
+
+ override init() {
+ super.init()
+
+ Account.shared.addObserver(self)
+ updateDataSnapshot()
+ }
+
+ private func registerClasses() {
+ CellReuseIdentifiers.allCases.forEach { cellIdentifier in
+ tableView?.register(cellIdentifier.reusableViewClass, forCellReuseIdentifier: cellIdentifier.rawValue)
+ }
+
+ HeaderFooterReuseIdentifier.allCases.forEach { reuseIdentifier in
+ tableView?.register(reuseIdentifier.reusableViewClass, forHeaderFooterViewReuseIdentifier: reuseIdentifier.rawValue)
+ }
+ }
+
+ private func updateDataSnapshot() {
+ var newSnapshot = DataSourceSnapshot<Section, Item>()
+
+ if Account.shared.isLoggedIn {
+ newSnapshot.appendSections([.main])
+ newSnapshot.appendItems([.account, .preferences, .wireguardKey], in: .main)
+ }
+
+ newSnapshot.appendSections([.version, .problemReport])
+ newSnapshot.appendItems([.version], in: .version)
+ newSnapshot.appendItems([.problemReport], in: .problemReport)
+
+ snapshot = newSnapshot
+ }
+
+ // MARK: - UITableViewDataSource
+
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ let sectionIdentifier = snapshot.section(at: section)!
+
+ return snapshot.numberOfItems(in: sectionIdentifier) ?? 0
+ }
+
+ func numberOfSections(in tableView: UITableView) -> Int {
+ return snapshot.numberOfSections()
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let item = snapshot.itemForIndexPath(indexPath)!
+
+ switch item {
+ case .account:
+ let cell = tableView.dequeueReusableCell(withIdentifier: CellReuseIdentifiers.accountCell.rawValue, for: indexPath) as! SettingsAccountCell
+ cell.titleLabel.text = NSLocalizedString("ACCOUNT_CELL_LABEL", tableName: "Settings", value: "Account", comment: "")
+ cell.accountExpiryDate = Account.shared.expiry
+ cell.accessibilityIdentifier = "AccountCell"
+ cell.accessoryType = .disclosureIndicator
+
+ return cell
+
+ case .preferences:
+ let cell = tableView.dequeueReusableCell(withIdentifier: CellReuseIdentifiers.basicCell.rawValue, for: indexPath) as! SettingsCell
+ cell.titleLabel.text = NSLocalizedString("PREFERENCES_CELL_LABEL", tableName: "Settings", value: "Preferences", comment: "")
+ cell.detailTitleLabel.text = nil
+ cell.accessibilityIdentifier = nil
+ cell.accessoryType = .disclosureIndicator
+
+ return cell
+
+ case .wireguardKey:
+ let cell = tableView.dequeueReusableCell(withIdentifier: CellReuseIdentifiers.basicCell.rawValue, for: indexPath) as! SettingsCell
+ cell.titleLabel.text = NSLocalizedString("WIREGUARD_KEY_CELL_LABEL", tableName: "Settings", value: "WireGuard key", comment: "")
+ cell.detailTitleLabel.text = nil
+ cell.accessibilityIdentifier = "WireGuardKeyCell"
+ cell.accessoryType = .disclosureIndicator
+
+ return cell
+
+ case .version:
+ let cell = tableView.dequeueReusableCell(withIdentifier: CellReuseIdentifiers.basicCell.rawValue, for: indexPath) as! SettingsCell
+ cell.titleLabel.text = NSLocalizedString("APP_VERSION_CELL_LABEL", tableName: "Settings", value: "App version", comment: "")
+ cell.detailTitleLabel.text = Bundle.main.productVersion
+ cell.accessibilityIdentifier = nil
+ cell.accessoryType = .none
+
+ return cell
+
+ case .problemReport:
+ let cell = tableView.dequeueReusableCell(withIdentifier: CellReuseIdentifiers.basicCell.rawValue, for: indexPath) as! SettingsCell
+ cell.titleLabel.text = NSLocalizedString("REPORT_PROBLEM_CELL_LABEL", tableName: "Settings", value: "Report a problem", comment: "")
+ cell.detailTitleLabel.text = nil
+ cell.accessibilityIdentifier = nil
+ cell.accessoryType = .disclosureIndicator
+
+ return cell
+ }
+ }
+
+ // MARK: - UITableViewDelegate
+
+ func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
+ if case .version = snapshot.itemForIndexPath(indexPath) {
+ return false
+ } else {
+ return true
+ }
+ }
+
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ guard let item = snapshot.itemForIndexPath(indexPath) else { return }
+
+ delegate?.settingsDataSource(self, didSelectItem: item)
+ }
+
+ func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
+ return tableView.dequeueReusableHeaderFooterView(withIdentifier: HeaderFooterReuseIdentifier.spacer.rawValue)
+ }
+
+ func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
+ return nil
+ }
+
+ func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
+ return UIMetrics.sectionSpacing
+ }
+
+ func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
+ return 0
+ }
+
+ // MARK: - AccountObserver
+
+ func account(_ account: Account, didUpdateExpiry expiry: Date) {
+ tableView?.performBatchUpdates {
+ if let indexPath = snapshot.indexPathForItem(.version) {
+ tableView?.reloadRows(at: [indexPath], with: .none)
+ }
+ }
+ }
+
+ func account(_ account: Account, didLoginWithToken token: String, expiry: Date) {
+ updateDataSnapshot()
+ tableView?.reloadData()
+ }
+
+ func accountDidLogout(_ account: Account) {
+ updateDataSnapshot()
+ tableView?.reloadData()
+ }
+}
diff --git a/ios/MullvadVPN/SettingsDataSourceDelegate.swift b/ios/MullvadVPN/SettingsDataSourceDelegate.swift
new file mode 100644
index 0000000000..739c6d4552
--- /dev/null
+++ b/ios/MullvadVPN/SettingsDataSourceDelegate.swift
@@ -0,0 +1,13 @@
+//
+// SettingsDataSourceDelegate.swift
+// MullvadVPN
+//
+// Created by pronebird on 19/10/2021.
+// Copyright © 2021 Mullvad VPN AB. All rights reserved.
+//
+
+import UIKit
+
+protocol SettingsDataSourceDelegate: AnyObject {
+ func settingsDataSource(_ dataSource: SettingsDataSource, didSelectItem item: SettingsDataSource.Item)
+}
diff --git a/ios/MullvadVPN/SettingsViewController.swift b/ios/MullvadVPN/SettingsViewController.swift
index a2a7f91208..80bf44338a 100644
--- a/ios/MullvadVPN/SettingsViewController.swift
+++ b/ios/MullvadVPN/SettingsViewController.swift
@@ -13,23 +13,11 @@ protocol SettingsViewControllerDelegate: AnyObject {
func settingsViewControllerDidFinish(_ controller: SettingsViewController)
}
-class SettingsViewController: UITableViewController, AccountObserver {
+class SettingsViewController: UITableViewController, SettingsDataSourceDelegate {
weak var delegate: SettingsViewControllerDelegate?
- private enum CellIdentifier: String {
- case accountCell = "AccountCell"
- case basicCell = "BasicCell"
- }
-
- private let staticDataSource = SettingsTableViewDataSource()
-
- private weak var accountRow: StaticTableViewRow?
- private var accountExpiryObserver: NSObjectProtocol?
-
- private var settingsNavigationController: SettingsNavigationController? {
- return self.navigationController as? SettingsNavigationController
- }
+ private let dataSource = SettingsDataSource()
init() {
super.init(style: .grouped)
@@ -42,42 +30,17 @@ class SettingsViewController: UITableViewController, AccountObserver {
override func viewDidLoad() {
super.viewDidLoad()
- tableView.backgroundColor = .secondaryColor
- tableView.separatorColor = .secondaryColor
- tableView.rowHeight = UITableView.automaticDimension
- tableView.estimatedRowHeight = 60
- tableView.sectionHeaderHeight = UIMetrics.sectionSpacing
- tableView.sectionFooterHeight = 0
-
- tableView.dataSource = staticDataSource
- tableView.delegate = staticDataSource
-
- tableView.register(SettingsAccountCell.self, forCellReuseIdentifier: CellIdentifier.accountCell.rawValue)
- tableView.register(SettingsCell.self, forCellReuseIdentifier: CellIdentifier.basicCell.rawValue)
- tableView.register(EmptyTableViewHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: EmptyTableViewHeaderFooterView.reuseIdentifier)
-
navigationItem.title = NSLocalizedString("NAVIGATION_TITLE", tableName: "Settings", comment: "Navigation title")
navigationItem.largeTitleDisplayMode = .always
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(handleDismiss))
- Account.shared.addObserver(self)
- setupDataSource()
- }
-
- // MARK: - AccountObserver
-
- func account(_ account: Account, didUpdateExpiry expiry: Date) {
- guard let accountRow = accountRow else { return }
-
- staticDataSource.reloadRows([accountRow], with: .none)
- }
-
- func account(_ account: Account, didLoginWithToken token: String, expiry: Date) {
- // no-op
- }
+ tableView.backgroundColor = .secondaryColor
+ tableView.separatorColor = .secondaryColor
+ tableView.rowHeight = UITableView.automaticDimension
+ tableView.estimatedRowHeight = 60
- func accountDidLogout(_ account: Account) {
- // no-op
+ dataSource.tableView = tableView
+ dataSource.delegate = self
}
// MARK: - IBActions
@@ -86,88 +49,31 @@ class SettingsViewController: UITableViewController, AccountObserver {
delegate?.settingsViewControllerDidFinish(self)
}
- // MARK: - Private
+ // MARK: - SettingsDataSourceDelegate
- private func setupDataSource() {
- if Account.shared.isLoggedIn {
- let topSection = StaticTableViewSection()
- let accountRow = StaticTableViewRow(reuseIdentifier: CellIdentifier.accountCell.rawValue) { (_, cell) in
- let cell = cell as! SettingsAccountCell
+ func settingsDataSource(_ dataSource: SettingsDataSource, didSelectItem item: SettingsDataSource.Item) {
+ guard let route = item.navigationRoute else { return }
- cell.titleLabel.text = NSLocalizedString("ACCOUNT_CELL_LABEL", tableName: "Settings", comment: "")
- cell.accountExpiryDate = Account.shared.expiry
- cell.accessibilityIdentifier = "AccountCell"
- cell.accessoryType = .disclosureIndicator
- }
+ let settingsNavigationController = navigationController as? SettingsNavigationController
- accountRow.actionBlock = { [weak self] (indexPath) in
- self?.settingsNavigationController?.navigate(to: .account, animated: true)
- }
-
- let preferencesRow = StaticTableViewRow(reuseIdentifier: CellIdentifier.basicCell.rawValue) { (_, cell) in
- let cell = cell as! SettingsCell
- cell.titleLabel.text = NSLocalizedString("PREFERENCES_CELL_LABEL", tableName: "Settings", comment: "")
- cell.accessoryType = .disclosureIndicator
- }
-
- preferencesRow.actionBlock = { [weak self] (indexPath) in
- self?.settingsNavigationController?.navigate(to: .preferences, animated: true)
- }
-
- let wireguardKeyRow = StaticTableViewRow(reuseIdentifier: CellIdentifier.basicCell.rawValue) { (_, cell) in
- let cell = cell as! SettingsCell
-
- cell.titleLabel.text = NSLocalizedString("WIREGUARD_KEY_CELL_LABEL", tableName: "Settings", comment: "")
- cell.accessibilityIdentifier = "WireGuardKeyCell"
- cell.accessoryType = .disclosureIndicator
- }
-
- wireguardKeyRow.actionBlock = { [weak self] (indexPath) in
- self?.settingsNavigationController?.navigate(to: .wireguardKeys, animated: true)
- }
-
- self.accountRow = accountRow
-
- topSection.addRows([accountRow, preferencesRow, wireguardKeyRow])
- staticDataSource.addSections([topSection])
- }
-
- let middleSection = StaticTableViewSection()
- let versionRow = StaticTableViewRow(reuseIdentifier: CellIdentifier.basicCell.rawValue) { (_, cell) in
- let cell = cell as! SettingsCell
- cell.titleLabel.text = NSLocalizedString("APP_VERSION_CELL_LABEL", tableName: "Settings", comment: "")
- cell.detailTitleLabel.text = Bundle.main.productVersion
- }
- versionRow.isSelectable = false
-
- middleSection.addRows([versionRow])
- staticDataSource.addSections([middleSection])
-
- let bottomSection = StaticTableViewSection()
-
- let problemReportRow = StaticTableViewRow(reuseIdentifier: CellIdentifier.basicCell.rawValue) { (indexPath, cell) in
- let cell = cell as! SettingsCell
-
- cell.titleLabel.text = NSLocalizedString("REPORT_PROBLEM_CELL_LABEL", tableName: "Settings", comment: "")
- cell.accessoryType = .disclosureIndicator
- }
-
- problemReportRow.actionBlock = { [weak self] (indexPath) in
- self?.settingsNavigationController?.navigate(to: .problemReport, animated: true)
- }
-
- bottomSection.addRows([problemReportRow])
- staticDataSource.addSections([bottomSection])
+ settingsNavigationController?.navigate(to: route, animated: true)
}
}
-class SettingsTableViewDataSource: StaticTableViewDataSource {
-
- // MARK: - UITableViewDelegate
-
- func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
- return tableView.dequeueReusableHeaderFooterView(withIdentifier: EmptyTableViewHeaderFooterView.reuseIdentifier)
+extension SettingsDataSource.Item {
+ var navigationRoute: SettingsNavigationRoute? {
+ switch self {
+ case .account:
+ return .account
+ case .preferences:
+ return .preferences
+ case .wireguardKey:
+ return .wireguardKeys
+ case .version:
+ return nil
+ case .problemReport:
+ return .problemReport
+ }
}
-
}
diff --git a/ios/MullvadVPN/StaticTableViewDataSource.swift b/ios/MullvadVPN/StaticTableViewDataSource.swift
deleted file mode 100644
index 36cef2adaa..0000000000
--- a/ios/MullvadVPN/StaticTableViewDataSource.swift
+++ /dev/null
@@ -1,127 +0,0 @@
-//
-// StaticTableViewDataSource.swift
-// MullvadVPN
-//
-// Created by pronebird on 24/05/2019.
-// Copyright © 2019 Mullvad VPN AB. All rights reserved.
-//
-
-import UIKit
-
-class StaticTableViewRow {
- typealias ConfigurationBlock = (IndexPath, UITableViewCell) -> Void
- typealias ActionBlock = (IndexPath) -> Void
-
- let reuseIdentifier: String
- let configurationBlock: ConfigurationBlock
-
- var isSelectable = true
- var isHidden = false
- var actionBlock: ActionBlock?
-
- init(reuseIdentifier: String, configurationBlock: @escaping ConfigurationBlock) {
- self.reuseIdentifier = reuseIdentifier
- self.configurationBlock = configurationBlock
- }
-}
-
-class StaticTableViewSection {
- private(set) var rows = [StaticTableViewRow]()
-
- var isHidden: Bool {
- return rows.allSatisfy({ $0.isHidden })
- }
-
- func addRows(_ rows: [StaticTableViewRow]) {
- self.rows.append(contentsOf: rows)
- }
-}
-
-class StaticTableViewDataSource: NSObject, UITableViewDataSource, UITableViewDelegate {
-
- @IBOutlet weak var tableView: UITableView?
-
- private(set) var sections = [StaticTableViewSection]()
-
- func addSections(_ sections: [StaticTableViewSection]) {
- self.sections.append(contentsOf: sections)
- }
-
- func reloadRows(_ rows: [StaticTableViewRow], with animation: UITableView.RowAnimation) {
- let indexPaths = rows.compactMap { indexPathForRow($0) }
-
- tableView?.reloadRows(at: indexPaths, with: animation)
- }
-
- func indexPathForRow(_ searchRow: StaticTableViewRow) -> IndexPath? {
- var sectionIndex = 0
-
- for section in sections {
- let visibleRows = section.rows.filter { !$0.isHidden }
-
- // skip incrementing the section index since invisible sections are normally collapsed
- guard visibleRows.count > 0 else {
- continue
- }
-
- if let rowIndex = visibleRows.firstIndex(where: { $0 === searchRow }) {
- return IndexPath(row: rowIndex, section: sectionIndex)
- }
-
- sectionIndex += 1
- }
-
- return nil
- }
-
- // MARK: - UITableViewDelegate
-
- func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
- let row = self.row(for: indexPath)
-
- return row.isSelectable
- }
-
- // MARK: - UITableViewDataSource
-
- func numberOfSections(in tableView: UITableView) -> Int {
- return sections.reduce(0, { $1.isHidden ? $0 : $0 + 1 })
- }
-
- func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- return sections[section].rows.count
- }
-
- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- let row = self.row(for: indexPath)
- let reuseIdentifier = row.reuseIdentifier
-
- let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath)
-
- row.configurationBlock(indexPath, cell)
-
- return cell
- }
-
- func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- let row = self.row(for: indexPath)
-
- row.actionBlock?(indexPath)
- }
-
- // MARK: - Private
-
- private func row(for indexPath: IndexPath) -> StaticTableViewRow {
- let section = self.section(for: indexPath)
- let row = section.rows.compactMap({ $0.isHidden ? nil : $0 })
-
- return row[indexPath.row]
- }
-
- private func section(for indexPath: IndexPath) -> StaticTableViewSection {
- let visibleSections = sections.compactMap({ $0.isHidden ? nil : $0 })
-
- return visibleSections[indexPath.section]
- }
-
-}