Instantly share code, notes, and snippets.
Created
September 23, 2021 18:29
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // SNPSidebarSourceListViewController.swift | |
| // SNPSidebarSourceListViewController | |
| // | |
| // Created by Steven Troughton-Smith on 14/09/2021. | |
| // | |
| import UIKit | |
| class SNPSidebarSourceListViewController: UICollectionViewController { | |
| enum HIOutlineSection { | |
| case favorites | |
| case folders | |
| } | |
| struct HIOutlineItem: Hashable { | |
| var title: String = "" | |
| var indentation = 0 | |
| var subitems: [HIOutlineItem] = [] | |
| /* | |
| init(title: String, | |
| subitems: [HIOutlineItem] = []) { | |
| self.title = title | |
| self.subitems = subitems | |
| self.indentation = subitems | |
| } | |
| */ | |
| func hash(into hasher: inout Hasher) { | |
| hasher.combine(identifier) | |
| } | |
| static func == (lhs: HIOutlineItem, rhs: HIOutlineItem) -> Bool { | |
| return lhs.identifier == rhs.identifier | |
| } | |
| private let identifier = UUID() | |
| } | |
| var dataSource: UICollectionViewDiffableDataSource<HIOutlineSection, HIOutlineItem>! = nil | |
| init() { | |
| var listConfiguration = UICollectionLayoutListConfiguration(appearance: .sidebar) | |
| listConfiguration.showsSeparators = false | |
| let layout = UICollectionViewCompositionalLayout.list(using: listConfiguration) | |
| super.init(collectionViewLayout: layout) | |
| configureDataSource() | |
| } | |
| required init?(coder: NSCoder) { | |
| fatalError("init(coder:) has not been implemented") | |
| } | |
| // MARK: - | |
| func configureDataSource() { | |
| let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, HIOutlineItem> { cell, indexPath, menuItem in | |
| var contentConfiguration = cell.defaultContentConfiguration() | |
| var disclosureOptions = UICellAccessory.OutlineDisclosureOptions(style: .cell) | |
| if indexPath.item == 0 { | |
| disclosureOptions = UICellAccessory.OutlineDisclosureOptions(style: .header) | |
| contentConfiguration = UIListContentConfiguration.sidebarHeader() | |
| } | |
| else { | |
| contentConfiguration.textProperties.font = .preferredFont(forTextStyle: .body) | |
| contentConfiguration.imageProperties.reservedLayoutSize = CGSize(width: UIFloat(22), height: 0) | |
| } | |
| if indexPath.section == 0 { | |
| if indexPath.row == 1 { | |
| contentConfiguration.image = UIImage(systemName: "tray") | |
| } | |
| else if indexPath.row == 2 { | |
| contentConfiguration.image = UIImage(systemName: "clock") | |
| } | |
| } | |
| else { | |
| if indexPath.row > 0 { | |
| contentConfiguration.image = UIImage(systemName: "folder") | |
| } | |
| } | |
| contentConfiguration.text = menuItem.title | |
| if indexPath.section == 1 { | |
| // disclosureOptions.reservedLayoutWidth = .custom(UIFloat(8)) | |
| if menuItem.subitems.isEmpty == true { | |
| disclosureOptions.isHidden = true | |
| } | |
| else { | |
| disclosureOptions.isHidden = false | |
| } | |
| cell.accessories = [.outlineDisclosure(options: disclosureOptions)] | |
| cell.indentationLevel = menuItem.indentation | |
| } | |
| cell.contentConfiguration = contentConfiguration | |
| } | |
| dataSource = UICollectionViewDiffableDataSource<HIOutlineSection, HIOutlineItem>(collectionView: collectionView) { | |
| (collectionView: UICollectionView, indexPath: IndexPath, item: HIOutlineItem) -> UICollectionViewCell? in | |
| return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item) | |
| } | |
| collectionView.dataSource = dataSource | |
| refresh() | |
| } | |
| // MARK: - | |
| private lazy var menuItems: [HIOutlineItem] = { | |
| return [ | |
| HIOutlineItem(title: "Folders", subitems: [ | |
| HIOutlineItem(title: "Folder A", indentation: 0), | |
| HIOutlineItem(title: "Folder B", indentation: 0, subitems: [HIOutlineItem(title: "Folder C", indentation: 1, subitems: [])]) | |
| ]) | |
| ] | |
| }() | |
| private lazy var favoriteItems: [HIOutlineItem] = { | |
| return [ | |
| HIOutlineItem(title: "Favorites", subitems: [ | |
| HIOutlineItem(title: "All"), | |
| HIOutlineItem(title: "Recents") | |
| ]), | |
| ] | |
| }() | |
| func initialSnapshot(forItems:[HIOutlineItem]) -> NSDiffableDataSourceSectionSnapshot<HIOutlineItem> { | |
| var snapshot = NSDiffableDataSourceSectionSnapshot<HIOutlineItem>() | |
| func addItems(_ menuItems: [HIOutlineItem], to parent: HIOutlineItem?) { | |
| snapshot.append(menuItems, to: parent) | |
| snapshot.expand(menuItems) | |
| for menuItem in menuItems where !menuItem.subitems.isEmpty { | |
| addItems(menuItem.subitems, to: menuItem) | |
| } | |
| } | |
| addItems(forItems, to: nil) | |
| return snapshot | |
| } | |
| func refresh() { | |
| guard let dataSource = collectionView.dataSource as? UICollectionViewDiffableDataSource<HIOutlineSection, HIOutlineItem> else { return } | |
| dataSource.apply(initialSnapshot(forItems: favoriteItems), to: .favorites, animatingDifferences: false) | |
| dataSource.apply(initialSnapshot(forItems: menuItems), to: .folders, animatingDifferences: false) | |
| DispatchQueue.main.async { | |
| self.collectionView.selectItem(at: IndexPath(item: 1, section: 0), animated: false, scrollPosition: []) | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment