// // TabPickerViewController.swift // SBrowser // // Created by James Magahern on 7/30/20. // import UIKit protocol TabPickerViewControllerDelegate: class { func tabPicker(_ picker: TabPickerViewController, didSelectTab tab: Tab) func tabPicker(_ picker: TabPickerViewController, willCloseTab tab: Tab) } class TabPickerViewController: UIViewController, UICollectionViewDelegate { let tabController: TabController! var selectedTab: Tab? weak var delegate: TabPickerViewControllerDelegate? typealias TabID = UUID private var collectionView: UICollectionView? private var dataSource: UICollectionViewDiffableDataSource? init(tabController: TabController) { self.tabController = tabController super.init(nibName: nil, bundle: nil) self.title = "Tabs" } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func loadView() { var listConfig = UICollectionLayoutListConfiguration(appearance: .grouped) listConfig.trailingSwipeActionsConfigurationProvider = { [unowned self] indexPath in if self.dataSource?.snapshot().numberOfItems ?? 0 <= 1 { return nil } return UISwipeActionsConfiguration(actions: [ UIContextualAction(style: .destructive, title: "Close", handler: { [unowned self] (action, view, completionHandler) in if let item = self.dataSource?.itemIdentifier(for: indexPath), var snapshot = self.dataSource?.snapshot() { if let tab = self.tabController.tab(forIdentifier: item) { self.delegate?.tabPicker(self, willCloseTab: tab) self.tabController.closeTab(tab) snapshot.deleteItems([ item ]) self.dataSource?.apply(snapshot, animatingDifferences: true) } } })]) } let listLayout = UICollectionViewCompositionalLayout.list(using: listConfig) let collectionView = UICollectionView(frame: .zero, collectionViewLayout: listLayout) let registry = UICollectionView.CellRegistration { [unowned self] (listCell, indexPath, item) in var config = listCell.defaultContentConfiguration() if let tab = self.tabController.tab(forIdentifier: item) { if let title = tab.title { config.text = title config.secondaryText = tab.url?.absoluteString } else { config.text = tab.url?.absoluteString config.secondaryText = tab.url?.absoluteString } if let image = tab.favicon { config.image = image config.imageProperties.maximumSize = CGSize(width: 21.0, height: 21.0) config.imageProperties.cornerRadius = 3.0 } if tab == self.selectedTab { listCell.accessories = [ .checkmark() ] } else { listCell.accessories = [] } } listCell.contentConfiguration = config } let dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { (collectionView, indexPath, item) -> UICollectionViewCell? in return collectionView.dequeueConfiguredReusableCell(using: registry, for: indexPath, item: item) } collectionView.dataSource = dataSource collectionView.delegate = self var snapshot = dataSource.snapshot() snapshot.appendSections([ 0 ]) tabController.tabs.forEach { tab in snapshot.appendItems([ tab.identifier ]) } dataSource.apply(snapshot) self.dataSource = dataSource self.collectionView = collectionView self.view = self.collectionView let newTabButton = UIBarButtonItem(systemItem: .add, primaryAction: UIAction(handler: { [unowned self] _ in let newTab = self.tabController.createNewTab() self.delegate?.tabPicker(self, didSelectTab: newTab) }), menu: nil) navigationItem.rightBarButtonItem = newTabButton } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { let tab = tabController.tabs[indexPath.row] delegate?.tabPicker(self, didSelectTab: tab) } }