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?
|
weak var delegate: AssetCollectionViewControllerDelegate?
|
||||||
|
|
||||||
var flowLayout: UICollectionViewFlowLayout {
|
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
|
||||||
|
private var flowLayout: UICollectionViewFlowLayout {
|
||||||
return collectionViewLayout as! UICollectionViewFlowLayout
|
return collectionViewLayout as! UICollectionViewFlowLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
var availableWidth: CGFloat!
|
private var availableWidth: CGFloat!
|
||||||
var thumbnailSize: CGSize!
|
private var thumbnailSize: CGSize!
|
||||||
|
|
||||||
let imageManager = PHCachingImageManager()
|
private let imageManager = PHCachingImageManager()
|
||||||
var fetchResult: PHFetchResult<PHAsset>!
|
private var fetchResult: PHFetchResult<PHAsset>!
|
||||||
|
|
||||||
var selectedAssets: [PHAsset] {
|
var selectedAssets: [PHAsset] {
|
||||||
return collectionView.indexPathsForSelectedItems?.map({ (indexPath) in
|
return collectionView.indexPathsForSelectedItems?.compactMap { (indexPath) in
|
||||||
fetchResult.object(at: indexPath.row - 1)
|
guard case let .asset(asset) = dataSource.itemIdentifier(for: indexPath) else { return nil }
|
||||||
}) ?? []
|
return asset
|
||||||
|
} ?? []
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
@ -71,14 +73,42 @@ class AssetCollectionViewController: UICollectionViewController {
|
||||||
collectionView.register(UINib(nibName: "AssetCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: reuseIdentifier)
|
collectionView.register(UINib(nibName: "AssetCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: reuseIdentifier)
|
||||||
collectionView.register(UINib(nibName: "ShowCameraCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: cameraReuseIdentifier)
|
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()
|
let options = PHFetchOptions()
|
||||||
options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
|
options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
|
||||||
fetchResult = fetchAssets(with: options)
|
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
|
collectionView.allowsMultipleSelection = true
|
||||||
setEditing(true, animated: false)
|
setEditing(true, animated: false)
|
||||||
|
|
||||||
updateItemsSelected()
|
updateItemsSelectedCount()
|
||||||
|
|
||||||
if let singleFingerPanGesture = collectionView.gestureRecognizers?.first(where: {
|
if let singleFingerPanGesture = collectionView.gestureRecognizers?.first(where: {
|
||||||
$0.name == "multi-select.singleFingerPanGesture"
|
$0.name == "multi-select.singleFingerPanGesture"
|
||||||
|
@ -115,43 +145,12 @@ class AssetCollectionViewController: UICollectionViewController {
|
||||||
return PHAsset.fetchAssets(with: options)
|
return PHAsset.fetchAssets(with: options)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateItemsSelected() {
|
func updateItemsSelectedCount() {
|
||||||
let selected = collectionView.indexPathsForSelectedItems?.count ?? 0
|
let selected = collectionView.indexPathsForSelectedItems?.count ?? 0
|
||||||
|
|
||||||
navigationItem.title = "\(selected) selected"
|
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
|
// MARK: UICollectionViewDelegate
|
||||||
|
|
||||||
override func collectionView(_ collectionView: UICollectionView, shouldBeginMultipleSelectionInteractionAt indexPath: IndexPath) -> Bool {
|
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 {
|
override func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
|
||||||
if indexPath.row > 0,
|
guard let item = dataSource.itemIdentifier(for: indexPath) else { return false }
|
||||||
let delegate = delegate {
|
if let delegate = delegate,
|
||||||
let asset = fetchResult.object(at: indexPath.row - 1)
|
case let .asset(asset) = item {
|
||||||
return delegate.shouldSelectAsset(asset)
|
return delegate.shouldSelectAsset(asset)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
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)
|
collectionView.deselectItem(at: indexPath, animated: false)
|
||||||
delegate?.captureFromCamera()
|
delegate?.captureFromCamera()
|
||||||
} else {
|
case .asset(_):
|
||||||
updateItemsSelected()
|
updateItemsSelectedCount()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
|
override func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
|
||||||
updateItemsSelected()
|
updateItemsSelectedCount()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
|
override func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
|
||||||
if indexPath.row == 0 {
|
guard case let .asset(asset) = dataSource.itemIdentifier(for: indexPath) else { return nil }
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
let asset = fetchResult.object(at: indexPath.row - 1)
|
|
||||||
return UIContextMenuConfiguration(identifier: indexPath as NSIndexPath, previewProvider: { () -> UIViewController? in
|
return UIContextMenuConfiguration(identifier: indexPath as NSIndexPath, previewProvider: { () -> UIViewController? in
|
||||||
return AssetPreviewViewController(asset: asset)
|
return AssetPreviewViewController(asset: asset)
|
||||||
}, actionProvider: nil)
|
}, actionProvider: nil)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override func collectionView(_ collectionView: UICollectionView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
|
override func collectionView(_ collectionView: UICollectionView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
|
||||||
if let indexPath = (configuration.identifier as? NSIndexPath) as IndexPath?,
|
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