Privacy: Auto-delete logs (no functionality yet)

This commit is contained in:
relikd
2020-06-28 14:20:31 +02:00
parent 43de81929f
commit 80afa6aff1
8 changed files with 231 additions and 120 deletions

View File

@@ -141,6 +141,8 @@
54E540F4247D3F2600F7C34A /* TestDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E540F3247D3F2600F7C34A /* TestDataSource.swift */; };
54E540F8247DB90F00F7C34A /* RecordingsDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E540F7247DB90F00F7C34A /* RecordingsDB.swift */; };
54E540FA2482414800F7C34A /* SyncUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E540F92482414800F7C34A /* SyncUpdate.swift */; };
54E67E4624A8B0FE0025D261 /* PrefsShared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E67E4524A8B0FE0025D261 /* PrefsShared.swift */; };
54E67E4924A8B1280025D261 /* Prefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E67E4824A8B1280025D261 /* Prefs.swift */; };
54EFA4E82491A16A0022D618 /* Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54EFA4E72491A16A0022D618 /* Font.swift */; };
/* End PBXBuildFile section */
@@ -308,6 +310,8 @@
54E540F3247D3F2600F7C34A /* TestDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestDataSource.swift; sourceTree = "<group>"; };
54E540F7247DB90F00F7C34A /* RecordingsDB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordingsDB.swift; sourceTree = "<group>"; };
54E540F92482414800F7C34A /* SyncUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncUpdate.swift; sourceTree = "<group>"; };
54E67E4524A8B0FE0025D261 /* PrefsShared.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefsShared.swift; sourceTree = "<group>"; };
54E67E4824A8B1280025D261 /* Prefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Prefs.swift; sourceTree = "<group>"; };
54EFA4E72491A16A0022D618 /* Font.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Font.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -438,6 +442,8 @@
545DDDD224436A03003B6544 /* Common Classes */ = {
isa = PBXGroup;
children = (
54E67E4824A8B1280025D261 /* Prefs.swift */,
54E67E4524A8B0FE0025D261 /* PrefsShared.swift */,
545DDDD024436983003B6544 /* QuickUI.swift */,
545DDDCE243E6267003B6544 /* TutorialSheet.swift */,
54D8B979246C9F2000EB2414 /* FilterPipeline.swift */,
@@ -840,6 +846,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
54E67E4924A8B1280025D261 /* Prefs.swift in Sources */,
54E540F8247DB90F00F7C34A /* RecordingsDB.swift in Sources */,
54E540F4247D3F2600F7C34A /* TestDataSource.swift in Sources */,
545DDDD424466D37003B6544 /* AutoLayout.swift in Sources */,
@@ -859,6 +866,7 @@
54B34596240F0513004C53CC /* TableView.swift in Sources */,
540E6780242D2CF100871BBE /* VCRecordings.swift in Sources */,
54953E3323DC752E0054345C /* DBCore.swift in Sources */,
54E67E4624A8B0FE0025D261 /* PrefsShared.swift in Sources */,
544F912024A67EC5001D4B00 /* TVCOccurrenceContext.swift in Sources */,
54448A30248647D900771C96 /* Time.swift in Sources */,
54953E6123E0D69A0054345C /* TVCHosts.swift in Sources */,

View File

@@ -1207,10 +1207,38 @@ Duration: 60:00</string>
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection headerTitle="Privacy" id="wLR-T2-Qxm">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="8gD-At-D8n" detailTextLabel="Yy4-Ip-Wdv" style="IBUITableViewCellStyleValue1" id="Qyy-0U-yhd">
<rect key="frame" x="0.0" y="299.5" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Qyy-0U-yhd" id="Mfs-fu-W5k">
<rect key="frame" x="0.0" y="0.0" width="293" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Auto-delete logs" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8gD-At-D8n">
<rect key="frame" x="16" y="14" width="114" height="18"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Never" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Yy4-Ip-Wdv">
<rect key="frame" x="239.5" y="12" width="45.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection headerTitle="Reset Settings" id="tBs-BI-JqN">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="Uii-Jp-53c">
<rect key="frame" x="0.0" y="299.5" width="320" height="44"/>
<rect key="frame" x="0.0" y="399.5" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Uii-Jp-53c" id="4Fp-Ox-yrk">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
@@ -1232,7 +1260,7 @@ Duration: 60:00</string>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="Xgc-6Z-IlH">
<rect key="frame" x="0.0" y="343.5" width="320" height="44"/>
<rect key="frame" x="0.0" y="443.5" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Xgc-6Z-IlH" id="efR-vn-6MX">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
@@ -1245,7 +1273,7 @@ Duration: 60:00</string>
<color key="titleColor" systemColor="systemRedColor" red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="clearDatabaseResults:" destination="qdB-ZO-LHY" eventType="touchUpInside" id="adR-Yk-zsB"/>
<action selector="clearDatabaseResults" destination="qdB-ZO-LHY" eventType="touchUpInside" id="heU-m1-oJq"/>
</connections>
</button>
</subviews>
@@ -1257,27 +1285,27 @@ Duration: 60:00</string>
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection headerTitle="Advanced" id="wLR-T2-Qxm">
<tableViewSection headerTitle="Advanced" id="Vlg-nm-VB3">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="Qyy-0U-yhd">
<rect key="frame" x="0.0" y="443.5" width="320" height="44"/>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="VnR-9B-1zl">
<rect key="frame" x="0.0" y="543.5" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Qyy-0U-yhd" id="Mfs-fu-W5k">
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VnR-9B-1zl" id="ZTz-vZ-l5p">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9Ko-sD-7x0">
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="twS-Ne-dU0">
<rect key="frame" x="125" y="7" width="70" height="30"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
<state key="normal" title="Export DB"/>
<connections>
<action selector="exportDB:" destination="qdB-ZO-LHY" eventType="touchUpInside" id="3gu-WF-3Xa"/>
<action selector="exportDB" destination="qdB-ZO-LHY" eventType="touchUpInside" id="FYN-Zz-UK4"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="9Ko-sD-7x0" firstAttribute="centerX" secondItem="Mfs-fu-W5k" secondAttribute="centerX" id="LzG-xg-XTg"/>
<constraint firstItem="9Ko-sD-7x0" firstAttribute="centerY" secondItem="Mfs-fu-W5k" secondAttribute="centerY" id="SXw-dC-2kl"/>
<constraint firstItem="twS-Ne-dU0" firstAttribute="centerY" secondItem="ZTz-vZ-l5p" secondAttribute="centerY" id="LgK-8q-r6K"/>
<constraint firstItem="twS-Ne-dU0" firstAttribute="centerX" secondItem="ZTz-vZ-l5p" secondAttribute="centerX" id="ltC-Ba-Bxr"/>
</constraints>
</tableViewCellContentView>
</tableViewCell>
@@ -1293,6 +1321,7 @@ Duration: 60:00</string>
<connections>
<outlet property="cellDomainsBlocked" destination="3pw-7c-M6R" id="AHT-FE-z0s"/>
<outlet property="cellDomainsIgnored" destination="fZR-we-Y0k" id="Huy-N3-gz7"/>
<outlet property="cellPrivacyAutoDelete" destination="Qyy-0U-yhd" id="PzN-iv-kFl"/>
<outlet property="vpnToggle" destination="kmY-ot-lJW" id="yeS-DE-FfR"/>
</connections>
</tableViewController>

View File

@@ -166,9 +166,9 @@ class DatePickerAlert : CustomAlert<UIDatePicker> {
datePicker.date = Date()
}
func present(in viewController: UIViewController, onSuccess: @escaping (Date) -> Void) {
func present(in viewController: UIViewController, onSuccess: @escaping (UIDatePicker, Date) -> Void) {
super.present(in: viewController) {
onSuccess($0.date)
onSuccess($0, $0.date)
}
}
}
@@ -219,9 +219,9 @@ class DurationPickerAlert: CustomAlert<UIPickerView>, UIPickerViewDataSource, UI
compWidths[c] * pickerView.frame.width
}
func present(in viewController: UIViewController, onSuccess: @escaping ([Int]) -> Void) {
func present(in viewController: UIViewController, onSuccess: @escaping (UIPickerView, [Int]) -> Void) {
super.present(in: viewController) {
onSuccess($0.selection)
onSuccess($0, $0.selection)
}
}
}

View File

@@ -0,0 +1,77 @@
import Foundation
enum Pref {
static func Int(_ key: String) -> Int { UserDefaults.standard.integer(forKey: key) }
static func Int(_ val: Int, _ key: String) { UserDefaults.standard.set(val, forKey: key) }
static func Bool(_ key: String) -> Bool { UserDefaults.standard.bool(forKey: key) }
static func Bool(_ val: Bool, _ key: String) { UserDefaults.standard.set(val, forKey: key) }
static func `Any`(_ key: String) -> Any? { UserDefaults.standard.object(forKey: key) }
static func `Any`(_ val: Any?, _ key: String) { UserDefaults.standard.set(val, forKey: key) }
enum DidShowTutorial {
static var Welcome: Bool {
get { Pref.Bool("didShowTutorialAppWelcome") }
set { Pref.Bool(newValue, "didShowTutorialAppWelcome") }
}
static var Recordings: Bool {
get { Pref.Bool("didShowTutorialRecordings") }
set { Pref.Bool(newValue, "didShowTutorialRecordings") }
}
}
enum ContextAnalyis {
static var CoOccurrenceTime: Int? {
get { Pref.Any("contextAnalyisCoOccurrenceTime") as? Int }
set { Pref.Any(newValue, "contextAnalyisCoOccurrenceTime") }
}
}
enum DateFilter {
static var Kind: DateFilterKind {
get { DateFilterKind(rawValue: Pref.Int("dateFilterType"))! }
set { Pref.Int(newValue.rawValue, "dateFilterType") }
}
/// Default: `0` (disabled)
static var LastXMin: Int {
get { Pref.Int("dateFilterLastXMin") }
set { Pref.Int(newValue, "dateFilterLastXMin") }
}
/// Default: `nil` (disabled)
static var RangeA: Timestamp? {
get { Pref.Any("dateFilterRangeA") as? Timestamp }
set { Pref.Any(newValue, "dateFilterRangeA") }
}
/// Default: `nil` (disabled)
static var RangeB: Timestamp? {
get { Pref.Any("dateFilterRangeB") as? Timestamp }
set { Pref.Any(newValue, "dateFilterRangeB") }
}
/// default: `.Date`
static var OrderBy: DateFilterOrderBy {
get { DateFilterOrderBy(rawValue: Pref.Int("dateFilterOderType"))! }
set { Pref.Int(newValue.rawValue, "dateFilterOderType") }
}
/// default: `false` (Desc)
static var OrderAsc: Bool {
get { Pref.Bool("dateFilterOderAsc") }
set { Pref.Bool(newValue, "dateFilterOderAsc") }
}
/// - Returns: Timestamp restriction depending on current selected date filter.
/// - `Off` : `(nil, nil)`
/// - `LastXMin` : `(now-LastXMin, nil)`
/// - `ABRange` : `(RangeA, RangeB)`
static func restrictions() -> (type: DateFilterKind, earliest: Timestamp?, latest: Timestamp?) {
let type = Kind
switch type {
case .Off: return (type, nil, nil)
case .LastXMin: return (type, Timestamp.past(minutes: Pref.DateFilter.LastXMin), nil)
case .ABRange: return (type, Pref.DateFilter.RangeA, Pref.DateFilter.RangeB)
}
}
}
}
enum DateFilterKind: Int {
case Off = 0, LastXMin = 1, ABRange = 2;
}
enum DateFilterOrderBy: Int {
case Date = 0, Name = 1, Count = 2;
}

View File

@@ -0,0 +1,15 @@
import Foundation
enum PrefsShared {
private static var suite: UserDefaults { UserDefaults(suiteName: "group.de.uni-bamberg.psi.AppCheck")! }
private static func Int(_ key: String) -> Int { suite.integer(forKey: key) }
private static func Int(_ val: Int, _ key: String) { suite.set(val, forKey: key) }
// private static func Obj(_ key: String) -> Any? { suite.object(forKey: key) }
// private static func Obj(_ val: Any?, _ key: String) { suite.set(val, forKey: key) }
static var AutoDeleteLogsDays: Int {
get { Int("AutoDeleteLogsDays") }
set { Int(newValue, "AutoDeleteLogsDays"); suite.synchronize() }
}
}

View File

@@ -6,79 +6,3 @@ let sync = SyncUpdate(periodic: 7)
public enum VPNState : Int {
case on = 1, inbetween, off
}
enum Pref {
static func Int(_ key: String) -> Int { UserDefaults.standard.integer(forKey: key) }
static func Int(_ val: Int, _ key: String) { UserDefaults.standard.set(val, forKey: key) }
static func Bool(_ key: String) -> Bool { UserDefaults.standard.bool(forKey: key) }
static func Bool(_ val: Bool, _ key: String) { UserDefaults.standard.set(val, forKey: key) }
static func `Any`(_ key: String) -> Any? { UserDefaults.standard.object(forKey: key) }
static func `Any`(_ val: Any?, _ key: String) { UserDefaults.standard.set(val, forKey: key) }
enum DidShowTutorial {
static var Welcome: Bool {
get { Pref.Bool("didShowTutorialAppWelcome") }
set { Pref.Bool(newValue, "didShowTutorialAppWelcome") }
}
static var Recordings: Bool {
get { Pref.Bool("didShowTutorialRecordings") }
set { Pref.Bool(newValue, "didShowTutorialRecordings") }
}
}
enum ContextAnalyis {
static var CoOccurrenceTime: Int? {
get { Pref.Any("contextAnalyisCoOccurrenceTime") as? Int }
set { Pref.Any(newValue, "contextAnalyisCoOccurrenceTime") }
}
}
enum DateFilter {
static var Kind: DateFilterKind {
get { DateFilterKind(rawValue: Pref.Int("dateFilterType"))! }
set { Pref.Int(newValue.rawValue, "dateFilterType") }
}
/// Default: `0` (disabled)
static var LastXMin: Int {
get { Pref.Int("dateFilterLastXMin") }
set { Pref.Int(newValue, "dateFilterLastXMin") }
}
/// Default: `nil` (disabled)
static var RangeA: Timestamp? {
get { Pref.Any("dateFilterRangeA") as? Timestamp }
set { Pref.Any(newValue, "dateFilterRangeA") }
}
/// Default: `nil` (disabled)
static var RangeB: Timestamp? {
get { Pref.Any("dateFilterRangeB") as? Timestamp }
set { Pref.Any(newValue, "dateFilterRangeB") }
}
/// default: `.Date`
static var OrderBy: DateFilterOrderBy {
get { DateFilterOrderBy(rawValue: Pref.Int("dateFilterOderType"))! }
set { Pref.Int(newValue.rawValue, "dateFilterOderType") }
}
/// default: `false` (Desc)
static var OrderAsc: Bool {
get { Pref.Bool("dateFilterOderAsc") }
set { Pref.Bool(newValue, "dateFilterOderAsc") }
}
/// - Returns: Timestamp restriction depending on current selected date filter.
/// - `Off` : `(nil, nil)`
/// - `LastXMin` : `(now-LastXMin, nil)`
/// - `ABRange` : `(RangeA, RangeB)`
static func restrictions() -> (type: DateFilterKind, earliest: Timestamp?, latest: Timestamp?) {
let type = Kind
switch type {
case .Off: return (type, nil, nil)
case .LastXMin: return (type, Timestamp.past(minutes: Pref.DateFilter.LastXMin), nil)
case .ABRange: return (type, Pref.DateFilter.RangeA, Pref.DateFilter.RangeB)
}
}
}
}
enum DateFilterKind: Int {
case Off = 0, LastXMin = 1, ABRange = 2;
}
enum DateFilterOrderBy: Int {
case Date = 0, Name = 1, Count = 2;
}

View File

@@ -64,8 +64,8 @@ class VCDateFilter: UIViewController, UIGestureRecognizerDelegate {
@IBAction private func didTapRangeButton(_ sender: UIButton) {
let flag = (sender == buttonRangeStart)
let oldDate = flag ? Date(self.tsRangeA) : Date(self.tsRangeB)
DatePickerAlert(initial: oldDate).present(in: self) { (selected: Date) in
var ts = selected.timestamp
DatePickerAlert(initial: oldDate).present(in: self) {
var ts = $1.timestamp
ts -= ts % 60 // remove seconds
// if one of these is greater than the other, adjust the latter too.
if flag || self.tsRangeA > ts {

View File

@@ -6,6 +6,7 @@ class TVCSettings: UITableViewController {
@IBOutlet var vpnToggle: UISwitch!
@IBOutlet var cellDomainsIgnored: UITableViewCell!
@IBOutlet var cellDomainsBlocked: UITableViewCell!
@IBOutlet var cellPrivacyAutoDelete: UITableViewCell!
override func viewDidLoad() {
super.viewDidLoad()
@@ -15,37 +16,13 @@ class TVCSettings: UITableViewController {
reloadDataSource()
}
@objc func reloadDataSource() {
let (blocked, ignored) = DomainFilter.counts()
cellDomainsIgnored.detailTextLabel?.text = "\(ignored) Domains"
cellDomainsBlocked.detailTextLabel?.text = "\(blocked) Domains"
}
@IBAction func toggleVPNProxy(_ sender: UISwitch) {
// MARK: - VPN Proxy Settings
@IBAction private func toggleVPNProxy(_ sender: UISwitch) {
appDelegate.setProxyEnabled(sender.isOn)
}
@IBAction func exportDB(_ sender: Any) {
let sheet = UIActivityViewController(activityItems: [URL.internalDB()], applicationActivities: nil)
self.present(sheet, animated: true)
}
@IBAction func resetTutorialAlerts(_ sender: UIButton) {
Pref.DidShowTutorial.Welcome = false
Pref.DidShowTutorial.Recordings = false
Alert(title: sender.titleLabel?.text,
text: "\nDone.\n\nYou may need to restart the application.").presentIn(self)
}
@IBAction func clearDatabaseResults(_ sender: Any) {
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)
}
@objc func vpnStateChanged(_ notification: Notification) {
changedState(notification.object as! VPNState)
}
@@ -55,6 +32,17 @@ class TVCSettings: UITableViewController {
vpnToggle.onTintColor = (newState == .inbetween ? .systemYellow : nil)
}
// MARK: - Logging Filter
@objc func reloadDataSource() {
let (blocked, ignored) = DomainFilter.counts()
cellDomainsIgnored.detailTextLabel?.text = "\(ignored) Domains"
cellDomainsBlocked.detailTextLabel?.text = "\(blocked) Domains"
let (one, two) = autoDeleteSelection([1, 7, 31])
cellPrivacyAutoDelete.detailTextLabel?.text = autoDeleteString(one, unit: two)
}
override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
let t:String, d: String
switch tableView.cellForRow(at: indexPath)?.reuseIdentifier {
@@ -82,4 +70,74 @@ class TVCSettings: UITableViewController {
break
}
}
// MARK: - Privacy
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath), cell === cellPrivacyAutoDelete {
let multiplier = [1, 7, 31]
let (one, two) = autoDeleteSelection(multiplier)
let picker = DurationPickerAlert(
title: "Auto-delete logs",
detail: "Logs will be deleted on app launch or periodically 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) {
PrefsShared.AutoDeleteLogsDays = $1[0] * multiplier[$1[1]]
cell.detailTextLabel?.text = autoDeleteString($1[0], unit: $1[1])
// TODO: notify VPN and local delete timer
}
}
}
// MARK: - Reset Settings
@IBAction private func resetTutorialAlerts(_ sender: UIButton) {
Pref.DidShowTutorial.Welcome = false
Pref.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
@IBAction private func exportDB() {
let sheet = UIActivityViewController(activityItems: [URL.internalDB()], applicationActivities: nil)
self.present(sheet, animated: true)
}
}
// -------------------------------
// |
// | MARK: - Helper methods
// |
// -------------------------------
private func autoDeleteSelection(_ 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 autoDeleteString(_ num: Int, unit: Int) -> String {
switch num {
case 0: return "Never"
case 1: return "1 \(["Day", "Week", "Month"][unit])"
default: return "\(num) \(["Days", "Weeks", "Months"][unit])"
}
}