// // AccountListViewController.swift // Tusker // // Created by Shadowfacts on 9/5/19. // Copyright © 2019 Shadowfacts. All rights reserved. // import UIKit class AccountListViewController: UIViewController { typealias Item = String private let mastodonController: MastodonController private let accountIDs: [String] private var collectionView: UICollectionView { view as! UICollectionView } private var dataSource: UICollectionViewDiffableDataSource! init(accountIDs: [String], mastodonController: MastodonController) { self.mastodonController = mastodonController self.accountIDs = accountIDs super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func loadView() { let config = UICollectionLayoutListConfiguration(appearance: .grouped) let layout = UICollectionViewCompositionalLayout.list(using: config) view = UICollectionView(frame: .zero, collectionViewLayout: layout) collectionView.delegate = self collectionView.dragDelegate = self dataSource = createDataSource() } private func createDataSource() -> UICollectionViewDiffableDataSource { let accountCell = UICollectionView.CellRegistration { [unowned self] cell, indexPath, item in cell.delegate = self cell.updateUI(accountID: item) } return UICollectionViewDiffableDataSource(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in return collectionView.dequeueConfiguredReusableCell(using: accountCell, for: indexPath, item: itemIdentifier) } } override func viewDidLoad() { super.viewDidLoad() var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.accounts]) snapshot.appendItems(accountIDs) dataSource.apply(snapshot, animatingDifferences: false) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) collectionView.indexPathsForSelectedItems?.forEach { collectionView.deselectItem(at: $0, animated: true) } } } extension AccountListViewController { enum Section { case accounts } } extension AccountListViewController: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { if let id = dataSource.itemIdentifier(for: indexPath) { selected(account: id) } } func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { guard let id = dataSource.itemIdentifier(for: indexPath), let cell = collectionView.cellForItem(at: indexPath) else { return nil } return UIContextMenuConfiguration { ProfileViewController(accountID: id, mastodonController: self.mastodonController) } actionProvider: { _ in UIMenu(children: self.actionsForProfile(accountID: id, source: .view(cell))) } } func collectionView(_ collectionView: UICollectionView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) { MenuPreviewHelper.willPerformPreviewAction(animator: animator, presenter: self) } } extension AccountListViewController: UICollectionViewDragDelegate { func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] { guard let id = dataSource.itemIdentifier(for: indexPath), let currentAccountID = mastodonController.accountInfo?.id, let account = mastodonController.persistentContainer.account(for: id) else { return [] } let provider = NSItemProvider(object: account.url as NSURL) let activity = UserActivityManager.showProfileActivity(id: id, accountID: currentAccountID) activity.displaysAuxiliaryScene = true provider.registerObject(activity, visibility: .all) return [UIDragItem(itemProvider: provider)] } } extension AccountListViewController: TuskerNavigationDelegate { var apiController: MastodonController! { mastodonController } } extension AccountListViewController: MenuActionProvider { } extension AccountListViewController: StatusBarTappableViewController { func handleStatusBarTapped(xPosition: CGFloat) -> StatusBarTapActionResult { collectionView.scrollToTop() return .stop } }