Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limit number of image or video #307

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions BSImagePicker.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 45 additions & 0 deletions Example.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 = "<group>"; };
551D6966230FCDDC006B1481 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
Expand All @@ -53,6 +55,8 @@
55300E07222ED2530086E439 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
55300E09222ED2530086E439 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -68,6 +72,7 @@
buildActionMask = 2147483647;
files = (
55F67B7C222F106F00805134 /* BSImagePicker.framework in Frameworks */,
A4A434623B005765DB145BCA /* libPods-Example.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -90,6 +95,7 @@
551D6963230FCDDC006B1481 /* UITests */,
55300DFB222ED2520086E439 /* Products */,
55F67B65222ED56300805134 /* Frameworks */,
B9FB7690A29687B624C8F391 /* Pods */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -119,10 +125,21 @@
isa = PBXGroup;
children = (
55F67B66222ED56300805134 /* BSImagePicker.framework */,
438C0948FCFA747524306BEF /* libPods-Example.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
B9FB7690A29687B624C8F391 /* Pods */ = {
isa = PBXGroup;
children = (
5B6E1AEA5DFC7D6A4B2D8F0C /* Pods-Example.debug.xcconfig */,
B6F27CE7255ABDEA75EB13D2 /* Pods-Example.release.xcconfig */,
);
name = Pods;
path = Example/Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand All @@ -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 */,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -429,6 +472,7 @@
};
55300E18222ED2530086E439 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5B6E1AEA5DFC7D6A4B2D8F0C /* Pods-Example.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
Expand All @@ -448,6 +492,7 @@
};
55300E19222ED2530086E439 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = B6F27CE7255ABDEA75EB13D2 /* Pods-Example.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
Expand Down
27 changes: 21 additions & 6 deletions Example/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
Expand All @@ -19,7 +20,7 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GFw-cP-rmQ">
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GFw-cP-rmQ">
<rect key="frame" x="143.5" y="318.5" width="88" height="30"/>
<state key="normal" title="Image picker">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
Expand All @@ -28,7 +29,7 @@
<action selector="showImagePicker:" destination="BYZ-38-t0r" eventType="touchUpInside" id="LaC-Tl-d1J"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DzO-ex-PdY">
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DzO-ex-PdY">
<rect key="frame" x="114.5" y="356.5" width="146" height="30"/>
<constraints>
<constraint firstAttribute="width" constant="146" id="Cd2-rJ-ekE"/>
Expand All @@ -41,7 +42,7 @@
<action selector="showCustomImagePicker:" destination="BYZ-38-t0r" eventType="touchUpInside" id="GKA-nS-l2H"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="zgs-tU-5p9">
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="zgs-tU-5p9">
<rect key="frame" x="71.5" y="394.5" width="232" height="30"/>
<constraints>
<constraint firstAttribute="width" constant="232" id="IRj-9r-lbP"/>
Expand All @@ -52,12 +53,21 @@
<action selector="showImagePickerWithSelectedAssets:" destination="BYZ-38-t0r" eventType="touchUpInside" id="m00-0a-bkf"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ywf-iF-6QR">
<rect key="frame" x="66" y="432.5" width="243" height="30"/>
<state key="normal" title="Image picker limit 2 images, 1 video"/>
<connections>
<action selector="showImagePickerWithLimit:" destination="BYZ-38-t0r" eventType="touchUpInside" id="chb-F8-vjn"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="zgs-tU-5p9" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="0A6-aX-1jb"/>
<constraint firstAttribute="centerX" secondItem="DzO-ex-PdY" secondAttribute="centerX" id="EZn-Ed-pHh"/>
<constraint firstItem="zgs-tU-5p9" firstAttribute="top" secondItem="DzO-ex-PdY" secondAttribute="bottom" constant="8" id="GUE-MX-lLP"/>
<constraint firstItem="Ywf-iF-6QR" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="JYd-Ph-njS"/>
<constraint firstItem="Ywf-iF-6QR" firstAttribute="top" secondItem="zgs-tU-5p9" secondAttribute="bottom" constant="8" id="VjK-Iu-ymf"/>
<constraint firstAttribute="centerY" secondItem="GFw-cP-rmQ" secondAttribute="centerY" id="XmI-RH-XSN"/>
<constraint firstItem="DzO-ex-PdY" firstAttribute="top" secondItem="GFw-cP-rmQ" secondAttribute="bottom" constant="8" id="j2M-qn-wIK"/>
<constraint firstAttribute="centerX" secondItem="GFw-cP-rmQ" secondAttribute="centerX" id="vJT-bW-R2W"/>
Expand All @@ -69,4 +79,9 @@
<point key="canvasLocation" x="138" y="134"/>
</scene>
</scenes>
<resources>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
46 changes: 43 additions & 3 deletions Example/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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
Expand Down Expand Up @@ -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)")
Expand All @@ -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)
}
}

4 changes: 4 additions & 0 deletions Sources/Controller/ImagePickerController+Assets.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,8 @@ extension ImagePickerController: AssetsViewControllerDelegate {

pushViewController(previewViewController, animated: true)
}

func assetsViewController(_ assetsViewController: AssetsViewController, didReachSelectionLimit asset: PHAsset) {
imagePickerDelegate?.imagePicker(self, didReachSelectionLimitForType: asset.mediaType)
}
}
3 changes: 3 additions & 0 deletions Sources/Controller/ImagePickerController+Closure.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ extension ImagePickerController {

/// ImagePickerControllerDelegate closure wrapper
extension ImagePickerController: ImagePickerControllerDelegate {
huylv-teko marked this conversation as resolved.
Show resolved Hide resolved
public func imagePicker(_ imagePicker: ImagePickerController, didReachSelectionLimitForType type: PHAssetMediaType) {
}

public func imagePicker(_ imagePicker: ImagePickerController, didSelectAsset asset: PHAsset) {
onSelection?(asset)
}
Expand Down
5 changes: 5 additions & 0 deletions Sources/Controller/ImagePickerControllerDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
4 changes: 4 additions & 0 deletions Sources/Model/AssetStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
10 changes: 5 additions & 5 deletions Sources/Model/Settings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -137,7 +137,7 @@ import Photos
}
}
}
public lazy var supportedMediaTypes: Set<MediaTypes> = [.image]
public lazy var supportedMediaTypes: Set<MediaTypes> = [.image()]

public lazy var options: PHFetchOptions = {
let fetchOptions = PHFetchOptions()
Expand Down