diff --git a/BSImagePicker.xcworkspace/contents.xcworkspacedata b/BSImagePicker.xcworkspace/contents.xcworkspacedata
index a27d092e..11628338 100644
--- a/BSImagePicker.xcworkspace/contents.xcworkspacedata
+++ b/BSImagePicker.xcworkspace/contents.xcworkspacedata
@@ -7,4 +7,7 @@
+
+
diff --git a/Example.xcodeproj/project.pbxproj b/Example.xcodeproj/project.pbxproj
index 9538c31c..3306b125 100644
--- a/Example.xcodeproj/project.pbxproj
+++ b/Example.xcodeproj/project.pbxproj
@@ -15,6 +15,7 @@
55300E08222ED2530086E439 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 55300E06222ED2530086E439 /* LaunchScreen.storyboard */; };
55F67B7C222F106F00805134 /* BSImagePicker.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55F67B66222ED56300805134 /* BSImagePicker.framework */; };
55F67B7D222F106F00805134 /* BSImagePicker.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 55F67B66222ED56300805134 /* BSImagePicker.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ A4A434623B005765DB145BCA /* libPods-Example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 438C0948FCFA747524306BEF /* libPods-Example.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -42,6 +43,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 438C0948FCFA747524306BEF /* libPods-Example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Example.a"; sourceTree = BUILT_PRODUCTS_DIR; };
551D6962230FCDDC006B1481 /* UITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
551D6964230FCDDC006B1481 /* UITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITests.swift; sourceTree = ""; };
551D6966230FCDDC006B1481 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
@@ -53,6 +55,8 @@
55300E07222ED2530086E439 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
55300E09222ED2530086E439 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
55F67B66222ED56300805134 /* BSImagePicker.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BSImagePicker.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 5B6E1AEA5DFC7D6A4B2D8F0C /* Pods-Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.debug.xcconfig"; path = "Target Support Files/Pods-Example/Pods-Example.debug.xcconfig"; sourceTree = ""; };
+ B6F27CE7255ABDEA75EB13D2 /* Pods-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.release.xcconfig"; path = "Target Support Files/Pods-Example/Pods-Example.release.xcconfig"; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -68,6 +72,7 @@
buildActionMask = 2147483647;
files = (
55F67B7C222F106F00805134 /* BSImagePicker.framework in Frameworks */,
+ A4A434623B005765DB145BCA /* libPods-Example.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -90,6 +95,7 @@
551D6963230FCDDC006B1481 /* UITests */,
55300DFB222ED2520086E439 /* Products */,
55F67B65222ED56300805134 /* Frameworks */,
+ B9FB7690A29687B624C8F391 /* Pods */,
);
sourceTree = "";
};
@@ -119,10 +125,21 @@
isa = PBXGroup;
children = (
55F67B66222ED56300805134 /* BSImagePicker.framework */,
+ 438C0948FCFA747524306BEF /* libPods-Example.a */,
);
name = Frameworks;
sourceTree = "";
};
+ B9FB7690A29687B624C8F391 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ 5B6E1AEA5DFC7D6A4B2D8F0C /* Pods-Example.debug.xcconfig */,
+ B6F27CE7255ABDEA75EB13D2 /* Pods-Example.release.xcconfig */,
+ );
+ name = Pods;
+ path = Example/Pods;
+ sourceTree = "";
+ };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -148,6 +165,7 @@
isa = PBXNativeTarget;
buildConfigurationList = 55300E17222ED2530086E439 /* Build configuration list for PBXNativeTarget "Example" */;
buildPhases = (
+ 01CBEF346D56BCF09FAE864C /* [CP] Check Pods Manifest.lock */,
55300DF6222ED2520086E439 /* Sources */,
55300DF7222ED2520086E439 /* Frameworks */,
55300DF8222ED2520086E439 /* Resources */,
@@ -221,6 +239,31 @@
};
/* End PBXResourcesBuildPhase section */
+/* Begin PBXShellScriptBuildPhase section */
+ 01CBEF346D56BCF09FAE864C /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Example-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
/* Begin PBXSourcesBuildPhase section */
551D695E230FCDDC006B1481 /* Sources */ = {
isa = PBXSourcesBuildPhase;
@@ -429,6 +472,7 @@
};
55300E18222ED2530086E439 /* Debug */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 5B6E1AEA5DFC7D6A4B2D8F0C /* Pods-Example.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
@@ -448,6 +492,7 @@
};
55300E19222ED2530086E439 /* Release */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = B6F27CE7255ABDEA75EB13D2 /* Pods-Example.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
diff --git a/Example/Base.lproj/Main.storyboard b/Example/Base.lproj/Main.storyboard
index 214f6c2e..614dad57 100644
--- a/Example/Base.lproj/Main.storyboard
+++ b/Example/Base.lproj/Main.storyboard
@@ -1,9 +1,10 @@
-
+
-
+
+
@@ -19,7 +20,7 @@
-
-
+
+
+
@@ -69,4 +79,9 @@
+
+
+
+
+
diff --git a/Example/ViewController.swift b/Example/ViewController.swift
index a36de3fb..b1bceca7 100644
--- a/Example/ViewController.swift
+++ b/Example/ViewController.swift
@@ -30,7 +30,7 @@ class ViewController: UIViewController {
let imagePicker = ImagePickerController()
imagePicker.settings.selection.max = 5
imagePicker.settings.theme.selectionStyle = .numbered
- imagePicker.settings.fetch.assets.supportedMediaTypes = [.image, .video]
+ imagePicker.settings.fetch.assets.supportedMediaTypes = [.image(), .video()]
imagePicker.settings.selection.unselectOnReachingMax = true
let start = Date()
@@ -52,7 +52,7 @@ class ViewController: UIViewController {
let imagePicker = ImagePickerController()
imagePicker.settings.selection.max = 1
imagePicker.settings.selection.unselectOnReachingMax = true
- imagePicker.settings.fetch.assets.supportedMediaTypes = [.image, .video]
+ imagePicker.settings.fetch.assets.supportedMediaTypes = [.image(), .video()]
imagePicker.albumButton.tintColor = UIColor.green
imagePicker.cancelButton.tintColor = UIColor.red
imagePicker.doneButton.tintColor = UIColor.purple
@@ -99,7 +99,7 @@ class ViewController: UIViewController {
})
let imagePicker = ImagePickerController(selectedAssets: evenAssets)
- imagePicker.settings.fetch.assets.supportedMediaTypes = [.image]
+ imagePicker.settings.fetch.assets.supportedMediaTypes = [.image()]
self.presentImagePicker(imagePicker, select: { (asset) in
print("Selected: \(asset)")
@@ -111,5 +111,45 @@ class ViewController: UIViewController {
print("Finished with selections: \(assets)")
})
}
+
+ @IBAction func showImagePickerWithLimit(_ sender: Any) {
+ let imagePicker = ImagePickerController()
+ imagePicker.settings.selection.max = 5
+ imagePicker.settings.theme.selectionStyle = .numbered
+ imagePicker.settings.fetch.assets.supportedMediaTypes = [
+ .image(max: 2),
+ .video(max: 1)
+ ]
+
+ imagePicker.imagePickerDelegate = self
+ self.present(imagePicker, animated: true)
+
+ }
+}
+
+extension ViewController: ImagePickerControllerDelegate {
+ func imagePicker(_ imagePicker: ImagePickerController, didSelectAsset asset: PHAsset) {
+ print("Selected: \(asset)")
+ }
+
+ func imagePicker(_ imagePicker: ImagePickerController, didDeselectAsset asset: PHAsset) {
+ print("Deselected: \(asset)")
+ }
+
+ func imagePicker(_ imagePicker: ImagePickerController, didFinishWithAssets assets: [PHAsset]) {
+ print("Finished with selections: \(assets)")
+ }
+
+ func imagePicker(_ imagePicker: ImagePickerController, didCancelWithAssets assets: [PHAsset]) {
+ print("Canceled with selections: \(assets)")
+ }
+
+ func imagePicker(_ imagePicker: ImagePickerController, didReachSelectionLimit count: Int) {
+ print("didReachSelectionLimit with count: ", count)
+ }
+
+ func imagePicker(_ imagePicker: ImagePickerController, didReachSelectionLimitForType type: PHAssetMediaType) {
+ print("didReachSelectionLimitForType: ", type.rawValue)
+ }
}
diff --git a/Sources/Controller/ImagePickerController+Assets.swift b/Sources/Controller/ImagePickerController+Assets.swift
index 24b0abfb..c0816b2f 100644
--- a/Sources/Controller/ImagePickerController+Assets.swift
+++ b/Sources/Controller/ImagePickerController+Assets.swift
@@ -52,4 +52,8 @@ extension ImagePickerController: AssetsViewControllerDelegate {
pushViewController(previewViewController, animated: true)
}
+
+ func assetsViewController(_ assetsViewController: AssetsViewController, didReachSelectionLimit asset: PHAsset) {
+ imagePickerDelegate?.imagePicker(self, didReachSelectionLimitForType: asset.mediaType)
+ }
}
diff --git a/Sources/Controller/ImagePickerController+Closure.swift b/Sources/Controller/ImagePickerController+Closure.swift
index 2b98e6e1..0da040a1 100644
--- a/Sources/Controller/ImagePickerController+Closure.swift
+++ b/Sources/Controller/ImagePickerController+Closure.swift
@@ -73,6 +73,9 @@ extension ImagePickerController {
/// ImagePickerControllerDelegate closure wrapper
extension ImagePickerController: ImagePickerControllerDelegate {
+ public func imagePicker(_ imagePicker: ImagePickerController, didReachSelectionLimitForType type: PHAssetMediaType) {
+ }
+
public func imagePicker(_ imagePicker: ImagePickerController, didSelectAsset asset: PHAsset) {
onSelection?(asset)
}
diff --git a/Sources/Controller/ImagePickerControllerDelegate.swift b/Sources/Controller/ImagePickerControllerDelegate.swift
index 51bd48c7..c1f41c86 100644
--- a/Sources/Controller/ImagePickerControllerDelegate.swift
+++ b/Sources/Controller/ImagePickerControllerDelegate.swift
@@ -49,4 +49,9 @@ public protocol ImagePickerControllerDelegate: class {
/// - Parameter imagePicker: The image picker that selection limit was reached in.
/// - Parameter count: Number of selected assets.
func imagePicker(_ imagePicker: ImagePickerController, didReachSelectionLimit count: Int)
+
+ /// Selection limit reach by type
+ /// - Parameter imagePicker: The image picker that selection limit was reached in.
+ /// - Parameter type: Type of media which reaches limit.
+ func imagePicker(_ imagePicker: ImagePickerController, didReachSelectionLimitForType type: PHAssetMediaType)
}
diff --git a/Sources/Model/AssetStore.swift b/Sources/Model/AssetStore.swift
index e037dd15..5431d8a3 100644
--- a/Sources/Model/AssetStore.swift
+++ b/Sources/Model/AssetStore.swift
@@ -55,4 +55,8 @@ import Photos
func index(of asset: PHAsset) -> Int? {
return assets.firstIndex(of: asset)
}
+
+ func getCountByType(_ type: PHAssetMediaType) -> Int {
+ return assets.filter { $0.mediaType == type }.count
+ }
}
diff --git a/Sources/Model/Settings.swift b/Sources/Model/Settings.swift
index 70a0d1bf..c73c7d54 100755
--- a/Sources/Model/Settings.swift
+++ b/Sources/Model/Settings.swift
@@ -124,11 +124,11 @@ import Photos
/// Fetch options for assets
/// Simple wrapper around PHAssetMediaType to ensure we only expose the supported types.
- public enum MediaTypes {
- case image
- case video
+ public enum MediaTypes: Hashable {
+ case image(max: Int = Int.max)
+ case video(max: Int = Int.max)
- fileprivate var assetMediaType: PHAssetMediaType {
+ var assetMediaType: PHAssetMediaType {
switch self {
case .image:
return .image
@@ -137,7 +137,7 @@ import Photos
}
}
}
- public lazy var supportedMediaTypes: Set = [.image]
+ public lazy var supportedMediaTypes: Set = [.image()]
public lazy var options: PHFetchOptions = {
let fetchOptions = PHFetchOptions()
diff --git a/Sources/Scene/Assets/AssetsViewController.swift b/Sources/Scene/Assets/AssetsViewController.swift
index c1c1cbc3..21f150d8 100644
--- a/Sources/Scene/Assets/AssetsViewController.swift
+++ b/Sources/Scene/Assets/AssetsViewController.swift
@@ -27,6 +27,7 @@ protocol AssetsViewControllerDelegate: class {
func assetsViewController(_ assetsViewController: AssetsViewController, didSelectAsset asset: PHAsset)
func assetsViewController(_ assetsViewController: AssetsViewController, didDeselectAsset asset: PHAsset)
func assetsViewController(_ assetsViewController: AssetsViewController, didLongPressCell cell: AssetCollectionViewCell, displayingAsset asset: PHAsset)
+ func assetsViewController(_ assetsViewController: AssetsViewController, didReachSelectionLimit asset: PHAsset)
}
class AssetsViewController: UIViewController {
@@ -195,7 +196,22 @@ extension AssetsViewController: UICollectionViewDelegate {
}
func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
- guard store.count < settings.selection.max || settings.selection.unselectOnReachingMax else { return false }
+ let asset = fetchResult.object(at: indexPath.row)
+ for type in settings.fetch.assets.supportedMediaTypes {
+ switch type {
+ case .image(let max), .video(let max):
+ if asset.mediaType == type.assetMediaType {
+ if max <= store.getCountByType(type.assetMediaType) {
+ self.delegate?.assetsViewController(self, didReachSelectionLimit: asset)
+ return false
+ }
+ }
+ }
+ }
+
+ guard store.count < settings.selection.max || settings.selection.unselectOnReachingMax else {
+ return false
+ }
selectionFeedback.prepare()
return true