forked from shadowfacts/Tusker
Switch asset picker to use diffable data sources
This commit is contained in:
parent
985d30a401
commit
fe09c5e522
|
@ -22,20 +22,22 @@ class AssetCollectionViewController: UICollectionViewController {
|
|||
|
||||
weak var delegate: AssetCollectionViewControllerDelegate?
|
||||
|
||||
var flowLayout: UICollectionViewFlowLayout {
|
||||
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
|
||||
private var flowLayout: UICollectionViewFlowLayout {
|
||||
return collectionViewLayout as! UICollectionViewFlowLayout
|
||||
}
|
||||
|
||||
var availableWidth: CGFloat!
|
||||
var thumbnailSize: CGSize!
|
||||
private var availableWidth: CGFloat!
|
||||
private var thumbnailSize: CGSize!
|
||||
|
||||
let imageManager = PHCachingImageManager()
|
||||
var fetchResult: PHFetchResult<PHAsset>!
|
||||
private let imageManager = PHCachingImageManager()
|
||||
private var fetchResult: PHFetchResult<PHAsset>!
|
||||
|
||||
var selectedAssets: [PHAsset] {
|
||||
return collectionView.indexPathsForSelectedItems?.map({ (indexPath) in
|
||||
fetchResult.object(at: indexPath.row - 1)
|
||||
}) ?? []
|
||||
return collectionView.indexPathsForSelectedItems?.compactMap { (indexPath) in
|
||||
guard case let .asset(asset) = dataSource.itemIdentifier(for: indexPath) else { return nil }
|
||||
return asset
|
||||
} ?? []
|
||||
}
|
||||
|
||||
init() {
|
||||
|
@ -71,14 +73,42 @@ class AssetCollectionViewController: UICollectionViewController {
|
|||
collectionView.register(UINib(nibName: "AssetCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: reuseIdentifier)
|
||||
collectionView.register(UINib(nibName: "ShowCameraCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: cameraReuseIdentifier)
|
||||
|
||||
dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView, cellProvider: { (collectionView, indexPath, item) -> UICollectionViewCell? in
|
||||
switch item {
|
||||
case .showCamera:
|
||||
return collectionView.dequeueReusableCell(withReuseIdentifier: cameraReuseIdentifier, for: indexPath)
|
||||
case let .asset(asset):
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! AssetCollectionViewCell
|
||||
|
||||
cell.updateUI(asset: asset)
|
||||
self.imageManager.requestImage(for: asset, targetSize: self.thumbnailSize, contentMode: .aspectFill, options: nil) { (image, _) in
|
||||
guard let image = image else { return }
|
||||
DispatchQueue.main.async {
|
||||
guard cell.assetIdentifier == asset.localIdentifier else { return }
|
||||
cell.thumbnailImage = image
|
||||
}
|
||||
}
|
||||
|
||||
return cell
|
||||
}
|
||||
})
|
||||
|
||||
let options = PHFetchOptions()
|
||||
options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
|
||||
fetchResult = fetchAssets(with: options)
|
||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||
snapshot.appendSections([.assets])
|
||||
var items: [Item] = [.showCamera]
|
||||
fetchResult.enumerateObjects { (asset, _, _) in
|
||||
items.append(.asset(asset))
|
||||
}
|
||||
snapshot.appendItems(items)
|
||||
dataSource.apply(snapshot, animatingDifferences: false)
|
||||
|
||||
collectionView.allowsMultipleSelection = true
|
||||
setEditing(true, animated: false)
|
||||
|
||||
updateItemsSelected()
|
||||
updateItemsSelectedCount()
|
||||
|
||||
if let singleFingerPanGesture = collectionView.gestureRecognizers?.first(where: {
|
||||
$0.name == "multi-select.singleFingerPanGesture"
|
||||
|
@ -115,43 +145,12 @@ class AssetCollectionViewController: UICollectionViewController {
|
|||
return PHAsset.fetchAssets(with: options)
|
||||
}
|
||||
|
||||
func updateItemsSelected() {
|
||||
func updateItemsSelectedCount() {
|
||||
let selected = collectionView.indexPathsForSelectedItems?.count ?? 0
|
||||
|
||||
navigationItem.title = "\(selected) selected"
|
||||
}
|
||||
|
||||
// MARK: UICollectionViewDataSource
|
||||
|
||||
override func numberOfSections(in collectionView: UICollectionView) -> Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return fetchResult.count + 1
|
||||
}
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
if indexPath.row == 0 {
|
||||
return collectionView.dequeueReusableCell(withReuseIdentifier: cameraReuseIdentifier, for: indexPath)
|
||||
} else {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! AssetCollectionViewCell
|
||||
|
||||
let asset = fetchResult.object(at: indexPath.row - 1)
|
||||
|
||||
cell.updateUI(asset: asset)
|
||||
imageManager.requestImage(for: asset, targetSize: thumbnailSize, contentMode: .aspectFill, options: nil) { (image, _) in
|
||||
guard let image = image else { return }
|
||||
DispatchQueue.main.async {
|
||||
guard cell.assetIdentifier == asset.localIdentifier else { return }
|
||||
cell.thumbnailImage = image
|
||||
}
|
||||
}
|
||||
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: UICollectionViewDelegate
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, shouldBeginMultipleSelectionInteractionAt indexPath: IndexPath) -> Bool {
|
||||
|
@ -159,37 +158,35 @@ class AssetCollectionViewController: UICollectionViewController {
|
|||
}
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
|
||||
if indexPath.row > 0,
|
||||
let delegate = delegate {
|
||||
let asset = fetchResult.object(at: indexPath.row - 1)
|
||||
guard let item = dataSource.itemIdentifier(for: indexPath) else { return false }
|
||||
if let delegate = delegate,
|
||||
case let .asset(asset) = item {
|
||||
return delegate.shouldSelectAsset(asset)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
if indexPath.row == 0 {
|
||||
guard let item = dataSource.itemIdentifier(for: indexPath) else { return }
|
||||
switch item {
|
||||
case .showCamera:
|
||||
collectionView.deselectItem(at: indexPath, animated: false)
|
||||
delegate?.captureFromCamera()
|
||||
} else {
|
||||
updateItemsSelected()
|
||||
case .asset(_):
|
||||
updateItemsSelectedCount()
|
||||
}
|
||||
}
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
|
||||
updateItemsSelected()
|
||||
updateItemsSelectedCount()
|
||||
}
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
|
||||
if indexPath.row == 0 {
|
||||
return nil
|
||||
} else {
|
||||
let asset = fetchResult.object(at: indexPath.row - 1)
|
||||
guard case let .asset(asset) = dataSource.itemIdentifier(for: indexPath) else { return nil }
|
||||
return UIContextMenuConfiguration(identifier: indexPath as NSIndexPath, previewProvider: { () -> UIViewController? in
|
||||
return AssetPreviewViewController(asset: asset)
|
||||
}, actionProvider: nil)
|
||||
}
|
||||
}
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
|
||||
if let indexPath = (configuration.identifier as? NSIndexPath) as IndexPath?,
|
||||
|
@ -210,3 +207,13 @@ class AssetCollectionViewController: UICollectionViewController {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
extension AssetCollectionViewController {
|
||||
enum Section: Hashable {
|
||||
case assets
|
||||
}
|
||||
enum Item: Hashable {
|
||||
case showCamera
|
||||
case asset(PHAsset)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue