157 lines
4.9 KiB
Swift
157 lines
4.9 KiB
Swift
import UIKit
|
||
|
||
class TVCDomains: UITableViewController, IncrementalDataSourceUpdate, UISearchBarDelegate {
|
||
|
||
internal var dataSource: [GroupedDomain] = []
|
||
private func dataSource(at: Int) -> GroupedDomain {
|
||
dataSource[(searchActive ? searchIndices[at] : at)]
|
||
}
|
||
private var searchActive: Bool = false
|
||
private var searchIndices: [Int] = []
|
||
private var searchTerm: String?
|
||
private let searchBar: UISearchBar = {
|
||
let x = UISearchBar(frame: CGRect.init(x: 0, y: 0, width: 20, height: 10))
|
||
x.sizeToFit()
|
||
x.showsCancelButton = true
|
||
x.autocapitalizationType = .none
|
||
x.autocorrectionType = .no
|
||
return x
|
||
}()
|
||
@IBOutlet private var filterButton: UIBarButtonItem!
|
||
@IBOutlet private var filterButtonDetail: UIBarButtonItem!
|
||
|
||
override func viewDidLoad() {
|
||
super.viewDidLoad()
|
||
if #available(iOS 10.0, *) {
|
||
tableView.refreshControl = UIRefreshControl(call: #selector(reloadDataSource), on: self)
|
||
}
|
||
NotifyLogHistoryReset.observe(call: #selector(reloadDataSource), on: self)
|
||
reloadDataSource()
|
||
DBWrp.dataA_delegate = self
|
||
searchBar.delegate = self
|
||
NotifyDateFilterChanged.observe(call: #selector(dateFilterChanged), on: self)
|
||
dateFilterChanged()
|
||
}
|
||
|
||
@objc func reloadDataSource() {
|
||
dataSource = DBWrp.listOfDomains()
|
||
if searchActive {
|
||
searchBar(searchBar, textDidChange: "")
|
||
} else {
|
||
tableView.reloadData()
|
||
}
|
||
}
|
||
|
||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||
if let index = tableView.indexPathForSelectedRow?.row {
|
||
(segue.destination as? TVCHosts)?.parentDomain = dataSource(at: index).domain
|
||
}
|
||
}
|
||
|
||
|
||
// MARK: - Table View Delegate
|
||
|
||
override func tableView(_ _: UITableView, numberOfRowsInSection _: Int) -> Int {
|
||
searchActive ? searchIndices.count : dataSource.count
|
||
}
|
||
|
||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||
let cell = tableView.dequeueReusableCell(withIdentifier: "DomainCell")!
|
||
let entry = dataSource(at: indexPath.row)
|
||
cell.textLabel?.text = entry.domain
|
||
cell.detailTextLabel?.text = entry.detailCellText
|
||
cell.imageView?.image = entry.options?.tableRowImage()
|
||
return cell
|
||
}
|
||
|
||
|
||
// MARK: - Search
|
||
|
||
@IBAction private func searchButtonTapped(_ sender: UIBarButtonItem) {
|
||
setSearch(hidden: searchActive)
|
||
}
|
||
|
||
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
|
||
setSearch(hidden: true)
|
||
}
|
||
|
||
private func setSearch(hidden: Bool) {
|
||
searchActive = !hidden
|
||
searchIndices = []
|
||
searchTerm = nil
|
||
searchBar.text = nil
|
||
tableView.tableHeaderView = hidden ? nil : searchBar
|
||
if !hidden { searchBar.becomeFirstResponder() }
|
||
tableView.reloadData()
|
||
}
|
||
|
||
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
|
||
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(performSearch), object: nil)
|
||
perform(#selector(performSearch), with: nil, afterDelay: 0.3)
|
||
}
|
||
|
||
@objc private func performSearch() {
|
||
searchTerm = searchBar.text?.lowercased() ?? ""
|
||
searchIndices = dataSource.enumerated().compactMap {
|
||
if $1.domain.lowercased().contains(searchTerm!) { return $0 }
|
||
return nil
|
||
}
|
||
tableView.reloadData()
|
||
}
|
||
|
||
func shouldLiveUpdateIncrementalDataSource() -> Bool { !searchActive }
|
||
|
||
func didUpdateIncrementalDataSource(_ operation: IncrementalDataSourceUpdateOperation, row: Int, moveTo: Int) {
|
||
guard searchActive else {
|
||
return
|
||
}
|
||
switch operation {
|
||
case .ReloadTable:
|
||
DispatchQueue.main.sync { tableView.reloadData() }
|
||
case .Insert:
|
||
if dataSource[row].domain.lowercased().contains(searchTerm ?? "") {
|
||
searchIndices.insert(row, at: 0)
|
||
DispatchQueue.main.sync { tableView.safeInsertRow(0, with: .left) }
|
||
}
|
||
case .Delete:
|
||
if let idx = searchIndices.firstIndex(of: row) {
|
||
searchIndices.remove(at: idx)
|
||
DispatchQueue.main.sync { tableView.safeDeleteRow(idx) }
|
||
}
|
||
case .Update, .Move:
|
||
if let idx = searchIndices.firstIndex(of: row) {
|
||
if operation == .Move { searchIndices[idx] = moveTo }
|
||
DispatchQueue.main.sync { tableView.safeReloadRow(idx) }
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// MARK: - Filter
|
||
|
||
@IBAction private func filterButtonTapped(_ sender: UIBarButtonItem) {
|
||
let vc = self.storyboard!.instantiateViewController(withIdentifier: "domainFilter")
|
||
vc.modalPresentationStyle = .custom
|
||
if #available(iOS 13.0, *) {
|
||
vc.isModalInPresentation = true
|
||
}
|
||
present(vc, animated: true)
|
||
}
|
||
|
||
@objc private func dateFilterChanged() {
|
||
switch Pref.DateFilter.Kind {
|
||
case .ABRange: // read start/end time
|
||
self.filterButtonDetail.title = "A – B"
|
||
self.filterButton.image = UIImage(named: "filter-filled")
|
||
case .LastXMin: // most recent
|
||
let lastXMin = Pref.DateFilter.LastXMin
|
||
if lastXMin == 0 { fallthrough }
|
||
self.filterButtonDetail.title = TimeFormat.short(minutes: lastXMin, style: .abbreviated)
|
||
self.filterButton.image = UIImage(named: "filter-filled")
|
||
default:
|
||
self.filterButtonDetail.title = ""
|
||
self.filterButton.image = UIImage(named: "filter-clear")
|
||
}
|
||
}
|
||
}
|