mirror of
https://github.com/confirmedcode/Lockdown-iOS.git
synced 2025-12-21 12:14:02 +01:00
218 lines
6.9 KiB
Swift
218 lines
6.9 KiB
Swift
//
|
|
// BlockLogViewController.swift
|
|
// Lockdown
|
|
//
|
|
// Copyright © 2019 Confirmed Inc. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
|
|
class BlockLogViewController: BaseViewController, UITableViewDelegate, UITableViewDataSource {
|
|
|
|
@IBOutlet var blockDayCounterLabel: UILabel!
|
|
|
|
// -- SUPPORTING LIVE UPDATES
|
|
var timer: Timer?
|
|
var kvoObservationToken: Any?
|
|
let debouncer = Debouncer(seconds: 0.3)
|
|
//
|
|
|
|
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
|
return dayLogTime.count;
|
|
}
|
|
|
|
func numberOfSections(in tableView: UITableView) -> Int {
|
|
return 1
|
|
}
|
|
|
|
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
|
return 0
|
|
}
|
|
|
|
func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
|
|
return false
|
|
}
|
|
|
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
|
guard let cell = tableView.dequeueReusableCell(withIdentifier: "blockLogCell", for: indexPath) as? BlockLogCell else {
|
|
return UITableViewCell()
|
|
}
|
|
|
|
cell.time.text = dayLogTime[indexPath.row];
|
|
cell.logHost?.text = dayLogHost[indexPath.row];
|
|
|
|
return cell
|
|
}
|
|
|
|
func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
|
|
let logHost = dayLogHost[indexPath.row]
|
|
let info = TrackerInfoRegistry.shared.info(forTrackerDomain: logHost)
|
|
|
|
showPopupDialog(title: info.title, message: info.description, acceptButton: "Okay")
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
blockDayCounterLabel.text = getDayMetricsString(commas: true)
|
|
tableView.refreshControl = refreshControl
|
|
refreshControl.addTarget(self, action: #selector(self.refreshData(_:)), for: .valueChanged)
|
|
|
|
configureObservers()
|
|
|
|
refreshData(self)
|
|
}
|
|
|
|
deinit {
|
|
timer?.invalidate()
|
|
timer = nil
|
|
}
|
|
|
|
func configureObservers() {
|
|
kvoObservationToken = defaults.observe(\.LockdownDayLogs, options: [.new, .old]) { [weak self] (defaults, change) in
|
|
DispatchQueue.main.async {
|
|
self?.debouncer.debounce {
|
|
self?.refreshData(defaults)
|
|
}
|
|
}
|
|
}
|
|
|
|
// timer is used as a backup in case KVO fails for any reason
|
|
timer = Timer.scheduledTimer(withTimeInterval: 15.0, repeats: true) { [weak self] (timer) in
|
|
self?.refreshData(timer)
|
|
}
|
|
timer?.tolerance = 3.0
|
|
}
|
|
|
|
@objc func refreshData(_ sender: Any) {
|
|
blockDayCounterLabel.text = getDayMetricsString(commas: true)
|
|
if BlockDayLog.shared.isEnabled {
|
|
tableView.isHidden = false
|
|
blockLogDisabledContainer.isHidden = true
|
|
|
|
let oldDayLogTime = dayLogTime
|
|
|
|
dayLogTime = []
|
|
dayLogHost = []
|
|
if let dayLogs = BlockDayLog.shared.strings?.reversed() {
|
|
for log in dayLogs {
|
|
let sp = log.components(separatedBy: "_");
|
|
if sp.count == 2 {
|
|
dayLogTime.append(sp[0]);
|
|
dayLogHost.append(sp[1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if dayLogTime.count > oldDayLogTime.count, oldDayLogTime != [] {
|
|
let diff = dayLogTime.count - oldDayLogTime.count
|
|
let indexPaths = (0 ..< diff).map({ IndexPath(row: $0, section: 0) })
|
|
tableView.performBatchUpdates {
|
|
tableView.insertRows(at: indexPaths, with: .top)
|
|
} completion: { (finished) in
|
|
return
|
|
}
|
|
} else {
|
|
tableView.reloadData()
|
|
}
|
|
|
|
DispatchQueue.main.async {
|
|
self.refreshControl.endRefreshing()
|
|
}
|
|
} else {
|
|
tableView.isHidden = true
|
|
blockLogDisabledContainer.isHidden = false
|
|
}
|
|
}
|
|
|
|
@IBAction func dismiss() {
|
|
self.dismiss(animated: true, completion: {})
|
|
}
|
|
|
|
@IBAction func showMenu() {
|
|
let isBlockEnabled = BlockDayLog.shared.isEnabled
|
|
|
|
let message = """
|
|
The block log can be manually cleared or disabled. Disabling the Block Log only disables the log of connections - \
|
|
the number of tracking attempts will still be displayed.
|
|
"""
|
|
showPopupDialog(
|
|
title: .localized("Settings"),
|
|
message: .localized(message),
|
|
buttons: [
|
|
.custom(title: isBlockEnabled ? .localized("Disable Block Log") : .localized("Enable Block Log")) {
|
|
if isBlockEnabled {
|
|
self.showDisableBlockLog()
|
|
} else {
|
|
self.enableBlockLog()
|
|
}
|
|
},
|
|
.custom(title: .localized("Clear Block Log")) {
|
|
BlockDayLog.shared.clear()
|
|
defaults.set(0, forKey: kDayMetrics)
|
|
self.refreshData(self)
|
|
},
|
|
.cancel()
|
|
])
|
|
}
|
|
|
|
func showDisableBlockLog() {
|
|
showPopupDialog(
|
|
title: .localized("Disable Block Log?"),
|
|
message: .localized("You'll have to reenable it later here to start seeing blocked entries again."),
|
|
buttons: [
|
|
.destructive(title: .localized("Disable")) {
|
|
BlockDayLog.shared.disable(shouldClear: true)
|
|
self.refreshData(self)
|
|
},
|
|
.preferredCancel()
|
|
])
|
|
}
|
|
|
|
@IBAction func enableBlockLog() {
|
|
BlockDayLog.shared.enable()
|
|
self.refreshData(self)
|
|
}
|
|
|
|
var dayLogTime: [String] = []
|
|
var dayLogHost: [String] = []
|
|
private let refreshControl = UIRefreshControl()
|
|
@IBOutlet var tableView: UITableView!
|
|
@IBOutlet var blockLogDisabledContainer: UIStackView!
|
|
|
|
}
|
|
|
|
fileprivate extension UserDefaults {
|
|
|
|
@objc
|
|
dynamic var LockdownDayLogs: [Any]? {
|
|
get {
|
|
return array(forKey: "LockdownDayLogs")
|
|
}
|
|
set {
|
|
set(newValue, forKey: "LockdownDayLogs")
|
|
}
|
|
}
|
|
}
|
|
|
|
// https://stackoverflow.com/a/52338788
|
|
// by Frédéric Adda
|
|
class Debouncer {
|
|
|
|
// MARK: - Properties
|
|
private let queue = DispatchQueue.main
|
|
private var workItem = DispatchWorkItem(block: {})
|
|
private var interval: TimeInterval
|
|
|
|
// MARK: - Initializer
|
|
init(seconds: TimeInterval) {
|
|
self.interval = seconds
|
|
}
|
|
|
|
// MARK: - Debouncing function
|
|
func debounce(action: @escaping (() -> Void)) {
|
|
workItem.cancel()
|
|
workItem = DispatchWorkItem(block: { action() })
|
|
queue.asyncAfter(deadline: .now() + interval, execute: workItem)
|
|
}
|
|
}
|