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

220 lines
6.0 KiB
Swift

//
// CustomTableView.swift
//
// Created by Aliaksandr Dvoineu on 16.03.23.
//
import UIKit
class TableViewHeader: UIView {
lazy var view: UIView = {
let view = UIView()
return view
}()
override init(frame: CGRect) {
super.init(frame: .zero)
configure()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configure() {
addSubview(view)
view.anchors.edges.pin()
}
}
class CustomTableViewCell: 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
}
}
final class CustomTableView: 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: [CustomTableViewCell] = []
var deselectsCellsAutomatically: Bool = false
var headerView = TableViewHeader()
override init(frame: CGRect, style: UITableView.Style) {
super.init(frame: frame, style: .grouped)
setup()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setup() {
dataSource = self
delegate = self
separatorStyle = .none
}
enum Insert {
case last
case dontInsert
}
@discardableResult
func addHeader(_ configure: (UIView) -> ()) -> TableViewHeader {
let header = headerView
configure(header.view)
return header
}
@discardableResult
func addRow(insert: Insert = .last, _ configure: (UIView) -> ()) -> CustomTableViewCell {
let cell = CustomTableViewCell()
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) -> ()) -> CustomTableViewCell {
let cell = CustomTableViewCell()
cell.selectionStyle = .none
configure(cell)
self.insert(cell: cell, insert: insert)
return cell
}
@discardableResult
func addCell(insert: Insert = .last, _ cell: CustomTableViewCell) -> CustomTableViewCell {
self.insert(cell: cell, insert: insert)
return cell
}
@discardableResult
func addRow(insert: Insert = .last, view: UIView, insets: UIEdgeInsets = .zero) -> CustomTableViewCell {
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: CustomTableViewCell, insert: Insert) {
switch insert {
case .dontInsert:
break
case .last:
rows.append(cell)
}
}
func clear() {
rows = []
}
}
extension CustomTableView: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rows.count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = headerView
return header
}
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 CustomTableView: UITableViewDelegate {
func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
if let cell = tableView.cellForRow(at: indexPath) as? CustomTableViewCell {
return cell.selectionStyle != .none
} else {
return false
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? CustomTableViewCell {
cell.selectionCallback()
if deselectsCellsAutomatically {
tableView.deselectRow(at: indexPath, animated: true)
}
}
}
}