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

208 lines
6.1 KiB
Swift

//
// StaticTableView.swift
// Private Analytics
//
// Created by Oleg Dreyman on 21.08.2020.
// Copyright © 2020 Confirmed, Inc. All rights reserved.
//
import UIKit
final class StaticTableView: UITableView {
// Resizing UITableView to fit content
override var contentSize: CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
layoutIfNeeded()
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
}
var rows: [SelectableTableViewCell] = []
var deselectsCellsAutomatically: Bool = false
override init(frame: CGRect, style: UITableView.Style) {
super.init(frame: frame, style: .insetGrouped)
setup()
}
func setup() {
dataSource = self
delegate = self
separatorStyle = .none
}
enum Insert {
case last
case dontInsert
}
@discardableResult
func addRow(insert: Insert = .last, _ configure: (UIView) -> ()) -> SelectableTableViewCell {
let cell = SelectableTableViewCell()
cell.selectionStyle = .none
cell.backgroundColor = nil
configure(cell.contentView)
self.insert(cell: cell, insert: insert)
return cell
}
@discardableResult
func addRowCell(insert: Insert = .last, _ configure: (UITableViewCell) -> ()) -> SelectableTableViewCell {
let cell = SelectableTableViewCell()
cell.selectionStyle = .none
configure(cell)
self.insert(cell: cell, insert: insert)
return cell
}
@discardableResult
func addCell(insert: Insert = .last, _ cell: SelectableTableViewCell) -> SelectableTableViewCell {
self.insert(cell: cell, insert: insert)
return cell
}
@discardableResult
func addRow(insert: Insert = .last, view: UIView, insets: UIEdgeInsets = .zero) -> SelectableTableViewCell {
return addRow(insert: insert) { (row) in
row.addSubview(view)
view.anchors.edges.pin(axis: .vertical)
view.anchors.edges.marginsPin(insets: insets, axis: .horizontal)
}
}
private func insert(cell: SelectableTableViewCell, insert: Insert) {
switch insert {
case .dontInsert:
break
case .last:
rows.append(cell)
}
}
func clear() {
rows = []
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class SelectableTableViewCell: UITableViewCell {
var selectionCallback: () -> () = { }
var deletionCallback: (() -> ())?
enum Action {
case toggleCheckmark
}
@discardableResult
func onSelect(callback: @escaping () -> ()) -> Self {
selectionStyle = .default
selectionCallback = callback
return self
}
@discardableResult
func onSwipeToDelete(callback: @escaping () -> ()) -> Self {
deletionCallback = callback
return self
}
@discardableResult
func onSelect(_ action: Action, callback: @escaping () -> () = { }) -> Self {
selectionCallback = { [unowned self] in
switch action {
case .toggleCheckmark:
if self.accessoryType == .checkmark {
self.accessoryType = .none
} else {
self.accessoryType = .checkmark
}
}
callback()
}
return self
}
}
extension StaticTableView: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rows.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return rows[indexPath.row]
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
let cell = rows[indexPath.row]
return cell.deletionCallback != nil
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
return .delete
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
let cell = rows[indexPath.row]
guard cell.deletionCallback != nil else {
return
}
cell.deletionCallback?()
self.rows.removeAll(where: { $0 === cell })
self.deleteRows(at: [indexPath], with: .fade)
}
}
extension StaticTableView: UITableViewDelegate {
func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
if let cell = tableView.cellForRow(at: indexPath) as? SelectableTableViewCell {
return cell.selectionStyle != .none
} else {
return false
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? SelectableTableViewCell {
cell.selectionCallback()
if deselectsCellsAutomatically {
tableView.deselectRow(at: indexPath, animated: true)
}
}
}
}
extension UIViewController {
func addTableView(_ tableView: UITableView, layout: (UIView) -> ()) {
// adding UITableView as UITableViewController will enable
// UIKit's own "scroll to text field when keyboard appears"
let tableViewController = StaticTableViewController()
tableViewController.tableView = tableView
view.addSubview(tableViewController.view)
layout(tableView)
addChild(tableViewController)
tableViewController.didMove(toParent: self)
}
}
final class StaticTableViewController: UITableViewController {
}