Files
lockdown-iOS-mirror/LockdowniOS/ListSettingsViewController.swift

380 lines
14 KiB
Swift

//
// ListSettingsViewController.swift
// Lockdown
//
// Created by Aliaksandr Dvoineu on 28.03.23.
// Copyright © 2023 Confirmed Inc. All rights reserved.
//
import UIKit
import CocoaLumberjackSwift
final class ListSettingsViewController: UIViewController {
// MARK: - Properties
private var blockedList: UserBlockListsGroup?
var listName = ""
weak var blockListVC: BlockListViewController?
var didMakeChange = false
lazy var navigationView: ConfiguredNavigationView = {
let view = ConfiguredNavigationView()
view.titleLabel.text = "List Settings"
view.leftNavButton.setTitle(NSLocalizedString("BACK", comment: ""), for: .normal)
view.leftNavButton.setImage(UIImage(systemName: "chevron.left"), for: .normal)
view.leftNavButton.addTarget(self, action: #selector(backButtonClicked), for: .touchUpInside)
view.rightNavButton.setTitle("...", for: .normal)
view.rightNavButton.titleLabel?.font = fontBold18
view.rightNavButton.addTarget(self, action: #selector(showSubmenu), for: .touchUpInside)
return view
}()
private lazy var switchBlockingView: SwitchBlockingView = {
let view = SwitchBlockingView()
view.titleLabel.text = NSLocalizedString("Blocking", comment: "")
view.switchView.addTarget(self, action: #selector(toggleBlocking), for: .valueChanged)
return view
}()
private lazy var subMenu: ListsSubmenuView = {
let view = ListsSubmenuView()
view.topButton.setTitle(NSLocalizedString("Export List...", comment: ""), for: .normal)
view.topButton.setImage(UIImage(named: "icn_export_folder"), for: .normal)
view.topButton.addTarget(self, action: #selector(exportList), for: .touchUpInside)
view.bottomButton.setTitle(NSLocalizedString("Delete List...", comment: ""), for: .normal)
view.bottomButton.setImage(UIImage(named: "icn_trash"), for: .normal)
view.bottomButton.addTarget(self, action: #selector(deleteList), for: .touchUpInside)
return view
}()
private let tableView = UITableView(frame: .zero, style: .insetGrouped)
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .secondarySystemBackground
// if let list = blockedList {
// list = getBlockedLists().userBlockListsDefaults[listName]
// switchBlockingView.switchView.isOn = list.enabled
// }
configureUI()
configureTableView()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let userBlockedLists = getBlockedLists().userBlockListsDefaults
blockedList = userBlockedLists[listName]
switchBlockingView.switchView.isOn = didMakeChange
}
// MARK: - Configure UI
func configureUI() {
view.addSubview(navigationView)
navigationView.anchors.leading.pin()
navigationView.anchors.trailing.pin()
navigationView.anchors.top.safeAreaPin()
view.addSubview(switchBlockingView)
switchBlockingView.anchors.top.spacing(12, to: navigationView.anchors.bottom)
switchBlockingView.anchors.leading.marginsPin()
switchBlockingView.anchors.trailing.marginsPin()
switchBlockingView.anchors.height.equal(40)
addTableView(tableView) { tableview in
tableView.anchors.top.spacing(20, to: switchBlockingView.anchors.bottom)
tableView.anchors.leading.pin()
tableView.anchors.trailing.pin()
tableView.anchors.bottom.pin()
}
view.addSubview(subMenu)
subMenu.anchors.top.spacing(0, to: navigationView.anchors.bottom)
subMenu.anchors.trailing.marginsPin()
subMenu.isHidden = true
let tap = UITapGestureRecognizer(target: self, action: #selector(hideSubmenu))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
func configureTableView() {
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = 40
tableView.register(ListBlockedTableViewCell.self, forCellReuseIdentifier: ListBlockedTableViewCell.identifier)
tableView.register(DomainsBlockedTableViewCell.self, forCellReuseIdentifier: DomainsBlockedTableViewCell.identifier)
}
private func removeDomain(at index: Int) {
guard let list = blockedList else { return }
let domain = Array(list.domains)[index]
blockedList = deleteDoman(domain: domain, inBlockedListName: listName)
}
}
extension ListSettingsViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView()
let sectionName = UILabel()
sectionName.font = fontBold13
view.addSubview(sectionName)
sectionName.anchors.top.marginsPin()
sectionName.anchors.leading.marginsPin()
sectionName.anchors.bottom.marginsPin()
switch section {
case 0:
sectionName.text = NSLocalizedString("NAME", comment: "")
case 1:
sectionName.text = NSLocalizedString("DESCRIPTION", comment: "")
case 2:
sectionName.text = NSLocalizedString("DOMAINS", comment: "")
let addButton = UIButton(type: .system)
let symbolConfig = UIImage.SymbolConfiguration(pointSize: 14, weight: .bold, scale: .large)
addButton.setImage(UIImage(systemName: "plus", withConfiguration: symbolConfig), for: .normal)
addButton.tintColor = .tunnelsBlue
addButton.addTarget(self, action: #selector(addDomain), for: .touchUpInside)
view.addSubview(addButton)
addButton.anchors.top.marginsPin()
addButton.anchors.trailing.marginsPin()
addButton.anchors.bottom.marginsPin()
default: break
}
return view
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
40
}
func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let numberOfDomains = blockedList?.domains.count
switch section {
case 0, 1: return 1
case 2: return numberOfDomains ?? 0
default: return 0
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.section {
case 0:
guard let cell = tableView.dequeueReusableCell(withIdentifier: ListBlockedTableViewCell.identifier, for: indexPath) as? ListBlockedTableViewCell else {
return UITableViewCell()
}
cell.label.text = listName
return cell
case 1:
guard let cell = tableView.dequeueReusableCell(withIdentifier: ListBlockedTableViewCell.identifier, for: indexPath) as? ListBlockedTableViewCell else {
return UITableViewCell()
}
cell.label.text = blockedList?.description ?? "Description"
return cell
case 2:
guard let cell = tableView.dequeueReusableCell(withIdentifier: DomainsBlockedTableViewCell.identifier, for: indexPath) as? DomainsBlockedTableViewCell else {
return UITableViewCell()
}
let domains: [String] = Array(blockedList!.domains)
cell.label.text = domains[indexPath.row]
return cell
default:
return UITableViewCell()
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
switch indexPath.section {
case 0:
let vc = ListDetailViewController()
vc.delegate = self
vc.listName = listName
navigationController?.pushViewController(vc, animated: true)
case 1:
let vc = ListDescriptionViewController()
vc.delegate = self
vc.listName = listName
navigationController?.pushViewController(vc, animated: true)
default:
break
}
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
indexPath.section == 2
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
.delete
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
guard indexPath.section == 2,
editingStyle == .delete else {
return
}
removeDomain(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
extension ListSettingsViewController: UITableViewDelegate {
}
// MARK: - Functions
extension ListSettingsViewController {
@objc func backButtonClicked() {
navigationController?.popViewController(animated: true)
}
func saveNewDomain(userEnteredDomainName: String) {
didMakeChange = true
DDLogInfo("Adding custom domain - \(userEnteredDomainName)")
addDomainToBlockedList(domain: userEnteredDomainName, for: listName)
blockedList = getBlockedLists().userBlockListsDefaults[listName]
tableView.reloadData()
}
@objc func addDomain() {
let alertController = UIAlertController(title: "Add a Domain to Block", message: nil, preferredStyle: .alert)
let saveAction = UIAlertAction(title: "Save", style: .default) { [weak self] (_) in
guard let self else { return }
if let txtField = alertController.textFields?.first, let text = txtField.text {
self.saveNewDomain(userEnteredDomainName: text)
}
}
saveAction.isEnabled = false
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in }
alertController.addTextField { (textField) in
textField.keyboardType = .URL
textField.placeholder = "domain-to-block"
}
NotificationCenter.default.addObserver(
forName: UITextField.textDidChangeNotification,
object: alertController.textFields?.first,
queue: .main) { (notification) -> Void in
guard let textFieldText = alertController.textFields?.first?.text else { return }
saveAction.isEnabled = textFieldText.isValid(.domainName)
}
alertController.addAction(saveAction)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}
@objc func showSubmenu() {
subMenu.isHidden = false
}
@objc func hideSubmenu() {
subMenu.isHidden = true
}
@objc func deleteList() {
let alert = UIAlertController(title: NSLocalizedString("Delete List?", comment: ""), message: NSLocalizedString("Are you sure you want to remove this list?", comment: ""), preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("No, Return", comment: ""), style: UIAlertAction.Style.default, handler: { _ in
print("Return")
}))
alert.addAction(UIAlertAction(title: NSLocalizedString("Yes, Delete", comment: ""),
style: UIAlertAction.Style.destructive,
handler: { [weak self] (_) in
guard let self else { return }
if let vc = self.blockListVC {
vc.didMakeChange = true
}
if let list = self.blockedList {
deleteBlockedList(listName: list.name)
}
self.backButtonClicked()
}))
self.present(alert, animated: true, completion: nil)
}
@objc func toggleBlocking(sender: UISwitch) {
let sender = switchBlockingView.switchView
setBlockingEnabled(sender.isOn)
}
func setBlockingEnabled(_ isEnabled: Bool) {
let domains = getBlockedLists().userBlockListsDefaults
var userList = domains[listName]
userList?.enabled = isEnabled
var data = getBlockedLists()
data.userBlockListsDefaults[listName] = userList
let encodedData = try? JSONEncoder().encode(data)
defaults.set(encodedData, forKey: kUserBlockedLists)
if let vc = self.blockListVC {
vc.didMakeChange = true
}
}
@objc func exportList(_ sender: UIButton) {
let userList = getBlockedLists().userBlockListsDefaults[listName]
guard let url = userList?.exportToURL() else { return }
let activity = UIActivityViewController(
activityItems: [url],
applicationActivities: nil
)
activity.popoverPresentationController?.sourceView = sender
present(activity, animated: true, completion: nil)
}
}
extension ListSettingsViewController: ListDetailViewControllerDelegate {
func changeListName(name: String) {
listName = name
tableView.reloadData()
}
}
extension ListSettingsViewController: ListDescriptionViewControllerDelegate {
func changeListDescription(description: String) {
tableView.reloadData()
}
}