Privacy: Auto-delete logs (no functionality yet)
This commit is contained in:
@@ -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 */,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
77
main/Common Classes/Prefs.swift
Normal file
77
main/Common Classes/Prefs.swift
Normal 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;
|
||||
}
|
||||
15
main/Common Classes/PrefsShared.swift
Normal file
15
main/Common Classes/PrefsShared.swift
Normal 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() }
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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])"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user