1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
//
// CustomDNSViewController.swift
// MullvadVPN
//
// Created by Jon Petersson on 2023-11-09.
// Copyright © 2025 Mullvad VPN AB. All rights reserved.
//
import MullvadSettings
import UIKit
class CustomDNSViewController: UITableViewController {
private let interactor: VPNSettingsInteractor
private var dataSource: CustomDNSDataSource?
private let alertPresenter: AlertPresenter
override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
init(interactor: VPNSettingsInteractor, alertPresenter: AlertPresenter) {
self.interactor = interactor
self.alertPresenter = alertPresenter
super.init(style: .grouped)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.setAccessibilityIdentifier(.dnsSettingsTableView)
tableView.backgroundColor = .secondaryColor
tableView.separatorColor = .secondaryColor
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 60
tableView.estimatedSectionHeaderHeight = tableView.estimatedRowHeight
dataSource = CustomDNSDataSource(tableView: tableView)
dataSource?.delegate = self
navigationItem.title = NSLocalizedString("DNS settings", comment: "")
if navigationItem.rightBarButtonItem != nil {
navigationItem.leftBarButtonItem = editButtonItem
navigationItem.leftBarButtonItem?.setAccessibilityIdentifier(.dnsSettingsEditButton)
} else {
navigationItem.rightBarButtonItem = editButtonItem
navigationItem.rightBarButtonItem?.setAccessibilityIdentifier(.dnsSettingsEditButton)
}
interactor.tunnelSettingsDidChange = { [weak self] newSettings in
self?.dataSource?.update(from: newSettings)
}
dataSource?.update(from: interactor.tunnelSettings)
tableView.tableHeaderView = UIView(
frame: CGRect(
origin: .zero,
size: CGSize(width: 0, height: UIMetrics.TableView.emptyHeaderHeight)
))
}
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
dataSource?.setEditing(editing, animated: animated)
navigationItem.setHidesBackButton(editing, animated: animated)
if navigationItem.rightBarButtonItem != editButtonItem {
if #available(iOS 16.0, *) {
navigationItem.rightBarButtonItem?.isHidden = editing
} else {
navigationItem.rightBarButtonItem?.isEnabled = !editing
}
}
// Disable swipe to dismiss when editing
isModalInPresentation = editing
}
private func showInfo(with message: NSAttributedString) {
let presentation = AlertPresentation(
id: "vpn-settings-content-blockers-alert",
icon: .info,
attributedMessage: message,
buttons: [
AlertAction(
title: NSLocalizedString("Got it!", comment: ""),
style: .default
)
]
)
alertPresenter.showAlert(presentation: presentation, animated: true)
}
}
extension CustomDNSViewController: @preconcurrency DNSSettingsDataSourceDelegate {
func didChangeViewModel(_ viewModel: VPNSettingsViewModel) {
interactor.updateSettings([.dnsSettings(viewModel.asDNSSettings())])
}
func showInfo(for item: VPNSettingsInfoButtonItem) {
showInfo(
with: NSAttributedString(
markdownString: item.description,
options: MarkdownStylingOptions(font: .preferredFont(forTextStyle: .body))
))
}
}
|