Files
appchk-app/main/Settings/TVCSettings.swift

226 lines
7.3 KiB
Swift

import UIKit
class TVCSettings: UITableViewController {
@IBOutlet var vpnToggle: UISwitch!
@IBOutlet var unresolvableToggle: UISwitch!
@IBOutlet var swcdToggle: UISwitch!
@IBOutlet var cellDomainsIgnored: UITableViewCell!
@IBOutlet var cellDomainsBlocked: UITableViewCell!
@IBOutlet var cellPrivacyAutoDelete: UITableViewCell!
@IBOutlet var cellNotificationReminder: UITableViewCell!
@IBOutlet var cellNotificationConnectionAlert: UITableViewCell!
override func viewDidLoad() {
super.viewDidLoad()
reloadVPNState()
reloadLoggingFilterUI()
reloadPrivacyUI()
reloadAdvancedUI()
NotifyVPNStateChanged.observe(call: #selector(reloadVPNState), on: self)
NotifyDNSFilterChanged.observe(call: #selector(reloadLoggingFilterUI), on: self)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
reloadNotificationState()
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// FIXME: there is a lag between tap and open when run on device
if let cell = tableView.cellForRow(at: indexPath), cell === cellPrivacyAutoDelete {
openAutoDeletePicker()
}
}
func openRestartVPNSettings() { scrollToSection(0, animated: false) }
func openNotificationSettings() { scrollToSection(2, animated: false) }
private func scrollToSection(_ section: Int, animated: Bool) {
tableView.scrollToRow(at: .init(row: 0, section: section), at: .top, animated: animated)
}
}
// MARK: - VPN Proxy Settings
extension TVCSettings {
@objc private func reloadVPNState() {
vpnToggle.isOn = (GlassVPN.state != .off)
vpnToggle.onTintColor = (GlassVPN.state == .inbetween ? .systemYellow : nil)
UIApplication.shared.applicationIconBadgeNumber =
!vpnToggle.isOn &&
PrefsShared.RestartReminder.Enabled &&
PrefsShared.RestartReminder.WithBadge ? 1 : 0
}
@IBAction private func toggleVPNProxy(_ sender: UISwitch) {
GlassVPN.setEnabled(sender.isOn)
}
}
// MARK: - Logging Filter
extension TVCSettings {
@objc private func reloadLoggingFilterUI() {
let (blocked, ignored, _, _) = DomainFilter.counts()
cellDomainsIgnored.detailTextLabel?.text = "\(ignored) Domains"
cellDomainsBlocked.detailTextLabel?.text = "\(blocked) Domains"
}
override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
let t:String, d: String
switch tableView.cellForRow(at: indexPath)?.reuseIdentifier {
case "settingsIgnoredCell":
t = "Ignored Domains"
d = "Ignored domains won't show up in session recordings nor in the requests overview. Requests to ignored domains are not logged."
case "settingsBlockedCell":
t = "Blocked Domains"
d = "Blocked domains prohibit all requests to that domain. Unless a domain is also ignored, the request will be logged and appear in session recordings and the requests overview."
default: return
}
Alert(title: t, text: d).presentIn(self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let dest = (segue.destination as? TVCFilter) else { return }
switch segue.identifier {
case "segueFilterIgnored":
dest.navigationItem.title = "Ignored Domains"
dest.currentFilter = .ignored
case "segueFilterBlocked":
dest.navigationItem.title = "Blocked Domains"
dest.currentFilter = .blocked
default:
break
}
}
}
// MARK: - Privacy
extension TVCSettings {
private func reloadPrivacyUI() {
let (num, unit) = getAutoDeleteSelection([1, 7, 31])
let str: String
switch num {
case 0: str = "Never"
case 1: str = "1 \(["Day", "Week", "Month"][unit])"
default: str = "\(num) \(["Days", "Weeks", "Months"][unit])"
}
cellPrivacyAutoDelete.detailTextLabel?.text = str
}
private func getAutoDeleteSelection(_ multiplier: [Int]) -> (Int, Int) {
let current = PrefsShared.AutoDeleteLogsDays
let snd = multiplier.lastIndex { current % $0 == 0 }! // make sure 1 is in list
return (current / multiplier[snd], snd)
}
private func openAutoDeletePicker() {
let multiplier = [1, 7, 31]
let (one, two) = getAutoDeleteSelection(multiplier)
let picker = DurationPickerAlert(
title: "Auto-delete logs",
detail: "Warning: Logs older than the selected interval are deleted immediately! " +
"Logs are also deleted on each app launch, and periodically in the background as long as the VPN is running.",
options: [(0...30).map{"\($0)"}, ["Days", "Weeks", "Months"]],
widths: [0.4, 0.6])
picker.pickerView.setSelection([min(30, one), two])
picker.present(in: self) { _, idx in
let asDays = idx[0] * multiplier[idx[1]]
PrefsShared.AutoDeleteLogsDays = asDays
self.reloadPrivacyUI()
if !GlassVPN.send(.autoDelete(after: asDays)) {
// if VPN isn't active, fallback to immediate local delete
TheGreatDestroyer.deleteLogs(olderThan: asDays)
}
}
}
}
// MARK: - Notification Settings
extension TVCSettings {
private func reloadNotificationState() {
let lbl1 = cellNotificationReminder.detailTextLabel
let lbl2 = cellNotificationConnectionAlert.detailTextLabel
readNotificationState { (realAllowed, provisional) in
lbl1?.text = provisional ? "Enabled" : "Disabled"
lbl2?.text = realAllowed ? "Enabled" : "Disabled"
}
}
private func readNotificationState(_ closure: @escaping (_ all: Bool, _ prov: Bool) -> Void) {
let en1 = PrefsShared.ConnectionAlerts.Enabled
let en2 = Prefs.RecordingReminder.Enabled || PrefsShared.RestartReminder.Enabled
closure(en1, en2)
guard en1 || en2 else { return }
PushNotification.allowed { state in
switch state {
case .NotDetermined, .Denied: closure(false, false)
case .Authorized: closure(en1, en2)
case .Provisional: closure(false, en2)
}
}
}
}
// MARK: - Reset Settings
extension TVCSettings {
@IBAction private func resetTutorialAlerts(_ sender: UIButton) {
Prefs.DidShowTutorial.Welcome = false
Prefs.DidShowTutorial.Recordings = false
Alert(title: sender.titleLabel?.text,
text: "\nDone.\n\nYou may need to restart the application.").presentIn(self)
}
@IBAction private func clearDatabaseResults() {
AskAlert(title: "Clear results?", text:
"You are about to delete all results that have been logged in the past. " +
"Your preferences for blocked and ignored domains are preserved.\n" +
"Continue?", buttonText: "Delete", buttonStyle: .destructive) { _ in
TheGreatDestroyer.deleteAllLogs()
}.presentIn(self)
}
}
// MARK: - Advanced
extension TVCSettings {
private func reloadAdvancedUI() {
unresolvableToggle.isOn = PrefsShared.ForceDisconnectUnresolvableDNS
swcdToggle.isOn = PrefsShared.ForceDisconnectSWCD
}
@IBAction private func togglePreventUnresolvable(_ sender: UISwitch) {
PrefsShared.ForceDisconnectUnresolvableDNS = sender.isOn
GlassVPN.send(.disconnectUnresolvable(sender.isOn))
}
@IBAction private func togglePreventSWCD(_ sender: UISwitch) {
PrefsShared.ForceDisconnectSWCD = sender.isOn
GlassVPN.send(.disconnectSWCD(sender.isOn))
}
@IBAction private func exportDB() {
AppDB?.vacuum()
let sheet = UIActivityViewController(activityItems: [URL.internalDB()], applicationActivities: nil)
self.present(sheet, animated: true)
}
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
if section == tableView.numberOfSections - 1 {
let fs = FileManager.default.readableSizeOf(path: URL.internalDB().relativePath)
return "Database size: \(fs ?? "0 MB")"
}
return nil
}
}