|
@@ -14,6 +14,7 @@ import MobileCoreServices
|
|
|
public protocol TLPhotosPickerViewControllerDelegate: class {
|
|
|
func dismissPhotoPicker(withPHAssets: [PHAsset])
|
|
|
func dismissPhotoPicker(withTLPHAssets: [TLPHAsset])
|
|
|
+ func shouldDismissPhotoPicker(withTLPHAssets: [TLPHAsset]) -> Bool
|
|
|
func dismissComplete()
|
|
|
func photoPickerDidCancel()
|
|
|
func canSelectAsset(phAsset: PHAsset) -> Bool
|
|
@@ -26,6 +27,7 @@ extension TLPhotosPickerViewControllerDelegate {
|
|
|
public func deninedAuthoization() { }
|
|
|
public func dismissPhotoPicker(withPHAssets: [PHAsset]) { }
|
|
|
public func dismissPhotoPicker(withTLPHAssets: [TLPHAsset]) { }
|
|
|
+ public func shouldDismissPhotoPicker(withTLPHAssets: [TLPHAsset]) -> Bool { return true }
|
|
|
public func dismissComplete() { }
|
|
|
public func photoPickerDidCancel() { }
|
|
|
public func canSelectAsset(phAsset: PHAsset) -> Bool { return true }
|
|
@@ -55,9 +57,13 @@ public struct TLPhotosPickerConfigure {
|
|
|
public var cancelTitle = "Cancel"
|
|
|
public var doneTitle = "Done"
|
|
|
public var emptyMessage = "No albums"
|
|
|
+ public var selectMessage = "Select"
|
|
|
+ public var deselectMessage = "Deselect"
|
|
|
public var emptyImage: UIImage? = nil
|
|
|
public var usedCameraButton = true
|
|
|
public var usedPrefetch = false
|
|
|
+ public var previewAtForceTouch = false
|
|
|
+ public var startplayBack: PHLivePhotoViewPlaybackStyle = .hint
|
|
|
public var allowedLivePhotos = true
|
|
|
public var allowedVideo = true
|
|
|
public var allowedAlbumCloudShared = false
|
|
@@ -145,14 +151,13 @@ open class TLPhotosPickerViewController: UIViewController {
|
|
|
public var customDataSouces: TLPhotopickerDataSourcesProtocol? = nil
|
|
|
|
|
|
private var usedCameraButton: Bool {
|
|
|
- get {
|
|
|
- return self.configure.usedCameraButton
|
|
|
- }
|
|
|
+ return self.configure.usedCameraButton
|
|
|
+ }
|
|
|
+ private var previewAtForceTouch: Bool {
|
|
|
+ return self.configure.previewAtForceTouch
|
|
|
}
|
|
|
private var allowedVideo: Bool {
|
|
|
- get {
|
|
|
- return self.configure.allowedVideo
|
|
|
- }
|
|
|
+ return self.configure.allowedVideo
|
|
|
}
|
|
|
private var usedPrefetch: Bool {
|
|
|
get {
|
|
@@ -221,6 +226,12 @@ open class TLPhotosPickerViewController: UIViewController {
|
|
|
|
|
|
open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
|
|
super.traitCollectionDidChange(previousTraitCollection)
|
|
|
+
|
|
|
+ if traitCollection.forceTouchCapability == .available && self.previewAtForceTouch {
|
|
|
+ registerForPreviewing(with: self, sourceView: collectionView)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
if #available(iOS 13.0, *) {
|
|
|
let userInterfaceStyle = self.traitCollection.userInterfaceStyle
|
|
|
let image = TLBundle.podBundleImage(named: "pop_arrow")
|
|
@@ -296,9 +307,10 @@ open class TLPhotosPickerViewController: UIViewController {
|
|
|
}
|
|
|
if
|
|
|
var index = self.focusedCollection?.fetchResult?.index(of: phAsset),
|
|
|
+ let focused = self.focusedCollection,
|
|
|
index != NSNotFound
|
|
|
{
|
|
|
- index += (getfocusedIndex() == 0 && self.configure.usedCameraButton) ? 1 : 0
|
|
|
+ index += (focused.useCameraButton) ? 1 : 0
|
|
|
self.collectionView.reloadItems(at: [IndexPath(row: index, section: 0)])
|
|
|
}
|
|
|
}
|
|
@@ -491,6 +503,7 @@ extension TLPhotosPickerViewController {
|
|
|
}
|
|
|
|
|
|
private func dismiss(done: Bool) {
|
|
|
+ var shouldDismiss = true
|
|
|
if done {
|
|
|
#if swift(>=4.1)
|
|
|
self.delegate?.dismissPhotoPicker(withPHAssets: self.selectedAssets.compactMap{ $0.phAsset })
|
|
@@ -498,6 +511,7 @@ extension TLPhotosPickerViewController {
|
|
|
self.delegate?.dismissPhotoPicker(withPHAssets: self.selectedAssets.flatMap{ $0.phAsset })
|
|
|
#endif
|
|
|
self.delegate?.dismissPhotoPicker(withTLPHAssets: self.selectedAssets)
|
|
|
+ shouldDismiss = self.delegate?.shouldDismissPhotoPicker(withTLPHAssets: self.selectedAssets) ?? true
|
|
|
self.completionWithTLPHAssets?(self.selectedAssets)
|
|
|
#if swift(>=4.1)
|
|
|
self.completionWithPHAssets?(self.selectedAssets.compactMap{ $0.phAsset })
|
|
@@ -508,9 +522,11 @@ extension TLPhotosPickerViewController {
|
|
|
self.delegate?.photoPickerDidCancel()
|
|
|
self.didCancel?()
|
|
|
}
|
|
|
- self.dismiss(animated: true) { [weak self] in
|
|
|
- self?.delegate?.dismissComplete()
|
|
|
- self?.dismissCompletion?()
|
|
|
+ if shouldDismiss {
|
|
|
+ self.dismiss(animated: true) { [weak self] in
|
|
|
+ self?.delegate?.dismissComplete()
|
|
|
+ self?.dismissCompletion?()
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -615,8 +631,8 @@ extension TLPhotosPickerViewController: UIImagePickerControllerDelegate, UINavig
|
|
|
PHPhotoLibrary.shared().performChanges({
|
|
|
let newAssetRequest = PHAssetChangeRequest.creationRequestForAsset(from: image)
|
|
|
placeholderAsset = newAssetRequest.placeholderForCreatedAsset
|
|
|
- }, completionHandler: { [weak self] (sucess, error) in
|
|
|
- if sucess, let `self` = self, let identifier = placeholderAsset?.localIdentifier {
|
|
|
+ }, completionHandler: { [weak self] (success, error) in
|
|
|
+ if success, let `self` = self, let identifier = placeholderAsset?.localIdentifier {
|
|
|
guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [identifier], options: nil).firstObject else { return }
|
|
|
var result = TLPHAsset(asset: asset)
|
|
|
result.selectedOrder = self.selectedAssets.count + 1
|
|
@@ -719,7 +735,7 @@ extension TLPhotosPickerViewController: PHLivePhotoViewDelegate {
|
|
|
cell?.livePhotoView?.isHidden = false
|
|
|
cell?.livePhotoView?.livePhoto = livePhoto
|
|
|
cell?.livePhotoView?.isMuted = true
|
|
|
- cell?.livePhotoView?.startPlayback(with: .hint)
|
|
|
+ cell?.livePhotoView?.startPlayback(with: self.configure.startplayBack)
|
|
|
})
|
|
|
if requestID > 0 {
|
|
|
self.playRequestID = (indexPath,requestID)
|
|
@@ -729,7 +745,7 @@ extension TLPhotosPickerViewController: PHLivePhotoViewDelegate {
|
|
|
|
|
|
public func livePhotoView(_ livePhotoView: PHLivePhotoView, didEndPlaybackWith playbackStyle: PHLivePhotoViewPlaybackStyle) {
|
|
|
livePhotoView.isMuted = true
|
|
|
- livePhotoView.startPlayback(with: .hint)
|
|
|
+ livePhotoView.startPlayback(with: self.configure.startplayBack)
|
|
|
}
|
|
|
|
|
|
public func livePhotoView(_ livePhotoView: PHLivePhotoView, willBeginPlaybackWith playbackStyle: PHLivePhotoViewPlaybackStyle) {
|
|
@@ -879,59 +895,15 @@ extension TLPhotosPickerViewController: UICollectionViewDelegate,UICollectionVie
|
|
|
//Delegate
|
|
|
open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
|
|
guard let collection = self.focusedCollection, let cell = self.collectionView.cellForItem(at: indexPath) as? TLPhotoCollectionViewCell else { return }
|
|
|
+
|
|
|
let isCameraRow = collection.useCameraButton && indexPath.section == 0 && indexPath.row == 0
|
|
|
+
|
|
|
if isCameraRow {
|
|
|
- if Platform.isSimulator {
|
|
|
- print("not supported by the simulator.")
|
|
|
- return
|
|
|
- }else {
|
|
|
- if self.configure.cameraCellNibSet?.nibName != nil {
|
|
|
- cell.selectedCell()
|
|
|
- }else {
|
|
|
- showCameraIfAuthorized()
|
|
|
- }
|
|
|
- self.logDelegate?.selectedCameraCell(picker: self)
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
- guard var asset = collection.getTLAsset(at: indexPath), let phAsset = asset.phAsset else { return }
|
|
|
- cell.popScaleAnim()
|
|
|
- if let index = self.selectedAssets.firstIndex(where: { $0.phAsset == asset.phAsset }) {
|
|
|
- //deselect
|
|
|
- self.logDelegate?.deselectedPhoto(picker: self, at: indexPath.row)
|
|
|
- self.selectedAssets.remove(at: index)
|
|
|
- #if swift(>=4.1)
|
|
|
- self.selectedAssets = self.selectedAssets.enumerated().compactMap({ (offset,asset) -> TLPHAsset? in
|
|
|
- var asset = asset
|
|
|
- asset.selectedOrder = offset + 1
|
|
|
- return asset
|
|
|
- })
|
|
|
- #else
|
|
|
- self.selectedAssets = self.selectedAssets.enumerated().flatMap({ (offset,asset) -> TLPHAsset? in
|
|
|
- var asset = asset
|
|
|
- asset.selectedOrder = offset + 1
|
|
|
- return asset
|
|
|
- })
|
|
|
- #endif
|
|
|
- cell.selectedAsset = false
|
|
|
- cell.stopPlay()
|
|
|
- self.orderUpdateCells()
|
|
|
- if self.playRequestID?.indexPath == indexPath {
|
|
|
- stopPlay()
|
|
|
- }
|
|
|
- }else {
|
|
|
- //select
|
|
|
- self.logDelegate?.selectedPhoto(picker: self, at: indexPath.row)
|
|
|
- guard !maxCheck() else { return }
|
|
|
- guard canSelect(phAsset: phAsset) else { return }
|
|
|
- asset.selectedOrder = self.selectedAssets.count + 1
|
|
|
- self.selectedAssets.append(asset)
|
|
|
- cell.selectedAsset = true
|
|
|
- cell.orderLabel?.text = "\(asset.selectedOrder)"
|
|
|
- if asset.type != .photo, self.configure.autoPlay {
|
|
|
- playVideo(asset: asset, indexPath: indexPath)
|
|
|
- }
|
|
|
+ selectCameraCell(cell)
|
|
|
+ return
|
|
|
}
|
|
|
+
|
|
|
+ toggleSelection(for: cell, at: indexPath)
|
|
|
}
|
|
|
|
|
|
open func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
|
|
@@ -969,6 +941,9 @@ extension TLPhotosPickerViewController: UICollectionViewDelegate,UICollectionVie
|
|
|
return cell
|
|
|
}
|
|
|
guard let asset = collection.getTLAsset(at: indexPath) else { return cell }
|
|
|
+
|
|
|
+ cell.asset = asset.phAsset
|
|
|
+
|
|
|
if let selectedAsset = getSelectedAssets(asset) {
|
|
|
cell.selectedAsset = true
|
|
|
cell.orderLabel?.text = "\(selectedAsset.selectedOrder)"
|
|
@@ -1138,7 +1113,7 @@ extension TLPhotosPickerViewController: UICollectionViewDelegateFlowLayout {
|
|
|
}
|
|
|
|
|
|
// MARK: - UITableView datasource & delegate
|
|
|
-extension TLPhotosPickerViewController: UITableViewDelegate,UITableViewDataSource {
|
|
|
+extension TLPhotosPickerViewController: UITableViewDelegate, UITableViewDataSource {
|
|
|
//delegate
|
|
|
open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
|
self.logDelegate?.selectedAlbum(picker: self, title: self.collections[indexPath.row].title, at: indexPath.row)
|
|
@@ -1174,10 +1149,111 @@ extension TLPhotosPickerViewController: UITableViewDelegate,UITableViewDataSourc
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// MARK: - UIViewControllerPreviewingDelegate
|
|
|
+extension TLPhotosPickerViewController: UIViewControllerPreviewingDelegate {
|
|
|
+ public func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
|
|
|
+ guard self.previewAtForceTouch == true else { return nil }
|
|
|
+ guard let pressingIndexPath = collectionView.indexPathForItem(at: location) else { return nil }
|
|
|
+ guard let pressingCell = collectionView.cellForItem(at: pressingIndexPath) as? TLPhotoCollectionViewCell else { return nil }
|
|
|
+
|
|
|
+ previewingContext.sourceRect = pressingCell.frame
|
|
|
+ let previewController = TLAssetPreviewViewController()
|
|
|
+ previewController.asset = pressingCell.asset
|
|
|
+
|
|
|
+ return previewController
|
|
|
+ }
|
|
|
+
|
|
|
+ public func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {}
|
|
|
+
|
|
|
+ @available(iOS 13.0, *)
|
|
|
+ public func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
|
|
|
+ guard self.previewAtForceTouch == true else { return nil }
|
|
|
+ guard let cell = collectionView.cellForItem(at: indexPath) as? TLPhotoCollectionViewCell else { return nil }
|
|
|
+
|
|
|
+ return UIContextMenuConfiguration(identifier: nil, previewProvider: {
|
|
|
+ let previewController = TLAssetPreviewViewController()
|
|
|
+ previewController.asset = cell.asset
|
|
|
+ return previewController
|
|
|
+
|
|
|
+ }, actionProvider: { [weak self] suggestedActions in
|
|
|
+ guard let self = self else { return nil }
|
|
|
+ let isSelected = cell.selectedAsset
|
|
|
+ let title = isSelected ? self.configure.deselectMessage : self.configure.selectMessage
|
|
|
+ let imageName = isSelected ? "checkmark.circle" : "circle"
|
|
|
+ let toggleSelection = UIAction(title: title, image: UIImage(systemName: imageName)) { [weak self] action in
|
|
|
+ self?.toggleSelection(for: cell, at: indexPath)
|
|
|
+ }
|
|
|
+
|
|
|
+ return UIMenu(title: "", children: [toggleSelection])
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension TLPhotosPickerViewController {
|
|
|
+ func selectCameraCell(_ cell: TLPhotoCollectionViewCell) {
|
|
|
+ if Platform.isSimulator {
|
|
|
+ print("not supported by the simulator.")
|
|
|
+ } else {
|
|
|
+ if configure.cameraCellNibSet?.nibName != nil {
|
|
|
+ cell.selectedCell()
|
|
|
+ } else {
|
|
|
+ showCameraIfAuthorized()
|
|
|
+ }
|
|
|
+ logDelegate?.selectedCameraCell(picker: self)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ func toggleSelection(for cell: TLPhotoCollectionViewCell, at indexPath: IndexPath) {
|
|
|
+ guard let collection = focusedCollection, var asset = collection.getTLAsset(at: indexPath), let phAsset = asset.phAsset else { return }
|
|
|
+
|
|
|
+ cell.popScaleAnim()
|
|
|
+
|
|
|
+ if let index = selectedAssets.firstIndex(where: { $0.phAsset == asset.phAsset }) {
|
|
|
+ //deselect
|
|
|
+ logDelegate?.deselectedPhoto(picker: self, at: indexPath.row)
|
|
|
+ selectedAssets.remove(at: index)
|
|
|
+ #if swift(>=4.1)
|
|
|
+ selectedAssets = selectedAssets.enumerated().compactMap({ (offset,asset) -> TLPHAsset? in
|
|
|
+ var asset = asset
|
|
|
+ asset.selectedOrder = offset + 1
|
|
|
+ return asset
|
|
|
+ })
|
|
|
+ #else
|
|
|
+ selectedAssets = selectedAssets.enumerated().flatMap({ (offset,asset) -> TLPHAsset? in
|
|
|
+ var asset = asset
|
|
|
+ asset.selectedOrder = offset + 1
|
|
|
+ return asset
|
|
|
+ })
|
|
|
+ #endif
|
|
|
+ cell.selectedAsset = false
|
|
|
+ cell.stopPlay()
|
|
|
+ orderUpdateCells()
|
|
|
+ if playRequestID?.indexPath == indexPath {
|
|
|
+ stopPlay()
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //select
|
|
|
+ logDelegate?.selectedPhoto(picker: self, at: indexPath.row)
|
|
|
+ guard !maxCheck(), canSelect(phAsset: phAsset) else { return }
|
|
|
+
|
|
|
+ asset.selectedOrder = selectedAssets.count + 1
|
|
|
+ selectedAssets.append(asset)
|
|
|
+ cell.selectedAsset = true
|
|
|
+ cell.orderLabel?.text = "\(asset.selectedOrder)"
|
|
|
+
|
|
|
+ if asset.type != .photo, configure.autoPlay {
|
|
|
+ playVideo(asset: asset, indexPath: indexPath)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
extension Array where Element == PopupConfigure {
|
|
|
var duration: TimeInterval {
|
|
|
var result: TimeInterval = 0.1
|
|
|
- self.compactMap{ $0 as? PopupConfigure }.forEach{
|
|
|
+ forEach {
|
|
|
if case let .animation(duration) = $0 {
|
|
|
result = duration
|
|
|
}
|