Files
Attractor/App/Autocomplete/AutocompleteViewController.swift

123 lines
4.4 KiB
Swift

//
// AutocompleteViewController.swift
// App
//
// Created by James Magahern on 9/21/20.
//
import UIKit
protocol AutocompleteViewControllerDelegate: AnyObject {
func autocompleteController(_: AutocompleteViewController, didSelectHistoryItem: HistoryItem)
}
class AutocompleteViewController: UIViewController, UICollectionViewDelegate
{
public var historyItems: [HistoryItem] = [] {
didSet {
var snapshot = dataSource.snapshot()
snapshot.deleteAllItems()
snapshot.appendSections([ .HistoryItems ])
snapshot.appendItems(historyItems, toSection: .HistoryItems)
dataSource.apply(snapshot, animatingDifferences: false)
}
}
public weak var delegate: AutocompleteViewControllerDelegate?
private enum Section: Int {
case HistoryItems
}
override var canBecomeFirstResponder: Bool { true }
public let collectionView: UICollectionView
private let dataSource: UICollectionViewDiffableDataSource<Section, HistoryItem>
init() {
let listConfiguration = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
let listLayout = UICollectionViewCompositionalLayout.list(using: listConfiguration)
collectionView = UICollectionView(frame: .zero, collectionViewLayout: listLayout)
let cellRegistry = UICollectionView.CellRegistration<UICollectionViewListCell, HistoryItem> { (cell, indexPath, item) in
var config = cell.defaultContentConfiguration()
config.text = item.title
config.secondaryText = item.url.absoluteString
cell.contentConfiguration = config
}
dataSource = UICollectionViewDiffableDataSource<Section, HistoryItem>(collectionView: collectionView, cellProvider:
{ (collectionView, indexPath, item) -> UICollectionViewCell? in
collectionView.dequeueConfiguredReusableCell(using: cellRegistry, for: indexPath, item: item)
})
super.init(nibName: nil, bundle: nil)
collectionView.delegate = self
view.backgroundColor = .systemBackground
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
override func loadView() {
self.view = collectionView
}
override var keyCommands: [UIKeyCommand]? {
[
UIKeyCommand(action: #selector(self.selectNextItem), input: UIKeyCommand.inputDownArrow),
UIKeyCommand(action: #selector(self.selectPreviousItem), input: UIKeyCommand.inputUpArrow),
UIKeyCommand(action: #selector(self.commitSelectedItem), input: "\r"), // this is stupid...
]
}
override func becomeFirstResponder() -> Bool {
let result = super.becomeFirstResponder()
if result {
let firstIndex = IndexPath(row: 0, section: 0)
collectionView.selectItem(at: firstIndex, animated: false, scrollPosition: .top)
}
return result
}
private func selectItem(inDirection direction: Int) {
if let selectedIndex = collectionView.indexPathsForSelectedItems?.first {
let nextRow = (selectedIndex.row + direction)
if nextRow < dataSource.snapshot().numberOfItems && nextRow >= 0 {
let nextIndexPath = IndexPath(row: nextRow, section: 0)
collectionView.selectItem(at: nextIndexPath, animated: false, scrollPosition: .centeredVertically)
}
}
}
@objc
private func selectNextItem(_ sender: Any?) {
selectItem(inDirection: 1)
}
@objc
private func selectPreviousItem(_ sender: Any?) {
selectItem(inDirection: -1)
}
@objc
private func commitSelectedItem(_ sender: Any?) {
if let selectedIndex = collectionView.indexPathsForSelectedItems?.first,
let item = dataSource.itemIdentifier(for: selectedIndex)
{
delegate?.autocompleteController(self, didSelectHistoryItem: item)
}
}
// MARK: UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.deselectItem(at: indexPath, animated: true)
if let item = dataSource.itemIdentifier(for: indexPath) {
delegate?.autocompleteController(self, didSelectHistoryItem: item)
}
}
}