Compare commits
90 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
52716045fc | |
|
|
2bcf6d33df | |
|
|
c19996eddb | |
|
|
42e4b4fcf3 | |
|
|
9362d7ebd1 | |
|
|
324f4bf207 | |
|
|
f39a38a615 | |
|
|
5c7102fad6 | |
|
|
f44c660e17 | |
|
|
f86c28822b | |
|
|
51e3c6c870 | |
|
|
78a1861f04 | |
|
|
7160ddb436 | |
|
|
d28c68a2c2 | |
|
|
4334d458eb | |
|
|
60216c5f90 | |
|
|
27997da165 | |
|
|
d17ebd4820 | |
|
|
ac6edd1e3b | |
|
|
e067d8c68f | |
|
|
2476d779d4 | |
|
|
973f672b12 | |
|
|
555a19bcc9 | |
|
|
0768a23570 | |
|
|
a31ead43ab | |
|
|
54042e744b | |
|
|
338efc533f | |
|
|
688ced9981 | |
|
|
df819fffb9 | |
|
|
753332e8ff | |
|
|
8eb6575aaf | |
|
|
dac1bba0cb | |
|
|
c6a501b4cb | |
|
|
98a17c6e2b | |
|
|
cf3868fcaf | |
|
|
919d6d6873 | |
|
|
357443a6b7 | |
|
|
8846e8c28d | |
|
|
4f31eaafc7 | |
|
|
d1d65e9cf1 | |
|
|
9b66207137 | |
|
|
2698510de5 | |
|
|
dd9017ec9e | |
|
|
677eb1a51d | |
|
|
97f6814c1d | |
|
|
e1fa97ea2d | |
|
|
5b4c6b5c3a | |
|
|
d822cdf449 | |
|
|
b0fdba4fd2 | |
|
|
c0c34eae5d | |
|
|
4536b5a2d9 | |
|
|
0e98d5acfb | |
|
|
790b948574 | |
|
|
91249c4459 | |
|
|
7250e1d962 | |
|
|
0130329564 | |
|
|
ef9b35d64a | |
|
|
22971c96a6 | |
|
|
38dfaa16c0 | |
|
|
eafd52c8ac | |
|
|
d58a9bd994 | |
|
|
7d9503ce0c | |
|
|
f5fcd704bb | |
|
|
9008253a55 | |
|
|
01bdb7fcca | |
|
|
2454d1057b | |
|
|
c16999c312 | |
|
|
840e133ae2 | |
|
|
b939ab137c | |
|
|
d508cf3461 | |
|
|
860285d6d9 | |
|
|
459e51f56e | |
|
|
6d1e4529ef | |
|
|
6d091690e5 | |
|
|
6820091576 | |
|
|
f59be657cd | |
|
|
accfe28f8e | |
|
|
15a97c706e | |
|
|
f4d9d0e1f5 | |
|
|
9cfe813b85 | |
|
|
d4062ef8c8 | |
|
|
de500efa96 | |
|
|
cf077f0d56 | |
|
|
5bff5ee1fb | |
|
|
ddbb570c7b | |
|
|
b2c890658f | |
|
|
512b5202be | |
|
|
25a6f81aa3 | |
|
|
567ee0d93d | |
|
|
4381c4e614 |
|
|
@ -0,0 +1 @@
|
|||
4.2
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
disabled_rules: # rule identifiers to exclude from running
|
||||
- todo
|
||||
# - colon
|
||||
# - comma
|
||||
# - control_statement
|
||||
- file_length
|
||||
- force_cast
|
||||
- force_try
|
||||
- function_body_length
|
||||
# - leading_whitespace
|
||||
- line_length
|
||||
- legacy_constructor
|
||||
- nesting
|
||||
# - opening_brace
|
||||
# - operator_whitespace
|
||||
# - return_arrow_whitespace
|
||||
# - statement_position
|
||||
# - todo
|
||||
# - trailing_newline
|
||||
# - trailing_semicolon
|
||||
# - trailing_whitespace
|
||||
- type_body_length
|
||||
- type_name
|
||||
- variable_name_max_length
|
||||
- variable_name_min_length
|
||||
- variable_name
|
||||
- valid_docs
|
||||
- function_parameter_count
|
||||
- cyclomatic_complexity
|
||||
excluded: # paths to ignore during linting.
|
||||
- Carthage
|
||||
- Pods
|
||||
- .git
|
||||
# parameterized rules can be customized from this configuration file
|
||||
line_length: 300 # default 100
|
||||
type_body_length:
|
||||
- 200 # warning default 200
|
||||
- 650 # error default 350
|
||||
function_body_length:
|
||||
- 80 # warning default 40
|
||||
- 250 # error default 100
|
||||
file_length:
|
||||
- 400 # warning default 400
|
||||
- 1300 # error default 1000
|
||||
variable_name_min_length:
|
||||
- 1 # warning default 3
|
||||
- 0 # error default 2
|
||||
|
|
@ -22,33 +22,32 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
var window: UIWindow?
|
||||
|
||||
|
||||
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillResignActive(application: UIApplication) {
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
|
||||
}
|
||||
|
||||
func applicationDidEnterBackground(application: UIApplication) {
|
||||
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
}
|
||||
|
||||
func applicationWillEnterForeground(application: UIApplication) {
|
||||
func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(application: UIApplication) {
|
||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||
}
|
||||
|
||||
func applicationWillTerminate(application: UIApplication) {
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,15 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
|
|
@ -32,6 +42,16 @@
|
|||
"filename" : "180.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
|
|
@ -69,6 +89,11 @@
|
|||
"idiom" : "ipad",
|
||||
"filename" : "167.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"size" : "1024x1024",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9532" systemVersion="15E65" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="q5W-GZ-eHb">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13196" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="q5W-GZ-eHb">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13173"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--NohanaImagePicker-->
|
||||
|
|
@ -10,22 +14,22 @@
|
|||
<objects>
|
||||
<tableViewController id="G3T-A5-GIu" customClass="DemoListViewController" customModule="Demo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="LNK-dE-8Ye">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" textLabel="lwK-uA-3Me" style="IBUITableViewCellStyleDefault" id="6f6-ob-xNw">
|
||||
<rect key="frame" x="0.0" y="92" width="600" height="44"/>
|
||||
<rect key="frame" x="0.0" y="28" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="6f6-ob-xNw" id="VH4-Rk-3Uo">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="lwK-uA-3Me">
|
||||
<rect key="frame" x="15" y="0.0" width="570" height="43.5"/>
|
||||
<rect key="frame" x="16" y="0.0" width="344" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
|
|
@ -49,7 +53,7 @@
|
|||
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="q5W-GZ-eHb" sceneMemberID="viewController">
|
||||
<toolbarItems/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="RTV-gX-iYb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<nil name="viewControllers"/>
|
||||
|
|
|
|||
|
|
@ -23,159 +23,172 @@ struct Cell {
|
|||
}
|
||||
|
||||
class DemoListViewController: UITableViewController, NohanaImagePickerControllerDelegate {
|
||||
|
||||
|
||||
let cells = [
|
||||
Cell(title: "Default", selector: #selector(DemoListViewController.showDefaultPicker)),
|
||||
Cell(title: "Large thumbnail", selector: #selector(DemoListViewController.showLargeThumbnailPicker)),
|
||||
Cell(title: "No toolbar", selector: #selector(DemoListViewController.showNoToolbarPicker)),
|
||||
Cell(title: "Disable to pick assets", selector: #selector(DemoListViewController.showDisableToPickAssetsPicker)),
|
||||
Cell(title: "Custom UI", selector: #selector(DemoListViewController.showCustomUIPicker)),
|
||||
]
|
||||
|
||||
override func viewDidAppear(animated: Bool) {
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
if let indexPathForSelectedRow = tableView.indexPathForSelectedRow {
|
||||
tableView.deselectRowAtIndexPath(indexPathForSelectedRow, animated: true)
|
||||
tableView.deselectRow(at: indexPathForSelectedRow, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return cells.count
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("Cell")!
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!
|
||||
cell.textLabel?.text = cells[indexPath.row].title
|
||||
return cell
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
checkIfAuthorizedToAccessPhotos { isAuthorized in
|
||||
dispatch_async(dispatch_get_main_queue(), {
|
||||
DispatchQueue.main.async(execute: {
|
||||
if isAuthorized {
|
||||
self.performSelector(self.cells[indexPath.row].selector)
|
||||
self.perform(self.cells[indexPath.row].selector)
|
||||
} else {
|
||||
let alert = UIAlertController(title: "Error", message: "Denied access to photos.", preferredStyle: .Alert)
|
||||
alert.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil))
|
||||
self.presentViewController(alert, animated: true, completion: nil)
|
||||
let alert = UIAlertController(title: "Error", message: "Denied access to photos.", preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Photos
|
||||
|
||||
func checkIfAuthorizedToAccessPhotos(handler: (isAuthorized: Bool) -> Void) {
|
||||
|
||||
func checkIfAuthorizedToAccessPhotos(_ handler: @escaping (_ isAuthorized: Bool) -> Void) {
|
||||
switch PHPhotoLibrary.authorizationStatus() {
|
||||
case .NotDetermined:
|
||||
PHPhotoLibrary.requestAuthorization{ status in
|
||||
switch status {
|
||||
case .Authorized:
|
||||
handler(isAuthorized: true)
|
||||
default:
|
||||
handler(isAuthorized: false)
|
||||
case .notDetermined:
|
||||
PHPhotoLibrary.requestAuthorization { status in
|
||||
DispatchQueue.main.async {
|
||||
switch status {
|
||||
case .authorized:
|
||||
handler(true)
|
||||
default:
|
||||
handler(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case .Restricted:
|
||||
handler(isAuthorized: false)
|
||||
case .Denied:
|
||||
handler(isAuthorized: false)
|
||||
case .Authorized:
|
||||
handler(isAuthorized: true)
|
||||
case .restricted:
|
||||
handler(false)
|
||||
case .denied:
|
||||
handler(false)
|
||||
case .authorized:
|
||||
handler(true)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Show NohanaImagePicker
|
||||
|
||||
@objc
|
||||
func showDefaultPicker() {
|
||||
@objc func showDefaultPicker() {
|
||||
let picker = NohanaImagePickerController()
|
||||
picker.delegate = self
|
||||
presentViewController(picker, animated: true, completion: nil)
|
||||
present(picker, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@objc
|
||||
func showLargeThumbnailPicker() {
|
||||
@objc func showLargeThumbnailPicker() {
|
||||
let picker = NohanaImagePickerController()
|
||||
picker.delegate = self
|
||||
picker.numberOfColumnsInPortrait = 2
|
||||
picker.numberOfColumnsInLandscape = 3
|
||||
presentViewController(picker, animated: true, completion: nil)
|
||||
present(picker, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@objc
|
||||
func showNoToolbarPicker() {
|
||||
@objc func showNoToolbarPicker() {
|
||||
let picker = NohanaImagePickerController()
|
||||
picker.delegate = self
|
||||
picker.toolbarHidden = true
|
||||
presentViewController(picker, animated: true, completion: nil)
|
||||
present(picker, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@objc
|
||||
func showDisableToPickAssetsPicker() {
|
||||
@objc func showDisableToPickAssetsPicker() {
|
||||
let picker = NohanaImagePickerController()
|
||||
picker.delegate = self
|
||||
picker.canPickAsset = { (asset:AssetType) -> Bool in
|
||||
picker.canPickAsset = { (asset: Asset) -> Bool in
|
||||
return asset.identifier % 2 == 0
|
||||
}
|
||||
presentViewController(picker, animated: true, completion: nil)
|
||||
present(picker, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
@objc func showCustomUIPicker() {
|
||||
let picker = NohanaImagePickerController()
|
||||
picker.delegate = self
|
||||
picker.config.color.background = UIColor(red: 0xcc/0xff, green: 0xff/0xff, blue: 0xff/0xff, alpha: 1)
|
||||
picker.config.color.separator = UIColor(red: 0x00/0xff, green: 0x66/0xff, blue: 0x66/0xff, alpha: 1)
|
||||
picker.config.strings.albumListTitle = "🏞"
|
||||
picker.config.image.droppedSmall = UIImage(named: "btn_select_m")
|
||||
picker.config.image.pickedSmall = UIImage(named: "btn_selected_m")
|
||||
present(picker, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
// MARK: - NohanaImagePickerControllerDelegate
|
||||
|
||||
func nohanaImagePickerDidCancel(picker: NohanaImagePickerController) {
|
||||
|
||||
func nohanaImagePickerDidCancel(_ picker: NohanaImagePickerController) {
|
||||
print("🐷Canceled🙅")
|
||||
picker.dismissViewControllerAnimated(true, completion: nil)
|
||||
picker.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
func nohanaImagePicker(picker: NohanaImagePickerController, didFinishPickingPhotoKitAssets pickedAssts :[PHAsset]) {
|
||||
|
||||
func nohanaImagePicker(_ picker: NohanaImagePickerController, didFinishPickingPhotoKitAssets pickedAssts: [PHAsset]) {
|
||||
print("🐷Completed🙆\n\tpickedAssets = \(pickedAssts)")
|
||||
picker.dismissViewControllerAnimated(true, completion: nil)
|
||||
picker.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
func nohanaImagePicker(picker: NohanaImagePickerController, willPickPhotoKitAsset asset: PHAsset, pickedAssetsCount: Int) -> Bool {
|
||||
|
||||
func nohanaImagePicker(_ picker: NohanaImagePickerController, willPickPhotoKitAsset asset: PHAsset, pickedAssetsCount: Int) -> Bool {
|
||||
print("🐷\(#function)\n\tasset = \(asset)\n\tpickedAssetsCount = \(pickedAssetsCount)")
|
||||
return true
|
||||
}
|
||||
|
||||
func nohanaImagePicker(picker: NohanaImagePickerController, didPickPhotoKitAsset asset: PHAsset, pickedAssetsCount: Int) {
|
||||
|
||||
func nohanaImagePicker(_ picker: NohanaImagePickerController, didPickPhotoKitAsset asset: PHAsset, pickedAssetsCount: Int) {
|
||||
print("🐷\(#function)\n\tasset = \(asset)\n\tpickedAssetsCount = \(pickedAssetsCount)")
|
||||
}
|
||||
|
||||
func nohanaImagePicker(picker: NohanaImagePickerController, willDropPhotoKitAsset asset: PHAsset, pickedAssetsCount: Int) -> Bool {
|
||||
|
||||
func nohanaImagePicker(_ picker: NohanaImagePickerController, willDropPhotoKitAsset asset: PHAsset, pickedAssetsCount: Int) -> Bool {
|
||||
print("🐷\(#function)\n\tasset = \(asset)\n\tpickedAssetsCount = \(pickedAssetsCount)")
|
||||
return true
|
||||
}
|
||||
|
||||
func nohanaImagePicker(picker: NohanaImagePickerController, didDropPhotoKitAsset asset: PHAsset, pickedAssetsCount: Int) {
|
||||
|
||||
func nohanaImagePicker(_ picker: NohanaImagePickerController, didDropPhotoKitAsset asset: PHAsset, pickedAssetsCount: Int) {
|
||||
print("🐷\(#function)\n\tasset = \(asset)\n\tpickedAssetsCount = \(pickedAssetsCount)")
|
||||
}
|
||||
|
||||
func nohanaImagePicker(picker: NohanaImagePickerController, didSelectPhotoKitAsset asset: PHAsset) {
|
||||
|
||||
func nohanaImagePicker(_ picker: NohanaImagePickerController, didSelectPhotoKitAsset asset: PHAsset) {
|
||||
print("🐷\(#function)\n\tasset = \(asset)\n\t")
|
||||
}
|
||||
|
||||
func nohanaImagePicker(picker: NohanaImagePickerController, didSelectPhotoKitAssetList assetList: PHAssetCollection) {
|
||||
|
||||
func nohanaImagePicker(_ picker: NohanaImagePickerController, didSelectPhotoKitAssetList assetList: PHAssetCollection) {
|
||||
print("🐷\(#function)\n\t\tassetList = \(assetList)\n\t")
|
||||
}
|
||||
|
||||
func nohanaImagePickerDidSelectMoment(picker: NohanaImagePickerController) -> Void {
|
||||
|
||||
func nohanaImagePickerDidSelectMoment(_ picker: NohanaImagePickerController) -> Void {
|
||||
print("🐷\(#function)")
|
||||
}
|
||||
|
||||
func nohanaImagePicker(picker: NohanaImagePickerController, assetListViewController: UICollectionViewController, cell: UICollectionViewCell, indexPath: NSIndexPath, photoKitAsset: PHAsset) -> UICollectionViewCell {
|
||||
|
||||
func nohanaImagePicker(_ picker: NohanaImagePickerController, assetListViewController: UICollectionViewController, cell: UICollectionViewCell, indexPath: IndexPath, photoKitAsset: PHAsset) -> UICollectionViewCell {
|
||||
print("🐷\(#function)\n\tindexPath = \(indexPath)\n\tphotoKitAsset = \(photoKitAsset)")
|
||||
return cell
|
||||
}
|
||||
|
||||
func nohanaImagePicker(picker: NohanaImagePickerController, assetDetailListViewController: UICollectionViewController, cell: UICollectionViewCell, indexPath: NSIndexPath, photoKitAsset: PHAsset) -> UICollectionViewCell {
|
||||
|
||||
func nohanaImagePicker(_ picker: NohanaImagePickerController, assetDetailListViewController: UICollectionViewController, cell: UICollectionViewCell, indexPath: IndexPath, photoKitAsset: PHAsset) -> UICollectionViewCell {
|
||||
print("🐷\(#function)\n\tindexPath = \(indexPath)\n\tphotoKitAsset = \(photoKitAsset)")
|
||||
return cell
|
||||
}
|
||||
|
||||
func nohanaImagePicker(picker: NohanaImagePickerController, assetDetailListViewController: UICollectionViewController, didChangeAssetDetailPage indexPath: NSIndexPath, photoKitAsset: PHAsset) {
|
||||
|
||||
func nohanaImagePicker(_ picker: NohanaImagePickerController, assetDetailListViewController: UICollectionViewController, didChangeAssetDetailPage indexPath: IndexPath, photoKitAsset: PHAsset) {
|
||||
print("🐷\(#function)\n\tindexPath = \(indexPath)")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,5 +43,7 @@
|
|||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>To pick some photos.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
BIN
Demo/Resources/NohanaImagePicker.xcassets/btn_select_m.imageset/btn_select_m@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
Demo/Resources/NohanaImagePicker.xcassets/btn_select_m.imageset/btn_select_m@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
Demo/Resources/NohanaImagePicker.xcassets/btn_selected_m.imageset/btn_selected_m@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Demo/Resources/NohanaImagePicker.xcassets/btn_selected_m.imageset/btn_selected_m@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
|
|
@ -1,15 +1,17 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'NohanaImagePicker'
|
||||
s.version = '0.6.0'
|
||||
s.summary = 'Multiple image picker for iOS app.'
|
||||
s.homepage = 'https://github.com/nohana/NohanaImagePicker'
|
||||
s.version = '0.9.3'
|
||||
s.summary = 'A multiple image picker for iOS app.'
|
||||
s.homepage = 'https://github.com/TouchInstinct/NohanaImagePicker'
|
||||
s.license = { :type => 'Apache License v2', :file => 'LICENSE' }
|
||||
s.author = { 'nohana' => 'development@nohana.co.jp' }
|
||||
s.source = { :git => 'https://github.com/nohana/NohanaImagePicker.git', :tag => s.version.to_s }
|
||||
s.source = {
|
||||
:git => 'https://github.com/TouchInstinct/NohanaImagePicker.git',
|
||||
:tag => s.version.to_s }
|
||||
s.ios.deployment_target = '8.0'
|
||||
s.source_files = 'NohanaImagePicker/*.swift'
|
||||
s.resource_bundles = {
|
||||
'NohanaImagePicker' => ['NohanaImagePicker/*.{xcassets,storyboard,lproj}']
|
||||
'NohanaImagePicker' => ['NohanaImagePicker/**/*.{xcassets,storyboard,lproj}', "Resources/NohanaImagePicker.storyboard"]
|
||||
}
|
||||
s.frameworks = 'UIKit', 'Photos'
|
||||
end
|
||||
end
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
F202573A1C7343D20069B33A /* ImageName.swift in Sources */ = {isa = PBXBuildFile; fileRef = F20257391C7343D20069B33A /* ImageName.swift */; };
|
||||
3569CAA91EC1918E000C41C0 /* NohanaImagePicker.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3569CAA61EC1918E000C41C0 /* NohanaImagePicker.xcassets */; };
|
||||
F202573C1C7418920069B33A /* PickedAssetList.swift in Sources */ = {isa = PBXBuildFile; fileRef = F202573B1C7418920069B33A /* PickedAssetList.swift */; };
|
||||
F208E5541CD7370B00FFC9F6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F208E5531CD7370B00FFC9F6 /* AppDelegate.swift */; };
|
||||
F208E5591CD7370B00FFC9F6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F208E5571CD7370B00FFC9F6 /* Main.storyboard */; };
|
||||
|
|
@ -21,15 +21,14 @@
|
|||
F218D7DE1C6C3A5B001FCED1 /* AlbumCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F218D7DD1C6C3A5B001FCED1 /* AlbumCell.swift */; };
|
||||
F23554261C69D19C00796DCA /* NohanaImagePicker.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F23554251C69D19C00796DCA /* NohanaImagePicker.storyboard */; };
|
||||
F23554281C69D5DB00796DCA /* NohanaImagePickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F23554271C69D5DB00796DCA /* NohanaImagePickerController.swift */; };
|
||||
F237249B1C6DCF96005D1E8A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F237249A1C6DCF96005D1E8A /* Images.xcassets */; };
|
||||
F237249B1C6DCF96005D1E8A /* NohanaImagePicker.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F237249A1C6DCF96005D1E8A /* NohanaImagePicker.xcassets */; };
|
||||
F23CC89E1CB745C800BCE443 /* ActivityIndicatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F23CC89D1CB745C800BCE443 /* ActivityIndicatable.swift */; };
|
||||
F24EB6901C68AEED0002EC86 /* AlbumListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F24EB68F1C68AEED0002EC86 /* AlbumListViewController.swift */; };
|
||||
F25C10C21C8ED9BF007453C3 /* MomentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F25C10C11C8ED9BF007453C3 /* MomentViewController.swift */; };
|
||||
F25C69881CA23A0A005935D6 /* MomentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F25C69871CA23A0A005935D6 /* MomentCell.swift */; };
|
||||
F25C69901CA27311005935D6 /* EmptyIndicatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F25C698F1CA27311005935D6 /* EmptyIndicatable.swift */; };
|
||||
F25C69921CA28728005935D6 /* AlbumListEmptyIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F25C69911CA28728005935D6 /* AlbumListEmptyIndicator.swift */; };
|
||||
F25C699B1CA2B79A005935D6 /* ColorConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = F25C699A1CA2B79A005935D6 /* ColorConfig.swift */; };
|
||||
F26775DE1C701FA7002E786C /* ItemListType.swift in Sources */ = {isa = PBXBuildFile; fileRef = F26775DD1C701FA7002E786C /* ItemListType.swift */; };
|
||||
F26775DE1C701FA7002E786C /* ItemList.swift in Sources */ = {isa = PBXBuildFile; fileRef = F26775DD1C701FA7002E786C /* ItemList.swift */; };
|
||||
F26775E11C7046C7002E786C /* ExpandingAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F26775E01C7046C7002E786C /* ExpandingAnimationController.swift */; };
|
||||
F26775E51C70574F002E786C /* AnimatableNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F26775E41C70574F002E786C /* AnimatableNavigationController.swift */; };
|
||||
F26775E81C7073CD002E786C /* Size.swift in Sources */ = {isa = PBXBuildFile; fileRef = F26775E71C7073CD002E786C /* Size.swift */; };
|
||||
|
|
@ -71,7 +70,9 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
F20257391C7343D20069B33A /* ImageName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageName.swift; sourceTree = "<group>"; };
|
||||
23D1CD93207CEB1200F8115E /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/NohanaImagePicker.strings; sourceTree = "<group>"; };
|
||||
3569CAA61EC1918E000C41C0 /* NohanaImagePicker.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = NohanaImagePicker.xcassets; sourceTree = "<group>"; };
|
||||
3590F1F51EC1A79400F32E06 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/NohanaImagePicker.strings; sourceTree = "<group>"; };
|
||||
F202573B1C7418920069B33A /* PickedAssetList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PickedAssetList.swift; sourceTree = "<group>"; };
|
||||
F208E5511CD7370B00FFC9F6 /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F208E5531CD7370B00FFC9F6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -85,15 +86,14 @@
|
|||
F218D7DD1C6C3A5B001FCED1 /* AlbumCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlbumCell.swift; sourceTree = "<group>"; };
|
||||
F23554251C69D19C00796DCA /* NohanaImagePicker.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NohanaImagePicker.storyboard; sourceTree = "<group>"; };
|
||||
F23554271C69D5DB00796DCA /* NohanaImagePickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NohanaImagePickerController.swift; sourceTree = "<group>"; };
|
||||
F237249A1C6DCF96005D1E8A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
F237249A1C6DCF96005D1E8A /* NohanaImagePicker.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = NohanaImagePicker.xcassets; sourceTree = "<group>"; };
|
||||
F23CC89D1CB745C800BCE443 /* ActivityIndicatable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActivityIndicatable.swift; sourceTree = "<group>"; };
|
||||
F24EB68F1C68AEED0002EC86 /* AlbumListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlbumListViewController.swift; sourceTree = "<group>"; };
|
||||
F25C10C11C8ED9BF007453C3 /* MomentViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MomentViewController.swift; sourceTree = "<group>"; };
|
||||
F25C69871CA23A0A005935D6 /* MomentCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MomentCell.swift; sourceTree = "<group>"; };
|
||||
F25C698F1CA27311005935D6 /* EmptyIndicatable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyIndicatable.swift; sourceTree = "<group>"; };
|
||||
F25C69911CA28728005935D6 /* AlbumListEmptyIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlbumListEmptyIndicator.swift; sourceTree = "<group>"; };
|
||||
F25C699A1CA2B79A005935D6 /* ColorConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorConfig.swift; sourceTree = "<group>"; };
|
||||
F26775DD1C701FA7002E786C /* ItemListType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListType.swift; sourceTree = "<group>"; };
|
||||
F26775DD1C701FA7002E786C /* ItemList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemList.swift; sourceTree = "<group>"; };
|
||||
F26775E01C7046C7002E786C /* ExpandingAnimationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExpandingAnimationController.swift; sourceTree = "<group>"; };
|
||||
F26775E41C70574F002E786C /* AnimatableNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimatableNavigationController.swift; sourceTree = "<group>"; };
|
||||
F26775E71C7073CD002E786C /* Size.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Size.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -132,9 +132,18 @@
|
|||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
3569CAA31EC1918E000C41C0 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3569CAA61EC1918E000C41C0 /* NohanaImagePicker.xcassets */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F208E5521CD7370B00FFC9F6 /* Demo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3569CAA31EC1918E000C41C0 /* Resources */,
|
||||
F208E5531CD7370B00FFC9F6 /* AppDelegate.swift */,
|
||||
F208E5681CD738CD00FFC9F6 /* DemoListViewController.swift */,
|
||||
F208E5571CD7370B00FFC9F6 /* Main.storyboard */,
|
||||
|
|
@ -163,7 +172,7 @@
|
|||
children = (
|
||||
F23554251C69D19C00796DCA /* NohanaImagePicker.storyboard */,
|
||||
F27029CD1C71C43A001647AB /* NohanaImagePicker.strings */,
|
||||
F237249A1C6DCF96005D1E8A /* Images.xcassets */,
|
||||
F237249A1C6DCF96005D1E8A /* NohanaImagePicker.xcassets */,
|
||||
);
|
||||
name = Resources;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -192,14 +201,12 @@
|
|||
F26775E61C7073B1002E786C /* Common */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F26775DD1C701FA7002E786C /* ItemListType.swift */,
|
||||
F26775DD1C701FA7002E786C /* ItemList.swift */,
|
||||
F202573B1C7418920069B33A /* PickedAssetList.swift */,
|
||||
F20257391C7343D20069B33A /* ImageName.swift */,
|
||||
F26775E71C7073CD002E786C /* Size.swift */,
|
||||
F2DA29761C7749D600B0A8E3 /* NotificationInfo.swift */,
|
||||
F25C698F1CA27311005935D6 /* EmptyIndicatable.swift */,
|
||||
F23CC89D1CB745C800BCE443 /* ActivityIndicatable.swift */,
|
||||
F25C699A1CA2B79A005935D6 /* ColorConfig.swift */,
|
||||
);
|
||||
name = Common;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -307,14 +314,16 @@
|
|||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0720;
|
||||
LastUpgradeCheck = 0720;
|
||||
LastUpgradeCheck = 1000;
|
||||
ORGANIZATIONNAME = nohana;
|
||||
TargetAttributes = {
|
||||
F208E5501CD7370B00FFC9F6 = {
|
||||
CreatedOnToolsVersion = 7.2.1;
|
||||
LastSwiftMigration = 0900;
|
||||
};
|
||||
F2C08D731C68651900B00181 = {
|
||||
CreatedOnToolsVersion = 7.2.1;
|
||||
LastSwiftMigration = 0900;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -326,6 +335,8 @@
|
|||
en,
|
||||
Base,
|
||||
ja,
|
||||
ru,
|
||||
de,
|
||||
);
|
||||
mainGroup = F2C08D6A1C68651900B00181;
|
||||
productRefGroup = F2C08D751C68651900B00181 /* Products */;
|
||||
|
|
@ -344,6 +355,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F208E55E1CD7370B00FFC9F6 /* LaunchScreen.storyboard in Resources */,
|
||||
3569CAA91EC1918E000C41C0 /* NohanaImagePicker.xcassets in Resources */,
|
||||
F208E55B1CD7370B00FFC9F6 /* Assets.xcassets in Resources */,
|
||||
F208E5591CD7370B00FFC9F6 /* Main.storyboard in Resources */,
|
||||
);
|
||||
|
|
@ -355,7 +367,7 @@
|
|||
files = (
|
||||
F23554261C69D19C00796DCA /* NohanaImagePicker.storyboard in Resources */,
|
||||
F27029CB1C71C43A001647AB /* NohanaImagePicker.strings in Resources */,
|
||||
F237249B1C6DCF96005D1E8A /* Images.xcassets in Resources */,
|
||||
F237249B1C6DCF96005D1E8A /* NohanaImagePicker.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
@ -377,13 +389,12 @@
|
|||
files = (
|
||||
F2DF3B171C6C868E00C1C0E4 /* AssetCell.swift in Sources */,
|
||||
F26775E81C7073CD002E786C /* Size.swift in Sources */,
|
||||
F26775DE1C701FA7002E786C /* ItemListType.swift in Sources */,
|
||||
F26775DE1C701FA7002E786C /* ItemList.swift in Sources */,
|
||||
F23CC89E1CB745C800BCE443 /* ActivityIndicatable.swift in Sources */,
|
||||
F202573C1C7418920069B33A /* PickedAssetList.swift in Sources */,
|
||||
F25C10C21C8ED9BF007453C3 /* MomentViewController.swift in Sources */,
|
||||
F25C69881CA23A0A005935D6 /* MomentCell.swift in Sources */,
|
||||
F2FE1F781C901D9400FDBE7B /* MomentSectionHeaderView.swift in Sources */,
|
||||
F202573A1C7343D20069B33A /* ImageName.swift in Sources */,
|
||||
F23554281C69D5DB00796DCA /* NohanaImagePickerController.swift in Sources */,
|
||||
F25C69921CA28728005935D6 /* AlbumListEmptyIndicator.swift in Sources */,
|
||||
F2131F431C79615700797887 /* SwipeInteractionController.swift in Sources */,
|
||||
|
|
@ -398,7 +409,6 @@
|
|||
F2DF3B2B1C6CC4DB00C1C0E4 /* AssetDetailListViewController.swift in Sources */,
|
||||
F218D7D61C6B3D22001FCED1 /* PhotoKitAlbumList.swift in Sources */,
|
||||
F24EB6901C68AEED0002EC86 /* AlbumListViewController.swift in Sources */,
|
||||
F25C699B1CA2B79A005935D6 /* ColorConfig.swift in Sources */,
|
||||
F28F4AC31C6C49EE00B7D725 /* PhotoKitAssetList.swift in Sources */,
|
||||
F26775EA1C71645A002E786C /* ContractingAnimationController.swift in Sources */,
|
||||
);
|
||||
|
|
@ -436,6 +446,8 @@
|
|||
children = (
|
||||
F27029CC1C71C43A001647AB /* en */,
|
||||
F27029CF1C71C4FE001647AB /* ja */,
|
||||
3590F1F51EC1A79400F32E06 /* ru */,
|
||||
23D1CD93207CEB1200F8115E /* de */,
|
||||
);
|
||||
name = NohanaImagePicker.strings;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -446,26 +458,30 @@
|
|||
F208E5601CD7370B00FFC9F6 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
||||
INFOPLIST_FILE = Demo/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = jp.co.nohana.NohanaImagePicker.Demo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
F208E5611CD7370B00FFC9F6 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
||||
INFOPLIST_FILE = Demo/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = jp.co.nohana.NohanaImagePicker.Demo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
|
@ -473,17 +489,28 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
|
|
@ -506,11 +533,12 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.2;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
|
|
@ -521,17 +549,28 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
|
|
@ -548,9 +587,11 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.2;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
|
|
@ -562,6 +603,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
|
|
@ -574,6 +616,8 @@
|
|||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
|
@ -581,6 +625,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
|
|
@ -592,6 +637,8 @@
|
|||
PRODUCT_BUNDLE_IDENTIFIER = jp.co.nohana.NohanaImagePicker;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0720"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@
|
|||
|
||||
public protocol ActivityIndicatable {
|
||||
func isProgressing() -> Bool
|
||||
func updateVisibilityOfActivityIndicator(activityIndicator: UIView)
|
||||
func updateVisibilityOfActivityIndicator(_ activityIndicator: UIView)
|
||||
}
|
||||
|
||||
public extension ActivityIndicatable where Self: UIViewController {
|
||||
|
||||
func updateVisibilityOfActivityIndicator(activityIndicator: UIView) {
|
||||
|
||||
func updateVisibilityOfActivityIndicator(_ activityIndicator: UIView) {
|
||||
if isProgressing() {
|
||||
if !view.subviews.contains(activityIndicator) {
|
||||
view.addSubview(activityIndicator)
|
||||
|
|
@ -30,4 +30,4 @@ public extension ActivityIndicatable where Self: UIViewController {
|
|||
activityIndicator.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,32 +15,32 @@
|
|||
*/
|
||||
|
||||
class AlbumListEmptyIndicator: UILabel {
|
||||
|
||||
init(message: String, description: String, frame: CGRect) {
|
||||
|
||||
init(message: String, description: String, frame: CGRect, config: NohanaImagePickerController.Config) {
|
||||
super.init(frame: frame)
|
||||
|
||||
|
||||
let centerStyle = NSMutableParagraphStyle()
|
||||
centerStyle.alignment = NSTextAlignment.Center
|
||||
|
||||
centerStyle.alignment = NSTextAlignment.center
|
||||
|
||||
let messageAttributes = [
|
||||
NSForegroundColorAttributeName : ColorConfig.emptyIndicator,
|
||||
NSFontAttributeName : UIFont.systemFontOfSize(26),
|
||||
NSParagraphStyleAttributeName : centerStyle
|
||||
NSAttributedString.Key.foregroundColor : config.color.empty ?? UIColor(red: 0x88/0xff, green: 0x88/0xff, blue: 0x88/0xff, alpha: 1),
|
||||
NSAttributedString.Key.font : UIFont.systemFont(ofSize: 26),
|
||||
NSAttributedString.Key.paragraphStyle : centerStyle
|
||||
]
|
||||
let messageText = NSAttributedString(string: message, attributes: messageAttributes)
|
||||
|
||||
|
||||
let descriptionAttributes = [
|
||||
NSForegroundColorAttributeName : ColorConfig.emptyIndicator,
|
||||
NSFontAttributeName : UIFont.systemFontOfSize(14),
|
||||
NSParagraphStyleAttributeName : centerStyle
|
||||
NSAttributedString.Key.foregroundColor : config.color.empty ?? UIColor(red: 0x88/0xff, green: 0x88/0xff, blue: 0x88/0xff, alpha: 1),
|
||||
NSAttributedString.Key.font : UIFont.systemFont(ofSize: 14),
|
||||
NSAttributedString.Key.paragraphStyle : centerStyle
|
||||
]
|
||||
let descriptionText = NSAttributedString(string: description, attributes: descriptionAttributes)
|
||||
|
||||
|
||||
let attributedText = NSMutableAttributedString()
|
||||
attributedText.appendAttributedString(messageText)
|
||||
attributedText.appendAttributedString(NSAttributedString(string: "\n\n", attributes: [NSFontAttributeName : UIFont.systemFontOfSize(6)]))
|
||||
attributedText.appendAttributedString(descriptionText)
|
||||
|
||||
attributedText.append(messageText)
|
||||
attributedText.append(NSAttributedString(string: "\n\n", attributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 6)]))
|
||||
attributedText.append(descriptionText)
|
||||
|
||||
self.numberOfLines = 0
|
||||
self.attributedText = attributedText
|
||||
}
|
||||
|
|
@ -48,4 +48,4 @@ class AlbumListEmptyIndicator: UILabel {
|
|||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,11 +18,11 @@ import UIKit
|
|||
import Photos
|
||||
|
||||
class AlbumListViewController: UITableViewController, EmptyIndicatable, ActivityIndicatable {
|
||||
|
||||
|
||||
enum AlbumListViewControllerSectionType: Int {
|
||||
case Moment = 0
|
||||
case Albums
|
||||
|
||||
case moment = 0
|
||||
case albums
|
||||
|
||||
static func count() -> Int {
|
||||
var count: Int = 0
|
||||
for i in 0..<Int.max {
|
||||
|
|
@ -34,44 +34,44 @@ class AlbumListViewController: UITableViewController, EmptyIndicatable, Activity
|
|||
return count
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
weak var nohanaImagePickerController: NohanaImagePickerController?
|
||||
var photoKitAlbumList: PhotoKitAlbumList!
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
if let nohanaImagePickerController = nohanaImagePickerController {
|
||||
title = NSLocalizedString("albumlist.title", tableName: "NohanaImagePicker", bundle: nohanaImagePickerController.assetBundle, comment: "")
|
||||
view.backgroundColor = nohanaImagePickerController.config.color.background ?? .white
|
||||
title = nohanaImagePickerController.config.strings.albumListTitle ?? NSLocalizedString("albumlist.title", tableName: "NohanaImagePicker", bundle: nohanaImagePickerController.assetBundle, comment: "")
|
||||
setUpToolbarItems()
|
||||
navigationController?.setToolbarHidden(nohanaImagePickerController.toolbarHidden ?? false, animated: false)
|
||||
navigationController?.setToolbarHidden(nohanaImagePickerController.toolbarHidden, animated: false)
|
||||
}
|
||||
setUpEmptyIndicator()
|
||||
setUpActivityIndicator()
|
||||
self.view.backgroundColor = ColorConfig.backgroundColor
|
||||
}
|
||||
|
||||
|
||||
deinit {
|
||||
NSNotificationCenter.defaultCenter().removeObserver(self)
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
override func viewWillAppear(animated: Bool) {
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
if let nohanaImagePickerController = nohanaImagePickerController {
|
||||
setToolbarTitle(nohanaImagePickerController)
|
||||
}
|
||||
if let indexPathForSelectedRow = tableView.indexPathForSelectedRow {
|
||||
tableView.deselectRowAtIndexPath(indexPathForSelectedRow, animated: true)
|
||||
tableView.deselectRow(at: indexPathForSelectedRow, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
|
||||
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
|
||||
|
||||
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
|
||||
super.viewWillTransition(to: size, with: coordinator)
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
// MARK: - UITableViewDelegate
|
||||
|
||||
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
guard let sectionType = AlbumListViewControllerSectionType(rawValue: indexPath.section) else {
|
||||
fatalError("Invalid section")
|
||||
}
|
||||
|
|
@ -79,83 +79,86 @@ class AlbumListViewController: UITableViewController, EmptyIndicatable, Activity
|
|||
return
|
||||
}
|
||||
switch sectionType {
|
||||
case .Moment:
|
||||
case .moment:
|
||||
nohanaImagePickerController.delegate?.nohanaImagePickerDidSelectMoment?(nohanaImagePickerController)
|
||||
case .Albums:
|
||||
case .albums:
|
||||
nohanaImagePickerController.delegate?.nohanaImagePicker?(nohanaImagePickerController, didSelectPhotoKitAssetList: photoKitAlbumList[indexPath.row].assetList)
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
guard let sectionType = AlbumListViewControllerSectionType(rawValue: indexPath.section) else {
|
||||
fatalError("Invalid section")
|
||||
}
|
||||
switch sectionType {
|
||||
case .Moment:
|
||||
case .moment:
|
||||
return 52
|
||||
case .Albums:
|
||||
case .albums:
|
||||
return 82
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UITableViewDataSource
|
||||
|
||||
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
|
||||
|
||||
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return AlbumListViewControllerSectionType.count()
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
if let emptyIndicator = emptyIndicator {
|
||||
updateVisibilityOfEmptyIndicator(emptyIndicator)
|
||||
}
|
||||
if let activityIndicator = activityIndicator {
|
||||
updateVisibilityOfActivityIndicator(activityIndicator)
|
||||
}
|
||||
|
||||
|
||||
guard let sectionType = AlbumListViewControllerSectionType(rawValue: section) else {
|
||||
fatalError("Invalid section")
|
||||
}
|
||||
|
||||
|
||||
switch sectionType {
|
||||
case .Moment:
|
||||
case .moment:
|
||||
if let nohanaImagePickerController = nohanaImagePickerController {
|
||||
return nohanaImagePickerController.shouldShowMoment ? 1 : 0
|
||||
}
|
||||
return 0
|
||||
|
||||
case .Albums:
|
||||
|
||||
case .albums:
|
||||
return photoKitAlbumList.count
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
guard let sectionType = AlbumListViewControllerSectionType(rawValue: indexPath.section) else {
|
||||
fatalError("Invalid section")
|
||||
}
|
||||
|
||||
|
||||
switch sectionType {
|
||||
case .Moment:
|
||||
guard let cell = tableView.dequeueReusableCellWithIdentifier("MomentAlbumCell") as? AlbumCell else {
|
||||
case .moment:
|
||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "MomentAlbumCell") as? MomentCell else {
|
||||
fatalError("failed to dequeueReusableCellWithIdentifier(\"MomentAlbumCell\")")
|
||||
}
|
||||
if let nohanaImagePickerController = nohanaImagePickerController {
|
||||
cell.titleLabel?.text = NSLocalizedString("albumlist.moment.title", tableName: "NohanaImagePicker", bundle: nohanaImagePickerController.assetBundle, comment: "")
|
||||
cell.config = nohanaImagePickerController.config
|
||||
cell.titleLabel?.text = nohanaImagePickerController.config.strings.albumListMomentTitle ?? NSLocalizedString("albumlist.moment.title", tableName: "NohanaImagePicker", bundle: nohanaImagePickerController.assetBundle, comment: "")
|
||||
}
|
||||
return cell
|
||||
case .Albums:
|
||||
guard let cell = tableView.dequeueReusableCellWithIdentifier("AlbumCell") as? AlbumCell else {
|
||||
case .albums:
|
||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "AlbumCell") as? AlbumCell else {
|
||||
fatalError("failed to dequeueReusableCellWithIdentifier(\"AlbumCell\")")
|
||||
}
|
||||
let albumList = photoKitAlbumList[indexPath.row]
|
||||
cell.titleLabel.text = albumList.title
|
||||
cell.tag = indexPath.row
|
||||
let imageSize = CGSize(
|
||||
width: cell.thumbnailImageView.frame.size.width * UIScreen.mainScreen().scale,
|
||||
height: cell.thumbnailImageView.frame.size.width * UIScreen.mainScreen().scale
|
||||
width: cell.thumbnailImageView.frame.size.width * UIScreen.main.scale,
|
||||
height: cell.thumbnailImageView.frame.size.width * UIScreen.main.scale
|
||||
)
|
||||
if let lastAsset = albumList.last {
|
||||
lastAsset.image(imageSize, handler: { (imageData) -> Void in
|
||||
dispatch_async(dispatch_get_main_queue(), { () -> Void in
|
||||
let albumCount = albumList.count
|
||||
if albumCount > 0 {
|
||||
let lastAsset = albumList[albumCount - 1]
|
||||
lastAsset.image(targetSize: imageSize, handler: { (imageData) -> Void in
|
||||
DispatchQueue.main.async(execute: { () -> Void in
|
||||
if let imageData = imageData {
|
||||
if cell.tag == indexPath.row {
|
||||
cell.thumbnailImageView.image = imageData.image
|
||||
|
|
@ -169,132 +172,134 @@ class AlbumListViewController: UITableViewController, EmptyIndicatable, Activity
|
|||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Storyboard
|
||||
|
||||
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
guard let sectionType = AlbumListViewControllerSectionType(rawValue: tableView.indexPathForSelectedRow!.section) else {
|
||||
fatalError("Invalid section")
|
||||
}
|
||||
switch sectionType {
|
||||
case .Moment:
|
||||
let momentViewController = segue.destinationViewController as! MomentViewController
|
||||
case .moment:
|
||||
let momentViewController = segue.destination as! MomentViewController
|
||||
momentViewController.nohanaImagePickerController = nohanaImagePickerController
|
||||
momentViewController.momentAlbumList = PhotoKitAlbumList(
|
||||
assetCollectionTypes: [.Moment],
|
||||
assetCollectionSubtypes: [.Any],
|
||||
assetCollectionTypes: [.moment],
|
||||
assetCollectionSubtypes: [.any],
|
||||
mediaType: nohanaImagePickerController!.mediaType,
|
||||
shouldShowEmptyAlbum: nohanaImagePickerController!.shouldShowEmptyAlbum,
|
||||
handler: { () -> Void in
|
||||
dispatch_async(dispatch_get_main_queue(), { [weak momentViewController] in
|
||||
DispatchQueue.main.async(execute: { [weak momentViewController] in
|
||||
momentViewController?.isLoading = false
|
||||
momentViewController?.collectionView?.reloadData()
|
||||
momentViewController?.isFirstAppearance = true
|
||||
momentViewController?.scrollCollectionViewToInitialPosition()
|
||||
})
|
||||
})
|
||||
case .Albums:
|
||||
let assetListViewController = segue.destinationViewController as! AssetListViewController
|
||||
case .albums:
|
||||
let assetListViewController = segue.destination as! AssetListViewController
|
||||
assetListViewController.photoKitAssetList = photoKitAlbumList[tableView.indexPathForSelectedRow!.row]
|
||||
assetListViewController.nohanaImagePickerController = nohanaImagePickerController
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - IBAction
|
||||
|
||||
@IBAction func didPushCancel(sender: AnyObject) {
|
||||
|
||||
@IBAction func didPushCancel(_ sender: AnyObject) {
|
||||
if let nohanaImagePickerController = nohanaImagePickerController {
|
||||
nohanaImagePickerController.delegate?.nohanaImagePickerDidCancel(nohanaImagePickerController)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - EmptyIndicatable
|
||||
|
||||
|
||||
var emptyIndicator: UIView?
|
||||
|
||||
|
||||
func setUpEmptyIndicator() {
|
||||
let frame = CGRect(origin: CGPoint.zero, size: Size.screenRectWithoutAppBar(self).size)
|
||||
guard let nohanaImagePickerController = nohanaImagePickerController else {
|
||||
return
|
||||
}
|
||||
emptyIndicator = AlbumListEmptyIndicator(
|
||||
message: NSLocalizedString("albumlist.empty.message", tableName: "NohanaImagePicker", bundle: nohanaImagePickerController.assetBundle, comment: ""),
|
||||
description: NSLocalizedString("albumlist.empty.description", tableName: "NohanaImagePicker", bundle: nohanaImagePickerController.assetBundle, comment: ""),
|
||||
frame: frame)
|
||||
message: nohanaImagePickerController.config.strings.albumListEmptyMessage ?? NSLocalizedString("albumlist.empty.message", tableName: "NohanaImagePicker", bundle: nohanaImagePickerController.assetBundle, comment: ""),
|
||||
description: nohanaImagePickerController.config.strings.albumListEmptyDescription ?? NSLocalizedString("albumlist.empty.description", tableName: "NohanaImagePicker", bundle: nohanaImagePickerController.assetBundle, comment: ""),
|
||||
frame: frame,
|
||||
config: nohanaImagePickerController.config)
|
||||
}
|
||||
|
||||
|
||||
func isEmpty() -> Bool {
|
||||
if isProgressing() {
|
||||
return false
|
||||
}
|
||||
return photoKitAlbumList.count == 0
|
||||
}
|
||||
|
||||
|
||||
// MARK: - ActivityIndicatable
|
||||
|
||||
|
||||
var activityIndicator: UIActivityIndicatorView?
|
||||
var isLoading = true
|
||||
|
||||
|
||||
func setUpActivityIndicator() {
|
||||
activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .Gray)
|
||||
activityIndicator = UIActivityIndicatorView(style: .gray)
|
||||
let screenRect = Size.screenRectWithoutAppBar(self)
|
||||
activityIndicator?.center = CGPoint(x: screenRect.size.width / 2, y: screenRect.size.height / 2)
|
||||
activityIndicator?.startAnimating()
|
||||
}
|
||||
|
||||
|
||||
func isProgressing() -> Bool {
|
||||
return isLoading
|
||||
}
|
||||
}
|
||||
|
||||
extension UIViewController {
|
||||
|
||||
|
||||
// MARK: - Toolbar
|
||||
|
||||
|
||||
func setUpToolbarItems() {
|
||||
let leftSpace = UIBarButtonItem(barButtonSystemItem: .FlexibleSpace, target: nil, action: nil)
|
||||
let rightSpace = UIBarButtonItem(barButtonSystemItem: .FlexibleSpace, target: nil, action: nil)
|
||||
|
||||
let infoButton = UIBarButtonItem(title: "", style: .Plain, target: nil, action: nil)
|
||||
infoButton.enabled = false
|
||||
infoButton.setTitleTextAttributes([NSFontAttributeName: UIFont.systemFontOfSize(14), NSForegroundColorAttributeName: UIColor.blackColor()], forState: .Normal)
|
||||
let leftSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
|
||||
let rightSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
|
||||
|
||||
let infoButton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
|
||||
infoButton.isEnabled = false
|
||||
infoButton.setTitleTextAttributes([NSAttributedString.Key.font: UIFont.systemFont(ofSize: 14), NSAttributedString.Key.foregroundColor: UIColor.black], for: UIControl.State())
|
||||
self.toolbarItems = [leftSpace, infoButton, rightSpace]
|
||||
}
|
||||
|
||||
func setToolbarTitle(nohanaImagePickerController:NohanaImagePickerController) {
|
||||
guard toolbarItems?.count >= 2 else {
|
||||
|
||||
func setToolbarTitle(_ nohanaImagePickerController: NohanaImagePickerController) {
|
||||
let count: Int? = toolbarItems?.count
|
||||
guard count != nil && count! >= 2 else {
|
||||
return
|
||||
}
|
||||
guard let infoButton = toolbarItems?[1] else {
|
||||
return
|
||||
}
|
||||
if nohanaImagePickerController.maximumNumberOfSelection == 0 {
|
||||
let title = String(format: NSLocalizedString("toolbar.title.nolimit", tableName: "NohanaImagePicker", bundle: nohanaImagePickerController.assetBundle, comment: ""),
|
||||
let title = String(format: nohanaImagePickerController.config.strings.toolbarTitleNoLimit ?? NSLocalizedString("toolbar.title.nolimit", tableName: "NohanaImagePicker", bundle: nohanaImagePickerController.assetBundle, comment: ""),
|
||||
nohanaImagePickerController.pickedAssetList.count)
|
||||
infoButton.title = title
|
||||
} else {
|
||||
let title = String(format: NSLocalizedString("toolbar.title.haslimit", tableName: "NohanaImagePicker", bundle: nohanaImagePickerController.assetBundle, comment: ""),
|
||||
let title = String(format: nohanaImagePickerController.config.strings.toolbarTitleHasLimit ?? NSLocalizedString("toolbar.title.haslimit", tableName: "NohanaImagePicker", bundle: nohanaImagePickerController.assetBundle, comment: ""),
|
||||
nohanaImagePickerController.pickedAssetList.count,
|
||||
nohanaImagePickerController.maximumNumberOfSelection)
|
||||
infoButton.title = title
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Notification
|
||||
|
||||
|
||||
func addPickPhotoKitAssetNotificationObservers() {
|
||||
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(AlbumListViewController.didPickPhotoKitAsset(_:)), name: NotificationInfo.Asset.PhotoKit.didPick, object: nil)
|
||||
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(AlbumListViewController.didDropPhotoKitAsset(_:)), name: NotificationInfo.Asset.PhotoKit.didDrop, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(AlbumListViewController.didPickPhotoKitAsset(_:)), name: NotificationInfo.Asset.PhotoKit.didPick, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(AlbumListViewController.didDropPhotoKitAsset(_:)), name: NotificationInfo.Asset.PhotoKit.didDrop, object: nil)
|
||||
}
|
||||
|
||||
func didPickPhotoKitAsset(notification: NSNotification) {
|
||||
|
||||
@objc func didPickPhotoKitAsset(_ notification: Notification) {
|
||||
guard let picker = notification.object as? NohanaImagePickerController else {
|
||||
return
|
||||
}
|
||||
setToolbarTitle(picker)
|
||||
}
|
||||
|
||||
func didDropPhotoKitAsset(notification: NSNotification) {
|
||||
|
||||
@objc func didDropPhotoKitAsset(_ notification: Notification) {
|
||||
guard let picker = notification.object as? NohanaImagePickerController else {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,28 +17,28 @@
|
|||
import UIKit
|
||||
|
||||
class AnimatableNavigationController: UINavigationController, UINavigationControllerDelegate {
|
||||
|
||||
|
||||
let swipeInteractionController = SwipeInteractionController()
|
||||
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
self.delegate = self
|
||||
}
|
||||
|
||||
func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||
|
||||
|
||||
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||
|
||||
switch operation {
|
||||
case .Push where fromVC is AssetListViewController:
|
||||
case .push where fromVC is AssetListViewController:
|
||||
guard let fromVC = fromVC as? AssetListViewController,
|
||||
selectedIndex = fromVC.collectionView?.indexPathsForSelectedItems()?.first,
|
||||
fromCell = fromVC.collectionView?.cellForItemAtIndexPath(selectedIndex) as? AssetCell
|
||||
let selectedIndex = fromVC.collectionView?.indexPathsForSelectedItems?.first,
|
||||
let fromCell = fromVC.collectionView?.cellForItem(at: selectedIndex) as? AssetCell
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
return ExpandingAnimationController(fromCell)
|
||||
case .Pop where toVC is AssetListViewController:
|
||||
case .pop where toVC is AssetListViewController:
|
||||
guard let fromVC = fromVC as? AssetDetailListViewController,
|
||||
fromCell = fromVC.collectionView?.cellForItemAtIndexPath(NSIndexPath(forItem: fromVC.currentIndexPath.item, inSection: 0)) as? AssetDetailCell
|
||||
let fromCell = fromVC.collectionView?.cellForItem(at: IndexPath(item: fromVC.currentIndexPath.item, section: 0)) as? AssetDetailCell
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -47,12 +47,12 @@ class AnimatableNavigationController: UINavigationController, UINavigationContro
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) {
|
||||
|
||||
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
|
||||
swipeInteractionController.attachToViewController(viewController)
|
||||
}
|
||||
|
||||
func navigationController(navigationController: UINavigationController, interactionControllerForAnimationController animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
|
||||
|
||||
func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
|
||||
if animationController is ExpandingAnimationController {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -61,5 +61,5 @@ class AnimatableNavigationController: UINavigationController, UINavigationContro
|
|||
}
|
||||
return swipeInteractionController
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,47 +16,46 @@
|
|||
import UIKit
|
||||
|
||||
class AssetCell: UICollectionViewCell {
|
||||
|
||||
|
||||
@IBOutlet weak var imageView: UIImageView!
|
||||
@IBOutlet weak var pickButton: UIButton!
|
||||
@IBOutlet weak var overlayView: UIView!
|
||||
|
||||
|
||||
weak var nohanaImagePickerController: NohanaImagePickerController?
|
||||
var asset: AssetType?
|
||||
|
||||
override func willMoveToSuperview(newSuperview: UIView?) {
|
||||
super.willMoveToSuperview(newSuperview)
|
||||
var asset: Asset?
|
||||
|
||||
override func willMove(toSuperview newSuperview: UIView?) {
|
||||
super.willMove(toSuperview: newSuperview)
|
||||
if let nohanaImagePickerController = nohanaImagePickerController {
|
||||
pickButton.setImage(
|
||||
UIImage(named: ImageName.AssetCell.PickButton.SizeM.dropped, inBundle: nohanaImagePickerController.assetBundle, compatibleWithTraitCollection: nil),
|
||||
forState: .Normal)
|
||||
pickButton.setImage(
|
||||
UIImage(named: ImageName.AssetCell.PickButton.SizeM.picked, inBundle: nohanaImagePickerController.assetBundle, compatibleWithTraitCollection: nil),
|
||||
forState: [.Normal, .Selected])
|
||||
let droppedImage: UIImage? = nohanaImagePickerController.config.image.droppedSmall ?? UIImage(named: "btn_select_m", in: nohanaImagePickerController.assetBundle, compatibleWith: nil)
|
||||
let pickedImage: UIImage? = nohanaImagePickerController.config.image.pickedSmall ?? UIImage(named: "btn_selected_m", in: nohanaImagePickerController.assetBundle, compatibleWith: nil)
|
||||
|
||||
pickButton.setImage(droppedImage, for: UIControl.State())
|
||||
pickButton.setImage(pickedImage, for: .selected)
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func didPushPickButton(sender: UIButton) {
|
||||
|
||||
@IBAction func didPushPickButton(_ sender: UIButton) {
|
||||
guard let asset = asset else {
|
||||
return
|
||||
}
|
||||
if pickButton.selected {
|
||||
if nohanaImagePickerController!.pickedAssetList.dropAsset(asset) {
|
||||
pickButton.selected = false
|
||||
if pickButton.isSelected {
|
||||
if nohanaImagePickerController!.pickedAssetList.drop(asset: asset) {
|
||||
pickButton.isSelected = false
|
||||
}
|
||||
} else {
|
||||
if nohanaImagePickerController!.pickedAssetList.pickAsset(asset) {
|
||||
pickButton.selected = true
|
||||
if nohanaImagePickerController!.pickedAssetList.pick(asset: asset) {
|
||||
pickButton.isSelected = true
|
||||
}
|
||||
}
|
||||
self.overlayView.hidden = !pickButton.selected
|
||||
self.overlayView.isHidden = !pickButton.isSelected
|
||||
}
|
||||
|
||||
func update(asset: AssetType, nohanaImagePickerController: NohanaImagePickerController) {
|
||||
|
||||
func update(asset: Asset, nohanaImagePickerController: NohanaImagePickerController) {
|
||||
self.asset = asset
|
||||
self.nohanaImagePickerController = nohanaImagePickerController
|
||||
self.pickButton.selected = nohanaImagePickerController.pickedAssetList.isPicked(asset) ?? false
|
||||
self.overlayView.hidden = !pickButton.selected
|
||||
self.pickButton.hidden = !(nohanaImagePickerController.canPickAsset(asset) ?? true)
|
||||
self.pickButton.isSelected = nohanaImagePickerController.pickedAssetList.isPicked(asset)
|
||||
self.overlayView.isHidden = !pickButton.isSelected
|
||||
self.pickButton.isHidden = !(nohanaImagePickerController.canPickAsset(asset) )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,58 +17,58 @@
|
|||
import UIKit
|
||||
|
||||
class AssetDetailCell: UICollectionViewCell, UIScrollViewDelegate {
|
||||
|
||||
|
||||
@IBOutlet weak var scrollView: UIScrollView!
|
||||
@IBOutlet weak var imageView: UIImageView!
|
||||
|
||||
|
||||
@IBOutlet weak var imageViewHeightConstraint: NSLayoutConstraint!
|
||||
@IBOutlet weak var imageViewWidthConstraint: NSLayoutConstraint!
|
||||
let doubleTapGestureRecognizer :UITapGestureRecognizer = UITapGestureRecognizer()
|
||||
|
||||
let doubleTapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer()
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
doubleTapGestureRecognizer.addTarget(self, action: #selector(AssetDetailCell.didDoubleTap(_:)))
|
||||
doubleTapGestureRecognizer.numberOfTapsRequired = 2
|
||||
}
|
||||
|
||||
override func willMoveToSuperview(newSuperview: UIView?) {
|
||||
super.willMoveToSuperview(newSuperview)
|
||||
|
||||
override func willMove(toSuperview newSuperview: UIView?) {
|
||||
super.willMove(toSuperview: newSuperview)
|
||||
scrollView.removeGestureRecognizer(doubleTapGestureRecognizer)
|
||||
scrollView.addGestureRecognizer(doubleTapGestureRecognizer)
|
||||
}
|
||||
|
||||
|
||||
deinit {
|
||||
scrollView.removeGestureRecognizer(doubleTapGestureRecognizer)
|
||||
doubleTapGestureRecognizer.removeTarget(self, action: #selector(AssetDetailCell.didDoubleTap(_:)))
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UIScrollViewDelegate
|
||||
|
||||
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
|
||||
|
||||
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
|
||||
return imageView
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Zoom
|
||||
|
||||
func didDoubleTap(sender: UITapGestureRecognizer) {
|
||||
|
||||
@objc func didDoubleTap(_ sender: UITapGestureRecognizer) {
|
||||
if scrollView.zoomScale < scrollView.maximumZoomScale {
|
||||
let center = sender.locationInView(imageView)
|
||||
scrollView.zoomToRect(zoomRect(center), animated: true)
|
||||
let center = sender.location(in: imageView)
|
||||
scrollView.zoom(to: zoomRect(center), animated: true)
|
||||
} else {
|
||||
let defaultScale: CGFloat = 1
|
||||
scrollView.setZoomScale(defaultScale, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
func zoomRect(center: CGPoint) -> CGRect {
|
||||
|
||||
func zoomRect(_ center: CGPoint) -> CGRect {
|
||||
var zoomRect: CGRect = CGRect()
|
||||
zoomRect.size.height = scrollView.frame.size.height / scrollView.maximumZoomScale
|
||||
zoomRect.size.width = scrollView.frame.size.width / scrollView.maximumZoomScale
|
||||
|
||||
|
||||
zoomRect.origin.x = center.x - zoomRect.size.width / 2.0
|
||||
zoomRect.origin.y = center.y - zoomRect.size.height / 2.0
|
||||
|
||||
|
||||
return zoomRect
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,112 +17,113 @@
|
|||
import UIKit
|
||||
|
||||
class AssetDetailListViewController: AssetListViewController {
|
||||
|
||||
var currentIndexPath: NSIndexPath = NSIndexPath() {
|
||||
|
||||
var currentIndexPath: IndexPath = IndexPath() {
|
||||
willSet {
|
||||
if currentIndexPath != newValue {
|
||||
didChangeAssetDetailPage(newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@IBOutlet weak var imageCollectionView: UICollectionView!
|
||||
@IBOutlet weak var pickButton: UIButton!
|
||||
|
||||
|
||||
override var cellSize: CGSize {
|
||||
get {
|
||||
return Size.screenRectWithoutAppBar(self).size
|
||||
}
|
||||
return Size.screenRectWithoutAppBar(self).size
|
||||
}
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
if let nohanaImagePickerController = nohanaImagePickerController {
|
||||
pickButton.setImage(
|
||||
UIImage(named: ImageName.AssetCell.PickButton.SizeL.dropped, inBundle: nohanaImagePickerController.assetBundle, compatibleWithTraitCollection: nil),
|
||||
forState: .Normal)
|
||||
pickButton.setImage(
|
||||
UIImage(named: ImageName.AssetCell.PickButton.SizeL.picked, inBundle: nohanaImagePickerController.assetBundle, compatibleWithTraitCollection: nil),
|
||||
forState: [.Normal, .Selected])
|
||||
let droppedImage: UIImage? = nohanaImagePickerController.config.image.droppedLarge ?? UIImage(named: "btn_select_l", in: nohanaImagePickerController.assetBundle, compatibleWith: nil)
|
||||
let pickedImage: UIImage? = nohanaImagePickerController.config.image.pickedLarge ?? UIImage(named: "btn_selected_l", in: nohanaImagePickerController.assetBundle, compatibleWith: nil)
|
||||
let backgroundColor: UIColor = nohanaImagePickerController.config.color.background ?? .white
|
||||
|
||||
imageCollectionView.backgroundColor = backgroundColor
|
||||
pickButton.setImage(droppedImage, for: UIControl.State())
|
||||
pickButton.setImage(pickedImage, for: .selected)
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
|
||||
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
|
||||
|
||||
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
|
||||
super.viewWillTransition(to: size, with: coordinator)
|
||||
let indexPath = currentIndexPath
|
||||
view.hidden = true
|
||||
coordinator.animateAlongsideTransition(nil) { _ in
|
||||
view.isHidden = true
|
||||
coordinator.animate(alongsideTransition: nil) { _ in
|
||||
self.view.invalidateIntrinsicContentSize()
|
||||
self.collectionView?.reloadData()
|
||||
self.scrollCollectionView(to: indexPath)
|
||||
self.view.hidden = false
|
||||
self.view.isHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func updateTitle() {
|
||||
self.title = ""
|
||||
}
|
||||
|
||||
func didChangeAssetDetailPage(indexPath:NSIndexPath) {
|
||||
|
||||
func didChangeAssetDetailPage(_ indexPath: IndexPath) {
|
||||
guard let nohanaImagePickerController = nohanaImagePickerController else {
|
||||
return
|
||||
}
|
||||
let asset = photoKitAssetList[indexPath.item]
|
||||
pickButton.selected = nohanaImagePickerController.pickedAssetList.isPicked(asset) ?? false
|
||||
pickButton.hidden = !(nohanaImagePickerController.canPickAsset(asset) ?? true)
|
||||
pickButton.isSelected = nohanaImagePickerController.pickedAssetList.isPicked(asset)
|
||||
pickButton.isHidden = !(nohanaImagePickerController.canPickAsset(asset) )
|
||||
nohanaImagePickerController.delegate?.nohanaImagePicker?(nohanaImagePickerController, assetDetailListViewController: self, didChangeAssetDetailPage: indexPath, photoKitAsset: asset.originalAsset)
|
||||
}
|
||||
|
||||
override func scrollCollectionView(to indexPath: NSIndexPath) {
|
||||
guard photoKitAssetList?.count > 0 else {
|
||||
|
||||
override func scrollCollectionView(to indexPath: IndexPath) {
|
||||
let count: Int? = photoKitAssetList?.count
|
||||
guard count != nil && count! > 0 else {
|
||||
return
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue()) {
|
||||
let toIndexPath = NSIndexPath(forItem: indexPath.item, inSection: 0)
|
||||
self.collectionView?.scrollToItemAtIndexPath(toIndexPath, atScrollPosition: UICollectionViewScrollPosition.CenteredHorizontally, animated: false)
|
||||
DispatchQueue.main.async {
|
||||
let toIndexPath = IndexPath(item: indexPath.item, section: 0)
|
||||
self.collectionView?.scrollToItem(at: toIndexPath, at: UICollectionView.ScrollPosition.centeredHorizontally, animated: false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func scrollCollectionViewToInitialPosition() {
|
||||
guard isFirstAppearance else {
|
||||
return
|
||||
}
|
||||
let indexPath = NSIndexPath(forRow: currentIndexPath.item, inSection: 0)
|
||||
let indexPath = IndexPath(row: currentIndexPath.item, section: 0)
|
||||
scrollCollectionView(to: indexPath)
|
||||
isFirstAppearance = false
|
||||
}
|
||||
|
||||
|
||||
// MARK: - IBAction
|
||||
|
||||
@IBAction func didPushPickButton(sender: UIButton) {
|
||||
|
||||
@IBAction func didPushPickButton(_ sender: UIButton) {
|
||||
let asset = photoKitAssetList[currentIndexPath.row]
|
||||
if pickButton.selected {
|
||||
if nohanaImagePickerController!.pickedAssetList.dropAsset(asset) {
|
||||
pickButton.selected = false
|
||||
if pickButton.isSelected {
|
||||
if nohanaImagePickerController!.pickedAssetList.drop(asset: asset) {
|
||||
pickButton.isSelected = false
|
||||
}
|
||||
} else {
|
||||
if nohanaImagePickerController!.pickedAssetList.pickAsset(asset) {
|
||||
pickButton.selected = true
|
||||
if nohanaImagePickerController!.pickedAssetList.pick(asset: asset) {
|
||||
pickButton.isSelected = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UICollectionViewDelegate
|
||||
|
||||
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
|
||||
guard let cell = collectionView.dequeueReusableCellWithReuseIdentifier("AssetDetailCell", forIndexPath: indexPath) as? AssetDetailCell,
|
||||
nohanaImagePickerController = nohanaImagePickerController else {
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AssetDetailCell", for: indexPath) as? AssetDetailCell,
|
||||
let nohanaImagePickerController = nohanaImagePickerController else {
|
||||
fatalError("failed to dequeueReusableCellWithIdentifier(\"AssetDetailCell\")")
|
||||
}
|
||||
cell.scrollView.zoomScale = 1
|
||||
cell.tag = indexPath.item
|
||||
|
||||
|
||||
let imageSize = CGSize(
|
||||
width: cellSize.width * UIScreen.mainScreen().scale,
|
||||
height: cellSize.height * UIScreen.mainScreen().scale
|
||||
width: cellSize.width * UIScreen.main.scale,
|
||||
height: cellSize.height * UIScreen.main.scale
|
||||
)
|
||||
let asset = photoKitAssetList[indexPath.item]
|
||||
asset.image(imageSize) { (imageData) -> Void in
|
||||
dispatch_async(dispatch_get_main_queue(), { () -> Void in
|
||||
asset.image(targetSize: imageSize) { (imageData) -> Void in
|
||||
DispatchQueue.main.async(execute: { () -> Void in
|
||||
if let imageData = imageData {
|
||||
if cell.tag == indexPath.item {
|
||||
cell.imageView.image = imageData.image
|
||||
|
|
@ -134,27 +135,27 @@ class AssetDetailListViewController: AssetListViewController {
|
|||
}
|
||||
return (nohanaImagePickerController.delegate?.nohanaImagePicker?(nohanaImagePickerController, assetDetailListViewController: self, cell: cell, indexPath: indexPath, photoKitAsset: asset.originalAsset)) ?? cell
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UIScrollViewDelegate
|
||||
|
||||
override func scrollViewDidScroll(scrollView: UIScrollView) {
|
||||
|
||||
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
guard let collectionView = collectionView else {
|
||||
return
|
||||
}
|
||||
let row = Int((collectionView.contentOffset.x + cellSize.width * 0.5) / cellSize.width)
|
||||
if row < 0 {
|
||||
currentIndexPath = NSIndexPath(forRow: 0, inSection: currentIndexPath.section)
|
||||
} else if row >= collectionView.numberOfItemsInSection(0) {
|
||||
currentIndexPath = NSIndexPath(forRow: collectionView.numberOfItemsInSection(0) - 1, inSection: currentIndexPath.section)
|
||||
currentIndexPath = IndexPath(row: 0, section: currentIndexPath.section)
|
||||
} else if row >= collectionView.numberOfItems(inSection: 0) {
|
||||
currentIndexPath = IndexPath(row: collectionView.numberOfItems(inSection: 0) - 1, section: currentIndexPath.section)
|
||||
} else {
|
||||
currentIndexPath = NSIndexPath(forRow: row, inSection: currentIndexPath.section)
|
||||
currentIndexPath = IndexPath(row: row, section: currentIndexPath.section)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UICollectionViewDelegateFlowLayout
|
||||
|
||||
override func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
|
||||
return cellSize
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,39 +17,37 @@
|
|||
import UIKit
|
||||
import Photos
|
||||
|
||||
class AssetListViewController: UICollectionViewController {
|
||||
|
||||
class AssetListViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
|
||||
|
||||
weak var nohanaImagePickerController: NohanaImagePickerController?
|
||||
var photoKitAssetList: PhotoKitAssetList!
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
view.backgroundColor = nohanaImagePickerController?.config.color.background ?? .white
|
||||
updateTitle()
|
||||
setUpToolbarItems()
|
||||
addPickPhotoKitAssetNotificationObservers()
|
||||
self.view.backgroundColor = ColorConfig.backgroundColor
|
||||
}
|
||||
|
||||
|
||||
var cellSize: CGSize {
|
||||
get {
|
||||
guard let nohanaImagePickerController = nohanaImagePickerController else {
|
||||
return CGSize.zero
|
||||
}
|
||||
var numberOfColumns = nohanaImagePickerController.numberOfColumnsInLandscape
|
||||
if UIInterfaceOrientationIsPortrait(UIApplication.sharedApplication().statusBarOrientation) {
|
||||
numberOfColumns = nohanaImagePickerController.numberOfColumnsInPortrait
|
||||
}
|
||||
let cellMargin:CGFloat = 2
|
||||
let cellWidth = (view.frame.width - cellMargin * (CGFloat(numberOfColumns) - 1)) / CGFloat(numberOfColumns)
|
||||
return CGSize(width: cellWidth, height: cellWidth)
|
||||
guard let nohanaImagePickerController = nohanaImagePickerController else {
|
||||
return CGSize.zero
|
||||
}
|
||||
var numberOfColumns = nohanaImagePickerController.numberOfColumnsInLandscape
|
||||
if UIApplication.shared.statusBarOrientation.isPortrait {
|
||||
numberOfColumns = nohanaImagePickerController.numberOfColumnsInPortrait
|
||||
}
|
||||
let cellMargin: CGFloat = 1
|
||||
let cellWidth = (view.frame.width - cellMargin * (CGFloat(numberOfColumns) - 1)) / CGFloat(numberOfColumns)
|
||||
return CGSize(width: cellWidth, height: cellWidth)
|
||||
}
|
||||
|
||||
|
||||
deinit {
|
||||
NSNotificationCenter.defaultCenter().removeObserver(self)
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
override func viewWillAppear(animated: Bool) {
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
if let nohanaImagePickerController = nohanaImagePickerController {
|
||||
setToolbarTitle(nohanaImagePickerController)
|
||||
|
|
@ -57,74 +55,75 @@ class AssetListViewController: UICollectionViewController {
|
|||
collectionView?.reloadData()
|
||||
scrollCollectionViewToInitialPosition()
|
||||
}
|
||||
|
||||
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
|
||||
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
|
||||
view.hidden = true
|
||||
coordinator.animateAlongsideTransition(nil) { _ in
|
||||
|
||||
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
|
||||
super.viewWillTransition(to: size, with: coordinator)
|
||||
view.isHidden = true
|
||||
coordinator.animate(alongsideTransition: nil) { _ in
|
||||
// http://saygoodnight.com/2015/06/18/openpics-swift-rotation.html
|
||||
if self.navigationController?.visibleViewController != self {
|
||||
self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, size.width, size.height)
|
||||
self.view.frame = CGRect(x: self.view.frame.origin.x, y: self.view.frame.origin.y, width: size.width, height: size.height)
|
||||
}
|
||||
self.collectionView?.reloadData()
|
||||
self.scrollCollectionViewToInitialPosition()
|
||||
self.view.hidden = false
|
||||
self.view.isHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var isFirstAppearance = true
|
||||
|
||||
|
||||
func updateTitle() {
|
||||
title = photoKitAssetList.title
|
||||
}
|
||||
|
||||
func scrollCollectionView(to indexPath: NSIndexPath) {
|
||||
guard photoKitAssetList?.count > 0 else {
|
||||
|
||||
func scrollCollectionView(to indexPath: IndexPath) {
|
||||
let count: Int? = photoKitAssetList?.count
|
||||
guard count != nil && count! > 0 else {
|
||||
return
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue()) {
|
||||
self.collectionView?.scrollToItemAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: false)
|
||||
DispatchQueue.main.async {
|
||||
self.collectionView?.scrollToItem(at: indexPath, at: .bottom, animated: false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func scrollCollectionViewToInitialPosition() {
|
||||
guard isFirstAppearance else {
|
||||
return
|
||||
}
|
||||
let indexPath = NSIndexPath(forItem: self.photoKitAssetList.count - 1, inSection: 0)
|
||||
let indexPath = IndexPath(item: self.photoKitAssetList.count - 1, section: 0)
|
||||
self.scrollCollectionView(to: indexPath)
|
||||
isFirstAppearance = false
|
||||
}
|
||||
|
||||
// MARK: - UICollectionViewDataSource
|
||||
|
||||
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
|
||||
// MARK: - UICollectionViewDataSource
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return photoKitAssetList.count
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UICollectionViewDelegate
|
||||
|
||||
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
if let nohanaImagePickerController = nohanaImagePickerController {
|
||||
nohanaImagePickerController.delegate?.nohanaImagePicker?(nohanaImagePickerController, didSelectPhotoKitAsset: photoKitAssetList[indexPath.item].originalAsset)
|
||||
}
|
||||
}
|
||||
|
||||
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
|
||||
guard let cell = collectionView.dequeueReusableCellWithReuseIdentifier("AssetCell", forIndexPath: indexPath) as? AssetCell,
|
||||
nohanaImagePickerController = nohanaImagePickerController else {
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AssetCell", for: indexPath) as? AssetCell,
|
||||
let nohanaImagePickerController = nohanaImagePickerController else {
|
||||
fatalError("failed to dequeueReusableCellWithIdentifier(\"AssetCell\")")
|
||||
}
|
||||
cell.tag = indexPath.item
|
||||
cell.update(photoKitAssetList[indexPath.row], nohanaImagePickerController: nohanaImagePickerController)
|
||||
|
||||
cell.update(asset: photoKitAssetList[indexPath.row], nohanaImagePickerController: nohanaImagePickerController)
|
||||
|
||||
let imageSize = CGSize(
|
||||
width: cellSize.width * UIScreen.mainScreen().scale,
|
||||
height: cellSize.height * UIScreen.mainScreen().scale
|
||||
width: cellSize.width * UIScreen.main.scale,
|
||||
height: cellSize.height * UIScreen.main.scale
|
||||
)
|
||||
let asset = photoKitAssetList[indexPath.item]
|
||||
asset.image(imageSize) { (imageData) -> Void in
|
||||
dispatch_async(dispatch_get_main_queue(), { () -> Void in
|
||||
asset.image(targetSize: imageSize) { (imageData) -> Void in
|
||||
DispatchQueue.main.async(execute: { () -> Void in
|
||||
if let imageData = imageData {
|
||||
if cell.tag == indexPath.item {
|
||||
cell.imageView.image = imageData.image
|
||||
|
|
@ -134,31 +133,29 @@ class AssetListViewController: UICollectionViewController {
|
|||
}
|
||||
return (nohanaImagePickerController.delegate?.nohanaImagePicker?(nohanaImagePickerController, assetListViewController: self, cell: cell, indexPath: indexPath, photoKitAsset: asset.originalAsset)) ?? cell
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UICollectionViewDelegateFlowLayout
|
||||
|
||||
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
|
||||
return cellSize
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Storyboard
|
||||
|
||||
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
|
||||
guard let selectedIndexPath = collectionView?.indexPathsForSelectedItems()?.first else {
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
guard let selectedIndexPath = collectionView?.indexPathsForSelectedItems?.first else {
|
||||
return
|
||||
}
|
||||
|
||||
let assetListDetailViewController = segue.destinationViewController as! AssetDetailListViewController
|
||||
|
||||
let assetListDetailViewController = segue.destination as! AssetDetailListViewController
|
||||
assetListDetailViewController.photoKitAssetList = photoKitAssetList
|
||||
assetListDetailViewController.nohanaImagePickerController = nohanaImagePickerController
|
||||
assetListDetailViewController.currentIndexPath = selectedIndexPath
|
||||
}
|
||||
|
||||
|
||||
// MARK: - IBAction
|
||||
@IBAction func didPushDone(sender: AnyObject) {
|
||||
let pickedPhotoKitAssets = nohanaImagePickerController!.pickedAssetList.map{ ($0 as! PhotoKitAsset).originalAsset }
|
||||
@IBAction func didPushDone(_ sender: AnyObject) {
|
||||
let pickedPhotoKitAssets = nohanaImagePickerController!.pickedAssetList.map { ($0 as! PhotoKitAsset).originalAsset }
|
||||
nohanaImagePickerController!.delegate?.nohanaImagePicker(nohanaImagePickerController!, didFinishPickingPhotoKitAssets: pickedPhotoKitAssets )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@
|
|||
import AVFoundation
|
||||
|
||||
extension Size {
|
||||
static func contractingAnimationToCellRect(toVC: AssetListViewController, toCell: AssetCell) -> CGRect {
|
||||
static func contractingAnimationToCellRect(_ toVC: AssetListViewController, toCell: AssetCell) -> CGRect {
|
||||
let origin = CGPoint(x: toCell.frame.origin.x, y: toCell.frame.origin.y - toVC.collectionView!.contentOffset.y)
|
||||
return CGRect(origin: origin, size: toCell.frame.size)
|
||||
}
|
||||
|
||||
static func contractingAnimationFromCellRect(fromVC: AssetDetailListViewController, fromCell: AssetDetailCell, contractingImageSize: CGSize) -> CGRect {
|
||||
var rect = AVMakeRectWithAspectRatioInsideRect(contractingImageSize, fromCell.imageView.frame)
|
||||
|
||||
static func contractingAnimationFromCellRect(_ fromVC: AssetDetailListViewController, fromCell: AssetDetailCell, contractingImageSize: CGSize) -> CGRect {
|
||||
var rect = AVMakeRect(aspectRatio: contractingImageSize, insideRect: fromCell.imageView.frame)
|
||||
rect.origin.y += Size.appBarHeight(fromVC)
|
||||
rect.origin.x -= fromCell.scrollView.contentOffset.x
|
||||
rect.origin.y -= fromCell.scrollView.contentOffset.y
|
||||
|
|
@ -32,64 +32,63 @@ extension Size {
|
|||
}
|
||||
|
||||
class ContractingAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
|
||||
|
||||
|
||||
var fromCell: AssetDetailCell
|
||||
|
||||
|
||||
init(_ fromCell: AssetDetailCell) {
|
||||
self.fromCell = fromCell
|
||||
}
|
||||
|
||||
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
|
||||
|
||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
||||
return 0.3
|
||||
}
|
||||
|
||||
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
|
||||
|
||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||
guard
|
||||
let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as? AssetDetailListViewController,
|
||||
toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) as? AssetListViewController,
|
||||
containerView = transitionContext.containerView()
|
||||
let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) as? AssetDetailListViewController,
|
||||
let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) as? AssetListViewController
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
var toCellTmp = toVC.collectionView?.cellForItemAtIndexPath(fromVC.currentIndexPath) as? AssetCell
|
||||
|
||||
var toCellTmp = toVC.collectionView?.cellForItem(at: fromVC.currentIndexPath as IndexPath) as? AssetCell
|
||||
if toCellTmp == nil {
|
||||
// if toCell is not shown in collection view, scroll collection view to toCell index path.
|
||||
toVC.collectionView?.scrollToItemAtIndexPath(fromVC.currentIndexPath, atScrollPosition: .CenteredVertically, animated: false)
|
||||
toVC.collectionView?.scrollToItem(at: fromVC.currentIndexPath as IndexPath, at: .centeredVertically, animated: false)
|
||||
toVC.collectionView?.layoutIfNeeded()
|
||||
toCellTmp = toVC.collectionView?.cellForItemAtIndexPath(fromVC.currentIndexPath) as? AssetCell
|
||||
toCellTmp = toVC.collectionView?.cellForItem(at: fromVC.currentIndexPath as IndexPath) as? AssetCell
|
||||
}
|
||||
|
||||
|
||||
guard let toCell = toCellTmp else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let contractingImageView = UIImageView(image: fromCell.imageView.image)
|
||||
contractingImageView.contentMode = toCell.imageView.contentMode
|
||||
contractingImageView.clipsToBounds = true
|
||||
contractingImageView.frame = Size.contractingAnimationFromCellRect(fromVC, fromCell: fromCell, contractingImageSize: contractingImageView.image!.size)
|
||||
|
||||
containerView.addSubview(toVC.view)
|
||||
containerView.addSubview(contractingImageView)
|
||||
transitionContext.containerView.addSubview(toVC.view)
|
||||
transitionContext.containerView.addSubview(contractingImageView)
|
||||
toVC.view.alpha = 0
|
||||
fromCell.alpha = 0
|
||||
toCell.alpha = 0
|
||||
|
||||
UIView.animateWithDuration(
|
||||
transitionDuration(transitionContext),
|
||||
|
||||
UIView.animate(
|
||||
withDuration: transitionDuration(using: transitionContext),
|
||||
delay: 0,
|
||||
options: .CurveEaseInOut,
|
||||
animations: { _ in
|
||||
options: UIView.AnimationOptions(),
|
||||
animations: {
|
||||
toVC.view.alpha = 1
|
||||
contractingImageView.frame = Size.contractingAnimationToCellRect(toVC, toCell: toCell)
|
||||
}) { _ in
|
||||
self.fromCell.alpha = 1
|
||||
toCell.alpha = 1
|
||||
contractingImageView.removeFromSuperview()
|
||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
|
||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@
|
|||
|
||||
public protocol EmptyIndicatable {
|
||||
func isEmpty() -> Bool
|
||||
func updateVisibilityOfEmptyIndicator(emptyIndicator: UIView)
|
||||
func updateVisibilityOfEmptyIndicator(_ emptyIndicator: UIView)
|
||||
}
|
||||
|
||||
public extension EmptyIndicatable where Self: UIViewController {
|
||||
func updateVisibilityOfEmptyIndicator(emptyIndicator: UIView) {
|
||||
if isEmpty(){
|
||||
func updateVisibilityOfEmptyIndicator(_ emptyIndicator: UIView) {
|
||||
if isEmpty() {
|
||||
if !view.subviews.contains(emptyIndicator) {
|
||||
view.addSubview(emptyIndicator)
|
||||
}
|
||||
|
|
@ -29,4 +29,4 @@ public extension EmptyIndicatable where Self: UIViewController {
|
|||
emptyIndicator.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,64 +18,62 @@ import AVFoundation
|
|||
|
||||
extension Size {
|
||||
|
||||
static func expandingAnimationFromCellRect(fromVC: AssetListViewController, fromCell: AssetCell) -> CGRect {
|
||||
static func expandingAnimationFromCellRect(_ fromVC: AssetListViewController, fromCell: AssetCell) -> CGRect {
|
||||
let origin = CGPoint(x: fromCell.frame.origin.x, y: fromCell.frame.origin.y - fromVC.collectionView!.contentOffset.y)
|
||||
return CGRect(origin: origin, size: fromCell.frame.size)
|
||||
}
|
||||
|
||||
static func expandingAnimationToCellRect(fromVC: UIViewController, toSize:CGSize) -> CGRect {
|
||||
return AVMakeRectWithAspectRatioInsideRect(toSize, Size.screenRectWithoutAppBar(fromVC))
|
||||
|
||||
static func expandingAnimationToCellRect(_ fromVC: UIViewController, toSize: CGSize) -> CGRect {
|
||||
return AVMakeRect(aspectRatio: toSize, insideRect: Size.screenRectWithoutAppBar(fromVC))
|
||||
}
|
||||
}
|
||||
|
||||
class ExpandingAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
|
||||
|
||||
|
||||
var fromCell: AssetCell
|
||||
|
||||
|
||||
init(_ fromCell: AssetCell) {
|
||||
self.fromCell = fromCell
|
||||
}
|
||||
|
||||
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
|
||||
|
||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
||||
return 0.3
|
||||
}
|
||||
|
||||
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
|
||||
guard let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as? AssetListViewController,
|
||||
toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) as? AssetDetailListViewController,
|
||||
containerView = transitionContext.containerView()
|
||||
|
||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||
guard let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) as? AssetListViewController,
|
||||
let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) as? AssetDetailListViewController
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let expandingImageView = UIImageView(image: fromCell.imageView.image)
|
||||
expandingImageView.contentMode = fromCell.imageView.contentMode
|
||||
expandingImageView.clipsToBounds = true
|
||||
expandingImageView.frame = Size.expandingAnimationFromCellRect(fromVC, fromCell: fromCell)
|
||||
|
||||
containerView.addSubview(toVC.view)
|
||||
containerView.addSubview(expandingImageView)
|
||||
transitionContext.containerView.addSubview(toVC.view)
|
||||
transitionContext.containerView.addSubview(expandingImageView)
|
||||
toVC.view.alpha = 0
|
||||
toVC.collectionView?.hidden = true
|
||||
toVC.view.backgroundColor = UIColor.blackColor()
|
||||
toVC.collectionView?.isHidden = true
|
||||
toVC.view.backgroundColor = .white
|
||||
fromCell.alpha = 0
|
||||
|
||||
UIView.animateWithDuration(
|
||||
transitionDuration(transitionContext),
|
||||
|
||||
UIView.animate(
|
||||
withDuration: transitionDuration(using: transitionContext),
|
||||
delay: 0,
|
||||
usingSpringWithDamping: 0.8,
|
||||
initialSpringVelocity: 10,
|
||||
options: .CurveEaseOut,
|
||||
options: .curveEaseOut,
|
||||
animations: { () -> Void in
|
||||
toVC.view.alpha = 1
|
||||
expandingImageView.frame = Size.expandingAnimationToCellRect(fromVC, toSize: expandingImageView.image!.size)
|
||||
}) { (_) -> Void in
|
||||
self.fromCell.alpha = 1
|
||||
toVC.collectionView?.hidden = false
|
||||
toVC.collectionView?.isHidden = false
|
||||
expandingImageView.removeFromSuperview()
|
||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
|
||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
|
@ -14,19 +14,25 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
public protocol ItemListType: CollectionType {
|
||||
public protocol ItemList: Collection {
|
||||
associatedtype Item
|
||||
var title:String { get }
|
||||
func update(handler:(() -> Void)?)
|
||||
var title: String { get }
|
||||
func update(_ handler:(() -> Void)?)
|
||||
subscript (index: Int) -> Item { get }
|
||||
}
|
||||
|
||||
public protocol AssetType {
|
||||
var identifier:Int { get }
|
||||
func image(targetSize:CGSize, handler: (ImageData?) -> Void)
|
||||
extension ItemList {
|
||||
public func index(after i: Int) -> Int {
|
||||
return i + 1
|
||||
}
|
||||
}
|
||||
|
||||
public protocol Asset {
|
||||
var identifier: Int { get }
|
||||
func image(targetSize: CGSize, handler: @escaping (ImageData?) -> Void)
|
||||
}
|
||||
|
||||
public struct ImageData {
|
||||
public var image: UIImage
|
||||
public var info: Dictionary<NSObject, AnyObject>?
|
||||
}
|
||||
}
|
||||
|
|
@ -17,11 +17,13 @@
|
|||
import UIKit
|
||||
|
||||
class MomentCell: AlbumCell {
|
||||
|
||||
override func drawRect(rect: CGRect) {
|
||||
super.drawRect(rect)
|
||||
let lineWidth: CGFloat = 1 / UIScreen.mainScreen().scale
|
||||
ColorConfig.AlbumList.momentCellSeparator.setFill()
|
||||
var config: NohanaImagePickerController.Config!
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
let lineWidth: CGFloat = 1 / UIScreen.main.scale
|
||||
let separatorColor: UIColor = config.color.separator ?? UIColor(red: 0xbb/0xff, green: 0xbb/0xff, blue: 0xbb/0xff, alpha: 1)
|
||||
separatorColor.setFill()
|
||||
UIRectFill(CGRect(x: 16, y: frame.size.height - lineWidth, width: frame.size.width, height:lineWidth))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,29 +18,30 @@ import UIKit
|
|||
import Photos
|
||||
|
||||
class MomentViewController: AssetListViewController, ActivityIndicatable {
|
||||
|
||||
|
||||
var momentAlbumList: PhotoKitAlbumList!
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
setUpActivityIndicator()
|
||||
}
|
||||
|
||||
|
||||
override func updateTitle() {
|
||||
if let nohanaImagePickerController = nohanaImagePickerController {
|
||||
title = NSLocalizedString("albumlist.moment.title", tableName: "NohanaImagePicker", bundle: nohanaImagePickerController.assetBundle, comment: "")
|
||||
}
|
||||
}
|
||||
|
||||
override func scrollCollectionView(to indexPath: NSIndexPath) {
|
||||
guard momentAlbumList?.count > 0 else {
|
||||
|
||||
override func scrollCollectionView(to indexPath: IndexPath) {
|
||||
let count: Int? = momentAlbumList?.count
|
||||
guard count != nil && count! > 0 else {
|
||||
return
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue()) {
|
||||
self.collectionView?.scrollToItemAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: false)
|
||||
DispatchQueue.main.async {
|
||||
self.collectionView?.scrollToItem(at: indexPath, at: .bottom, animated: false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func scrollCollectionViewToInitialPosition() {
|
||||
guard isFirstAppearance else {
|
||||
return
|
||||
|
|
@ -49,43 +50,43 @@ class MomentViewController: AssetListViewController, ActivityIndicatable {
|
|||
guard lastSection >= 0 else {
|
||||
return
|
||||
}
|
||||
let indexPath = NSIndexPath(forItem: momentAlbumList[lastSection].count - 1, inSection: lastSection)
|
||||
let indexPath = IndexPath(item: momentAlbumList[lastSection].count - 1, section: lastSection)
|
||||
scrollCollectionView(to: indexPath)
|
||||
isFirstAppearance = false
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UICollectionViewDataSource
|
||||
|
||||
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
|
||||
|
||||
override func numberOfSections(in collectionView: UICollectionView) -> Int {
|
||||
if let activityIndicator = activityIndicator {
|
||||
updateVisibilityOfActivityIndicator(activityIndicator)
|
||||
}
|
||||
|
||||
|
||||
return momentAlbumList.count
|
||||
}
|
||||
|
||||
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return momentAlbumList[section].count
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UICollectionViewDelegate
|
||||
|
||||
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
|
||||
guard let cell = collectionView.dequeueReusableCellWithReuseIdentifier("AssetCell", forIndexPath: indexPath) as? AssetCell,
|
||||
nohanaImagePickerController = nohanaImagePickerController else {
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AssetCell", for: indexPath) as? AssetCell,
|
||||
let nohanaImagePickerController = nohanaImagePickerController else {
|
||||
fatalError("failed to dequeueReusableCellWithIdentifier(\"AssetCell\")")
|
||||
}
|
||||
|
||||
|
||||
let asset = momentAlbumList[indexPath.section][indexPath.row]
|
||||
cell.tag = indexPath.item
|
||||
cell.update(asset, nohanaImagePickerController: nohanaImagePickerController)
|
||||
cell.update(asset: asset, nohanaImagePickerController: nohanaImagePickerController)
|
||||
|
||||
let imageSize = CGSize(
|
||||
width: cellSize.width * UIScreen.mainScreen().scale,
|
||||
height: cellSize.height * UIScreen.mainScreen().scale
|
||||
width: cellSize.width * UIScreen.main.scale,
|
||||
height: cellSize.height * UIScreen.main.scale
|
||||
)
|
||||
asset.image(imageSize) { (imageData) -> Void in
|
||||
dispatch_async(dispatch_get_main_queue(), { () -> Void in
|
||||
asset.image(targetSize: imageSize) { (imageData) -> Void in
|
||||
DispatchQueue.main.async(execute: { () -> Void in
|
||||
if let imageData = imageData {
|
||||
if cell.tag == indexPath.item {
|
||||
cell.imageView.image = imageData.image
|
||||
|
|
@ -95,21 +96,21 @@ class MomentViewController: AssetListViewController, ActivityIndicatable {
|
|||
}
|
||||
return (nohanaImagePickerController.delegate?.nohanaImagePicker?(nohanaImagePickerController, assetListViewController: self, cell: cell, indexPath: indexPath, photoKitAsset: asset.originalAsset)) ?? cell
|
||||
}
|
||||
|
||||
override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
|
||||
switch kind {
|
||||
case UICollectionElementKindSectionHeader:
|
||||
case UICollectionView.elementKindSectionHeader:
|
||||
let album = momentAlbumList[indexPath.section]
|
||||
guard let header = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: "MomentHeader", forIndexPath: indexPath) as? MomentSectionHeaderView else {
|
||||
guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "MomentHeader", for: indexPath) as? MomentSectionHeaderView else {
|
||||
fatalError("failed to create MomentHeader")
|
||||
}
|
||||
header.locationLabel.text = album.title
|
||||
if let date = album.date {
|
||||
let formatter = NSDateFormatter()
|
||||
formatter.dateStyle = .LongStyle
|
||||
formatter.timeStyle = NSDateFormatterStyle.NoStyle
|
||||
header.dateLabel.text = formatter.stringFromDate(date)
|
||||
} else {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .long
|
||||
formatter.timeStyle = DateFormatter.Style.none
|
||||
header.dateLabel.text = formatter.string(from: date as Date)
|
||||
} else {
|
||||
header.dateLabel.text = ""
|
||||
}
|
||||
return header
|
||||
|
|
@ -117,47 +118,47 @@ class MomentViewController: AssetListViewController, ActivityIndicatable {
|
|||
fatalError("failed to create MomentHeader")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - ActivityIndicatable
|
||||
|
||||
|
||||
var activityIndicator: UIActivityIndicatorView?
|
||||
var isLoading = true
|
||||
|
||||
|
||||
func setUpActivityIndicator() {
|
||||
activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .Gray)
|
||||
activityIndicator = UIActivityIndicatorView(style: .gray)
|
||||
let screenRect = Size.screenRectWithoutAppBar(self)
|
||||
activityIndicator?.center = CGPoint(x: screenRect.size.width / 2, y: screenRect.size.height / 2)
|
||||
activityIndicator?.startAnimating()
|
||||
}
|
||||
|
||||
|
||||
func isProgressing() -> Bool {
|
||||
return isLoading
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UICollectionViewDelegate
|
||||
|
||||
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
if let nohanaImagePickerController = nohanaImagePickerController {
|
||||
nohanaImagePickerController.delegate?.nohanaImagePicker?(nohanaImagePickerController, didSelectPhotoKitAsset: momentAlbumList[indexPath.section][indexPath.row].originalAsset)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Storyboard
|
||||
|
||||
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
|
||||
guard let selectedIndexPath = collectionView?.indexPathsForSelectedItems()?.first else {
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
guard let selectedIndexPath = collectionView?.indexPathsForSelectedItems?.first else {
|
||||
return
|
||||
}
|
||||
let assetListDetailViewController = segue.destinationViewController as! AssetDetailListViewController
|
||||
let assetListDetailViewController = segue.destination as! AssetDetailListViewController
|
||||
assetListDetailViewController.photoKitAssetList = momentAlbumList[selectedIndexPath.section]
|
||||
assetListDetailViewController.nohanaImagePickerController = nohanaImagePickerController
|
||||
assetListDetailViewController.currentIndexPath = selectedIndexPath
|
||||
}
|
||||
|
||||
|
||||
// MARK: - IBAction
|
||||
|
||||
@IBAction override func didPushDone(sender: AnyObject) {
|
||||
|
||||
@IBAction override func didPushDone(_ sender: AnyObject) {
|
||||
super.didPushDone(sender)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,41 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15G1004" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_0" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Album List View Controller-->
|
||||
<scene sceneID="q2I-uS-c5w">
|
||||
<objects>
|
||||
<tableViewController id="KD8-91-yw0" customClass="AlbumListViewController" customModule="NohanaImagePicker" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableViewController storyboardIdentifier="AlbumListViewController" id="KD8-91-yw0" customClass="AlbumListViewController" customModule="NohanaImagePicker" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="Nh8-55-S0b">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="AlbumCell" rowHeight="82" id="HiQ-6b-xqZ" customClass="AlbumCell" customModule="NohanaImagePicker" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="92" width="320" height="82"/>
|
||||
<rect key="frame" x="0.0" y="28" width="320" height="82"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="HiQ-6b-xqZ" id="Nuf-ja-Ajg">
|
||||
<rect key="frame" x="0.0" y="0.0" width="287" height="82"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="286" height="82"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Igm-UH-WUI">
|
||||
<rect key="frame" x="12" y="6" width="70" height="70"/>
|
||||
<rect key="frame" x="20" y="6" width="70" height="70"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="70" id="Vc2-EG-fnZ"/>
|
||||
<constraint firstAttribute="height" constant="70" id="xiw-gz-cfn"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Album Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YSz-MM-h6f">
|
||||
<rect key="frame" x="100" y="33" width="187" height="16"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="16" id="X2y-hP-9aM"/>
|
||||
</constraints>
|
||||
<rect key="frame" x="108" y="31.5" width="178" height="19.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
<constraint firstAttribute="trailingMargin" secondItem="YSz-MM-h6f" secondAttribute="trailing" constant="-8" id="tee-FS-sAo"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<connections>
|
||||
<outlet property="thumbnailImageView" destination="Igm-UH-WUI" id="RZo-Jd-deA"/>
|
||||
<outlet property="titleLabel" destination="YSz-MM-h6f" id="bA5-m7-lwo"/>
|
||||
|
|
@ -55,19 +55,19 @@
|
|||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="MomentAlbumCell" rowHeight="52" id="URZ-ke-kYw" customClass="MomentCell" customModule="NohanaImagePicker" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="174" width="320" height="52"/>
|
||||
<rect key="frame" x="0.0" y="110" width="320" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="URZ-ke-kYw" id="ZzC-oj-tew">
|
||||
<rect key="frame" x="0.0" y="0.0" width="287" height="52"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="286" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Moment Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nzC-P1-sBf">
|
||||
<rect key="frame" x="16" y="18" width="271" height="16"/>
|
||||
<rect key="frame" x="24" y="18" width="262" height="16"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="16" id="tPC-2Q-2pd"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
|
|
@ -77,7 +77,7 @@
|
|||
<constraint firstItem="nzC-P1-sBf" firstAttribute="centerY" secondItem="ZzC-oj-tew" secondAttribute="centerY" id="SZH-em-zj3"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<connections>
|
||||
<outlet property="titleLabel" destination="nzC-P1-sBf" id="XE1-Qw-Xid"/>
|
||||
<segue destination="FOz-K3-QuR" kind="show" id="oPR-kG-SaF"/>
|
||||
|
|
@ -106,34 +106,35 @@
|
|||
<!--Asset List View Controller-->
|
||||
<scene sceneID="29G-N1-dd5">
|
||||
<objects>
|
||||
<collectionViewController id="5jk-x3-LYk" customClass="AssetListViewController" customModule="NohanaImagePicker" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<collectionViewController storyboardIdentifier="AssetListViewController" id="5jk-x3-LYk" customClass="AssetListViewController" customModule="NohanaImagePicker" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" id="cLH-x9-2VN">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="2" minimumInteritemSpacing="2" id="xXL-vg-bZb">
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="1" minimumInteritemSpacing="1" id="xXL-vg-bZb">
|
||||
<size key="itemSize" width="50" height="50"/>
|
||||
<size key="headerReferenceSize" width="0.0" height="0.0"/>
|
||||
<size key="footerReferenceSize" width="44" height="44"/>
|
||||
<inset key="sectionInset" minX="0.0" minY="8" maxX="0.0" maxY="2"/>
|
||||
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
</collectionViewFlowLayout>
|
||||
<cells>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="AssetCell" id="gNu-ad-t1d" customClass="AssetCell" customModule="NohanaImagePicker" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="72" width="78" height="78"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="78" height="78"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="78" height="78"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="WKb-lP-sq5">
|
||||
<rect key="frame" x="0.0" y="0.0" width="78" height="78"/>
|
||||
<rect key="frame" x="0.0" y="20" width="78" height="58"/>
|
||||
</imageView>
|
||||
<view hidden="YES" alpha="0.29999999999999999" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="MT5-kg-1gq">
|
||||
<rect key="frame" x="0.0" y="0.0" width="78" height="78"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<rect key="frame" x="0.0" y="20" width="78" height="58"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="oDB-be-mWY">
|
||||
<rect key="frame" x="34" y="0.0" width="44" height="44"/>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="right" contentVerticalAlignment="bottom" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="oDB-be-mWY">
|
||||
<rect key="frame" x="26" y="26" width="44" height="44"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="44" id="7Yd-sj-A9c"/>
|
||||
<constraint firstAttribute="height" constant="44" id="Biw-rC-p8x"/>
|
||||
|
|
@ -144,18 +145,17 @@
|
|||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="oDB-be-mWY" secondAttribute="trailing" constant="-8" id="0u6-oO-0PG"/>
|
||||
<constraint firstAttribute="trailing" secondItem="oDB-be-mWY" secondAttribute="trailing" constant="8" id="0u6-oO-0PG"/>
|
||||
<constraint firstItem="WKb-lP-sq5" firstAttribute="leading" secondItem="gNu-ad-t1d" secondAttribute="leadingMargin" constant="-8" id="Gen-Gr-Deg"/>
|
||||
<constraint firstItem="oDB-be-mWY" firstAttribute="top" secondItem="gNu-ad-t1d" secondAttribute="topMargin" constant="-8" id="HMs-XU-000"/>
|
||||
<constraint firstItem="MT5-kg-1gq" firstAttribute="top" secondItem="gNu-ad-t1d" secondAttribute="topMargin" constant="-8" id="ISy-ev-P19"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="WKb-lP-sq5" secondAttribute="bottom" constant="-8" id="Lnf-5f-guH"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="MT5-kg-1gq" secondAttribute="trailing" constant="-8" id="QL8-B4-uFE"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="MT5-kg-1gq" secondAttribute="bottom" constant="-8" id="RNL-zl-et0"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="WKb-lP-sq5" secondAttribute="trailing" constant="-8" id="TF3-Wc-2HZ"/>
|
||||
<constraint firstItem="MT5-kg-1gq" firstAttribute="leading" secondItem="gNu-ad-t1d" secondAttribute="leadingMargin" constant="-8" id="afC-Dk-wv1"/>
|
||||
<constraint firstAttribute="bottom" secondItem="oDB-be-mWY" secondAttribute="bottom" constant="8" id="hKA-oO-Fmk"/>
|
||||
<constraint firstItem="WKb-lP-sq5" firstAttribute="top" secondItem="gNu-ad-t1d" secondAttribute="topMargin" constant="-8" id="l0l-Ge-QIn"/>
|
||||
</constraints>
|
||||
<size key="customSize" width="78" height="78"/>
|
||||
|
|
@ -168,7 +168,7 @@
|
|||
</collectionViewCell>
|
||||
</cells>
|
||||
<collectionReusableView key="sectionFooterView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="AssetListFooter" id="N6q-ob-hkI">
|
||||
<rect key="frame" x="0.0" y="152" width="320" height="44"/>
|
||||
<rect key="frame" x="0.0" y="78" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</collectionReusableView>
|
||||
<connections>
|
||||
|
|
@ -188,12 +188,12 @@
|
|||
</collectionViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="1SX-Sl-Deo" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1156" y="267"/>
|
||||
<point key="canvasLocation" x="1749" y="214"/>
|
||||
</scene>
|
||||
<!--Asset Detail List View Controller-->
|
||||
<scene sceneID="jjo-0p-7dH">
|
||||
<objects>
|
||||
<collectionViewController id="r7t-t8-AuE" customClass="AssetDetailListViewController" customModule="NohanaImagePicker" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<collectionViewController storyboardIdentifier="AssetDetailListViewController" id="r7t-t8-AuE" customClass="AssetDetailListViewController" customModule="NohanaImagePicker" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" dataMode="prototypes" id="wIU-KV-n3W">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
|
|
@ -205,14 +205,14 @@
|
|||
</collectionViewFlowLayout>
|
||||
<cells>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="AssetDetailCell" id="Sux-7h-iE6" customClass="AssetDetailCell" customModule="NohanaImagePicker" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="156" width="320" height="320"/>
|
||||
<rect key="frame" x="0.0" y="92" width="320" height="320"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="320"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" maximumZoomScale="3" translatesAutoresizingMaskIntoConstraints="NO" id="hM8-Xr-3HX">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="320"/>
|
||||
<rect key="frame" x="0.0" y="20" width="320" height="300"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Jr7-IN-pxL">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="320"/>
|
||||
|
|
@ -234,7 +234,6 @@
|
|||
</connections>
|
||||
</scrollView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<gestureRecognizers/>
|
||||
<constraints>
|
||||
|
|
@ -259,9 +258,8 @@
|
|||
<navigationItem key="navigationItem" id="UuE-5y-0BI">
|
||||
<barButtonItem key="rightBarButtonItem" id="K6j-IO-w2n">
|
||||
<button key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="c4C-Sf-Krj">
|
||||
<rect key="frame" x="276" y="8" width="28" height="28"/>
|
||||
<rect key="frame" x="274" y="5" width="30" height="34"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="btn_select_l"/>
|
||||
<connections>
|
||||
<action selector="didPushPickButton:" destination="r7t-t8-AuE" eventType="touchUpInside" id="vWF-yZ-1NC"/>
|
||||
</connections>
|
||||
|
|
@ -271,12 +269,13 @@
|
|||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<size key="freeformSize" width="320" height="568"/>
|
||||
<connections>
|
||||
<outlet property="imageCollectionView" destination="wIU-KV-n3W" id="9kr-es-gvr"/>
|
||||
<outlet property="pickButton" destination="c4C-Sf-Krj" id="Bam-Wm-TRa"/>
|
||||
</connections>
|
||||
</collectionViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="u84-ka-8a6" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1598" y="456"/>
|
||||
<point key="canvasLocation" x="2741" y="449"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="RR9-zr-Qlw">
|
||||
|
|
@ -286,7 +285,7 @@
|
|||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<size key="freeformSize" width="320" height="568"/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="tdZ-Dj-Unr">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<rect key="frame" x="0.0" y="20" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<nil name="viewControllers"/>
|
||||
|
|
@ -296,7 +295,7 @@
|
|||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="3iI-ph-cZF" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="259" y="219"/>
|
||||
<point key="canvasLocation" x="-456" y="215"/>
|
||||
</scene>
|
||||
<!--Animatable Navigation Controller-->
|
||||
<scene sceneID="Zpb-f1-dmj">
|
||||
|
|
@ -305,7 +304,7 @@
|
|||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<size key="freeformSize" width="320" height="568"/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="BOZ-Zf-lAN">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<rect key="frame" x="0.0" y="20" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
|
|
@ -314,16 +313,16 @@
|
|||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Sfb-mw-QnO" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="259" y="882"/>
|
||||
<point key="canvasLocation" x="-458" y="935"/>
|
||||
</scene>
|
||||
<!--Moment View Controller-->
|
||||
<scene sceneID="kJ6-NP-kmc">
|
||||
<objects>
|
||||
<collectionViewController id="FOz-K3-QuR" customClass="MomentViewController" customModule="NohanaImagePicker" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<collectionViewController storyboardIdentifier="MomentViewController" id="FOz-K3-QuR" customClass="MomentViewController" customModule="NohanaImagePicker" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" id="J9r-MB-y52">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="2" minimumInteritemSpacing="2" id="smE-Ti-qUX">
|
||||
<size key="itemSize" width="50" height="50"/>
|
||||
<size key="headerReferenceSize" width="50" height="44"/>
|
||||
|
|
@ -332,37 +331,34 @@
|
|||
</collectionViewFlowLayout>
|
||||
<cells>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="AssetCell" id="hn9-bM-eId" customClass="AssetCell" customModule="NohanaImagePicker" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="110" width="78" height="78"/>
|
||||
<rect key="frame" x="0.0" y="46" width="78" height="78"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="78" height="78"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="TB3-Xf-nik">
|
||||
<rect key="frame" x="0.0" y="0.0" width="78" height="78"/>
|
||||
<rect key="frame" x="0.0" y="20" width="78" height="58"/>
|
||||
</imageView>
|
||||
<view hidden="YES" alpha="0.30000001192092896" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SnZ-bd-Zia">
|
||||
<rect key="frame" x="0.0" y="0.0" width="78" height="78"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<rect key="frame" x="0.0" y="20" width="78" height="58"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="vrt-tc-b54">
|
||||
<rect key="frame" x="34" y="0.0" width="44" height="44"/>
|
||||
<rect key="frame" x="34" y="26" width="44" height="44"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="44" id="BX8-gP-86t"/>
|
||||
<constraint firstAttribute="height" constant="44" id="RUG-gG-ieX"/>
|
||||
</constraints>
|
||||
<state key="normal" image="btn_select_m"/>
|
||||
<connections>
|
||||
<action selector="didPushPickButton:" destination="hn9-bM-eId" eventType="touchUpInside" id="g70-dv-o5C"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="SnZ-bd-Zia" secondAttribute="bottom" constant="-8" id="1hA-eS-4fw"/>
|
||||
<constraint firstItem="SnZ-bd-Zia" firstAttribute="leading" secondItem="hn9-bM-eId" secondAttribute="leadingMargin" constant="-8" id="57F-oY-ykD"/>
|
||||
<constraint firstItem="vrt-tc-b54" firstAttribute="top" secondItem="hn9-bM-eId" secondAttribute="topMargin" constant="-8" id="Djb-rK-T7y"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="vrt-tc-b54" secondAttribute="trailing" constant="-8" id="KEs-ry-rwP"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="TB3-Xf-nik" secondAttribute="trailing" constant="-8" id="XM8-uU-hsZ"/>
|
||||
<constraint firstItem="TB3-Xf-nik" firstAttribute="top" secondItem="hn9-bM-eId" secondAttribute="topMargin" constant="-8" id="avn-LP-mMH"/>
|
||||
|
|
@ -370,6 +366,7 @@
|
|||
<constraint firstAttribute="trailingMargin" secondItem="SnZ-bd-Zia" secondAttribute="trailing" constant="-8" id="kX3-02-UOR"/>
|
||||
<constraint firstItem="SnZ-bd-Zia" firstAttribute="top" secondItem="hn9-bM-eId" secondAttribute="topMargin" constant="-8" id="vZV-H0-2Fs"/>
|
||||
<constraint firstItem="TB3-Xf-nik" firstAttribute="leading" secondItem="hn9-bM-eId" secondAttribute="leadingMargin" constant="-8" id="wGD-kd-Ibg"/>
|
||||
<constraint firstAttribute="bottom" secondItem="vrt-tc-b54" secondAttribute="bottom" constant="8" id="z5g-3Q-yNU"/>
|
||||
</constraints>
|
||||
<size key="customSize" width="78" height="78"/>
|
||||
<connections>
|
||||
|
|
@ -381,18 +378,17 @@
|
|||
</collectionViewCell>
|
||||
</cells>
|
||||
<collectionReusableView key="sectionHeaderView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MomentHeader" id="BCa-t3-9XW" customClass="MomentSectionHeaderView" customModule="NohanaImagePicker" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="64" width="320" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Date" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aNJ-Oh-VhZ">
|
||||
<rect key="frame" x="12" y="11" width="120" height="21"/>
|
||||
<rect key="frame" x="12" y="13.5" width="120" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="21" id="KSm-hH-VZX"/>
|
||||
<constraint firstAttribute="width" constant="120" id="QzC-0j-DZA"/>
|
||||
<constraint firstAttribute="height" constant="21" id="XMh-5E-eAL"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<variation key="default">
|
||||
<mask key="constraints">
|
||||
|
|
@ -401,12 +397,9 @@
|
|||
</variation>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Location" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9Aa-PA-AHS">
|
||||
<rect key="frame" x="132" y="12" width="176" height="21"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="21" id="QVr-qn-Rz7"/>
|
||||
</constraints>
|
||||
<rect key="frame" x="132" y="15" width="176" height="14.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
|
|
@ -447,15 +440,14 @@
|
|||
</collectionViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="A16-1a-z3b" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1156" y="914"/>
|
||||
<point key="canvasLocation" x="1751" y="965"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="btn_select_l" width="28" height="28"/>
|
||||
<image name="btn_select_m" width="44" height="44"/>
|
||||
</resources>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="tQI-o9-h2w"/>
|
||||
<segue reference="Bed-w3-B1Q"/>
|
||||
<segue reference="tQI-o9-h2w"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
</document>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
|
@ -6,12 +6,12 @@
|
|||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_photosize_low_s@2x.png",
|
||||
"filename" : "btn_select_m@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_photosize_low_s@3x.png",
|
||||
"filename" : "btn_select_m@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
|
@ -6,12 +6,12 @@
|
|||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_photosize_alert_s@2x.png",
|
||||
"filename" : "btn_selected_m@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "icon_photosize_alert_s@3x.png",
|
||||
"filename" : "btn_selected_m@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
|
@ -18,70 +18,72 @@ import UIKit
|
|||
import Photos
|
||||
|
||||
public enum MediaType: Int {
|
||||
case Any = 0, Photo, Video
|
||||
case any = 0, photo, video
|
||||
}
|
||||
|
||||
@objc public protocol NohanaImagePickerControllerDelegate {
|
||||
func nohanaImagePickerDidCancel(picker: NohanaImagePickerController)
|
||||
func nohanaImagePicker(picker: NohanaImagePickerController, didFinishPickingPhotoKitAssets pickedAssts :[PHAsset])
|
||||
optional func nohanaImagePicker(picker: NohanaImagePickerController, willPickPhotoKitAsset asset: PHAsset, pickedAssetsCount: Int) -> Bool
|
||||
optional func nohanaImagePicker(picker: NohanaImagePickerController, didPickPhotoKitAsset asset: PHAsset, pickedAssetsCount: Int)
|
||||
optional func nohanaImagePicker(picker: NohanaImagePickerController, willDropPhotoKitAsset asset: PHAsset, pickedAssetsCount: Int) -> Bool
|
||||
optional func nohanaImagePicker(picker: NohanaImagePickerController, didDropPhotoKitAsset asset: PHAsset, pickedAssetsCount: Int)
|
||||
optional func nohanaImagePicker(picker: NohanaImagePickerController, didSelectPhotoKitAsset asset: PHAsset)
|
||||
optional func nohanaImagePicker(picker: NohanaImagePickerController, didSelectPhotoKitAssetList assetList: PHAssetCollection)
|
||||
optional func nohanaImagePickerDidSelectMoment(picker: NohanaImagePickerController) -> Void
|
||||
optional func nohanaImagePicker(picker: NohanaImagePickerController, assetListViewController: UICollectionViewController, cell: UICollectionViewCell, indexPath: NSIndexPath, photoKitAsset: PHAsset) -> UICollectionViewCell
|
||||
optional func nohanaImagePicker(picker: NohanaImagePickerController, assetDetailListViewController: UICollectionViewController, cell: UICollectionViewCell, indexPath: NSIndexPath, photoKitAsset: PHAsset) -> UICollectionViewCell
|
||||
optional func nohanaImagePicker(picker: NohanaImagePickerController, assetDetailListViewController: UICollectionViewController, didChangeAssetDetailPage indexPath: NSIndexPath, photoKitAsset: PHAsset)
|
||||
|
||||
func nohanaImagePickerDidCancel(_ picker: NohanaImagePickerController)
|
||||
func nohanaImagePicker(_ picker: NohanaImagePickerController, didFinishPickingPhotoKitAssets pickedAssts: [PHAsset])
|
||||
@objc optional func nohanaImagePicker(_ picker: NohanaImagePickerController, willPickPhotoKitAsset asset: PHAsset, pickedAssetsCount: Int) -> Bool
|
||||
@objc optional func nohanaImagePicker(_ picker: NohanaImagePickerController, didPickPhotoKitAsset asset: PHAsset, pickedAssetsCount: Int)
|
||||
@objc optional func nohanaImagePicker(_ picker: NohanaImagePickerController, willDropPhotoKitAsset asset: PHAsset, pickedAssetsCount: Int) -> Bool
|
||||
@objc optional func nohanaImagePicker(_ picker: NohanaImagePickerController, didDropPhotoKitAsset asset: PHAsset, pickedAssetsCount: Int)
|
||||
@objc optional func nohanaImagePicker(_ picker: NohanaImagePickerController, didSelectPhotoKitAsset asset: PHAsset)
|
||||
@objc optional func nohanaImagePicker(_ picker: NohanaImagePickerController, didSelectPhotoKitAssetList assetList: PHAssetCollection)
|
||||
@objc optional func nohanaImagePickerDidSelectMoment(_ picker: NohanaImagePickerController) -> Void
|
||||
@objc optional func nohanaImagePicker(_ picker: NohanaImagePickerController, assetListViewController: UICollectionViewController, cell: UICollectionViewCell, indexPath: IndexPath, photoKitAsset: PHAsset) -> UICollectionViewCell
|
||||
@objc optional func nohanaImagePicker(_ picker: NohanaImagePickerController, assetDetailListViewController: UICollectionViewController, cell: UICollectionViewCell, indexPath: IndexPath, photoKitAsset: PHAsset) -> UICollectionViewCell
|
||||
@objc optional func nohanaImagePicker(_ picker: NohanaImagePickerController, assetDetailListViewController: UICollectionViewController, didChangeAssetDetailPage indexPath: IndexPath, photoKitAsset: PHAsset)
|
||||
|
||||
}
|
||||
|
||||
public class NohanaImagePickerController: UIViewController {
|
||||
|
||||
public var maximumNumberOfSelection: Int = 21 // set 0 to set no limit
|
||||
public var numberOfColumnsInPortrait: Int = 4
|
||||
public var numberOfColumnsInLandscape: Int = 7
|
||||
public weak var delegate: NohanaImagePickerControllerDelegate?
|
||||
public var shouldShowMoment: Bool = true
|
||||
public var shouldShowEmptyAlbum: Bool = false
|
||||
public var toolbarHidden: Bool = false
|
||||
public var canPickAsset = { (asset:AssetType) -> Bool in
|
||||
open class NohanaImagePickerController: UIViewController {
|
||||
|
||||
open var maximumNumberOfSelection: Int = 21 // set 0 to no limit
|
||||
open var numberOfColumnsInPortrait: Int = 4
|
||||
open var numberOfColumnsInLandscape: Int = 7
|
||||
open weak var delegate: NohanaImagePickerControllerDelegate?
|
||||
open var shouldShowMoment: Bool = true
|
||||
open var shouldShowEmptyAlbum: Bool = false
|
||||
open var toolbarHidden: Bool = false
|
||||
open var canPickAsset = { (asset: Asset) -> Bool in
|
||||
return true
|
||||
}
|
||||
lazy var assetBundle:NSBundle = {
|
||||
let bundle = NSBundle(forClass: self.dynamicType)
|
||||
if let path = bundle.pathForResource("NohanaImagePicker", ofType: "bundle") {
|
||||
return NSBundle(path: path)!
|
||||
open var config: Config = Config()
|
||||
|
||||
lazy var assetBundle: Bundle = {
|
||||
let bundle = Bundle(for: type(of: self))
|
||||
if let path = bundle.path(forResource: "NohanaImagePicker", ofType: "bundle") {
|
||||
return Bundle(path: path)!
|
||||
}
|
||||
return bundle
|
||||
}()
|
||||
let pickedAssetList: PickedAssetList
|
||||
let mediaType: MediaType
|
||||
let enableExpandingPhotoAnimation: Bool
|
||||
private let assetCollectionSubtypes: [PHAssetCollectionSubtype]
|
||||
|
||||
fileprivate let assetCollectionSubtypes: [PHAssetCollectionSubtype]
|
||||
|
||||
public init() {
|
||||
assetCollectionSubtypes = [
|
||||
.AlbumRegular,
|
||||
.AlbumSyncedEvent,
|
||||
.AlbumSyncedFaces,
|
||||
.AlbumSyncedAlbum,
|
||||
.AlbumImported,
|
||||
.AlbumMyPhotoStream,
|
||||
.AlbumCloudShared,
|
||||
.SmartAlbumGeneric,
|
||||
.SmartAlbumFavorites,
|
||||
.SmartAlbumRecentlyAdded,
|
||||
.SmartAlbumUserLibrary
|
||||
.albumRegular,
|
||||
.albumSyncedEvent,
|
||||
.albumSyncedFaces,
|
||||
.albumSyncedAlbum,
|
||||
.albumImported,
|
||||
.albumMyPhotoStream,
|
||||
.albumCloudShared,
|
||||
.smartAlbumGeneric,
|
||||
.smartAlbumFavorites,
|
||||
.smartAlbumRecentlyAdded,
|
||||
.smartAlbumUserLibrary
|
||||
]
|
||||
mediaType = .Photo
|
||||
mediaType = .photo
|
||||
pickedAssetList = PickedAssetList()
|
||||
enableExpandingPhotoAnimation = true
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
self.pickedAssetList.nohanaImagePickerController = self
|
||||
}
|
||||
|
||||
|
||||
public init(assetCollectionSubtypes: [PHAssetCollectionSubtype], mediaType: MediaType, enableExpandingPhotoAnimation: Bool) {
|
||||
self.assetCollectionSubtypes = assetCollectionSubtypes
|
||||
self.mediaType = mediaType
|
||||
|
|
@ -95,44 +97,72 @@ public class NohanaImagePickerController: UIViewController {
|
|||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override public func viewDidLoad() {
|
||||
override open func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
||||
// show albumListViewController
|
||||
let storyboard = UIStoryboard(name: "NohanaImagePicker", bundle: assetBundle)
|
||||
let viewControllerId = enableExpandingPhotoAnimation ? "EnableAnimationNavigationController" : "DisableAnimationNavigationController"
|
||||
guard let navigationController = storyboard.instantiateViewControllerWithIdentifier(viewControllerId) as? UINavigationController else {
|
||||
guard let navigationController = storyboard.instantiateViewController(withIdentifier: viewControllerId) as? UINavigationController else {
|
||||
fatalError("navigationController init failed.")
|
||||
}
|
||||
addChildViewController(navigationController)
|
||||
addChild(navigationController)
|
||||
view.addSubview(navigationController.view)
|
||||
navigationController.didMoveToParentViewController(self)
|
||||
|
||||
navigationController.didMove(toParent: self)
|
||||
|
||||
// setup albumListViewController
|
||||
guard let albumListViewController = navigationController.topViewController as? AlbumListViewController else {
|
||||
fatalError("albumListViewController is not topViewController.")
|
||||
}
|
||||
albumListViewController.photoKitAlbumList =
|
||||
PhotoKitAlbumList(
|
||||
assetCollectionTypes: [.SmartAlbum, .Album],
|
||||
assetCollectionTypes: [.smartAlbum, .album],
|
||||
assetCollectionSubtypes: assetCollectionSubtypes,
|
||||
mediaType: mediaType,
|
||||
shouldShowEmptyAlbum: shouldShowEmptyAlbum,
|
||||
handler: { [weak albumListViewController] in
|
||||
dispatch_async(dispatch_get_main_queue(), { () -> Void in
|
||||
DispatchQueue.main.async(execute: { () -> Void in
|
||||
albumListViewController?.isLoading = false
|
||||
albumListViewController?.tableView.reloadData()
|
||||
})
|
||||
})
|
||||
albumListViewController.nohanaImagePickerController = self
|
||||
}
|
||||
|
||||
public func pickAsset(asset: AssetType) {
|
||||
pickedAssetList.pickAsset(asset)
|
||||
|
||||
open func pickAsset(_ asset: Asset) {
|
||||
_ = pickedAssetList.pick(asset: asset)
|
||||
}
|
||||
|
||||
public func dropAsset(asset: AssetType) {
|
||||
pickedAssetList.dropAsset(asset)
|
||||
|
||||
open func dropAsset(_ asset: Asset) {
|
||||
_ = pickedAssetList.drop(asset: asset)
|
||||
}
|
||||
}
|
||||
|
||||
extension NohanaImagePickerController {
|
||||
public struct Config {
|
||||
public struct Color {
|
||||
public var background: UIColor?
|
||||
public var empty: UIColor?
|
||||
public var separator: UIColor?
|
||||
}
|
||||
public var color = Color()
|
||||
|
||||
public struct Image {
|
||||
public var pickedSmall: UIImage?
|
||||
public var pickedLarge: UIImage?
|
||||
public var droppedSmall: UIImage?
|
||||
public var droppedLarge: UIImage?
|
||||
}
|
||||
public var image = Image()
|
||||
|
||||
public struct Strings {
|
||||
public var albumListTitle: String?
|
||||
public var albumListMomentTitle: String?
|
||||
public var albumListEmptyMessage: String?
|
||||
public var albumListEmptyDescription: String?
|
||||
public var toolbarTitleNoLimit: String?
|
||||
public var toolbarTitleHasLimit: String?
|
||||
}
|
||||
public var strings = Strings()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@
|
|||
struct NotificationInfo {
|
||||
struct Asset {
|
||||
struct PhotoKit {
|
||||
static let didPick = "jp.co.nohana.NotificationName.Asset.PhotoKit.didPick"
|
||||
static let didPick = Notification.Name("jp.co.nohana.NotificationName.Asset.PhotoKit.didPick")
|
||||
static let didPickUserInfoKeyAsset = "asset"
|
||||
static let didPickUserInfoKeyPickedAssetsCount = "pickedAssetsCount"
|
||||
static let didDrop = "jp.co.nohana.NotificationName.Asset.PhotoKit.didDrop"
|
||||
static let didDrop = Notification.Name("jp.co.nohana.NotificationName.Asset.PhotoKit.didDrop")
|
||||
static let didDropUserInfoKeyAsset = "asset"
|
||||
static let didDropUserInfoKeyPickedAssetsCount = "pickedAssetsCount"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,14 +15,14 @@
|
|||
*/
|
||||
import Photos
|
||||
|
||||
public class PhotoKitAlbumList: ItemListType {
|
||||
|
||||
private var albumList:[Item] = []
|
||||
public class PhotoKitAlbumList: ItemList {
|
||||
|
||||
private var albumList: [Item] = []
|
||||
private let assetCollectionTypes: [PHAssetCollectionType]
|
||||
private let assetCollectionSubtypes: [PHAssetCollectionSubtype]
|
||||
private let mediaType: MediaType
|
||||
private var shouldShowEmptyAlbum: Bool
|
||||
|
||||
|
||||
// MARK: - init
|
||||
|
||||
init(assetCollectionTypes: [PHAssetCollectionType], assetCollectionSubtypes: [PHAssetCollectionSubtype], mediaType: MediaType, shouldShowEmptyAlbum: Bool, handler:(() -> Void)?) {
|
||||
|
|
@ -36,69 +36,58 @@ public class PhotoKitAlbumList: ItemListType {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ItemListType
|
||||
|
||||
|
||||
// MARK: - ItemList
|
||||
|
||||
public typealias Item = PhotoKitAssetList
|
||||
|
||||
public var title:String {
|
||||
get {
|
||||
return "PhotoKit"
|
||||
}
|
||||
|
||||
open var title: String {
|
||||
return "PhotoKit"
|
||||
}
|
||||
|
||||
public func update(handler:(() -> Void)?) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { () -> Void in
|
||||
var albumListFetchResult: [PHFetchResult] = []
|
||||
|
||||
open func update(_ handler:(() -> Void)?) {
|
||||
DispatchQueue.global(qos: .default).async {
|
||||
var albumListFetchResult: [PHFetchResult<PHAssetCollection>] = []
|
||||
for type in self.assetCollectionTypes {
|
||||
albumListFetchResult = albumListFetchResult + [PHAssetCollection.fetchAssetCollectionsWithType(type, subtype: .Any, options: nil)]
|
||||
albumListFetchResult = albumListFetchResult + [PHAssetCollection.fetchAssetCollections(with: type, subtype: .any, options: nil)]
|
||||
}
|
||||
|
||||
|
||||
self.albumList = []
|
||||
var tmpAlbumList:[Item] = []
|
||||
let isAssetCollectionSubtypeAny = self.assetCollectionSubtypes.contains(.Any)
|
||||
var tmpAlbumList: [Item] = []
|
||||
let isAssetCollectionSubtypeAny = self.assetCollectionSubtypes.contains(.any)
|
||||
for fetchResult in albumListFetchResult {
|
||||
fetchResult.enumerateObjectsUsingBlock { (album, index, stop) -> Void in
|
||||
guard let album = album as? PHAssetCollection else {
|
||||
return
|
||||
}
|
||||
fetchResult.enumerateObjects({ (album, index, stop) in
|
||||
if self.assetCollectionSubtypes.contains(album.assetCollectionSubtype) || isAssetCollectionSubtypeAny {
|
||||
if self.shouldShowEmptyAlbum || PHAsset.fetchAssetsInAssetCollection(album, options: PhotoKitAssetList.fetchOptions(self.mediaType)).count != 0 {
|
||||
if self.shouldShowEmptyAlbum || PHAsset.fetchAssets(in: album, options: PhotoKitAssetList.fetchOptions(self.mediaType)).count != 0 {
|
||||
tmpAlbumList.append(PhotoKitAssetList(album: album, mediaType: self.mediaType))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
if self.assetCollectionTypes == [.Moment] {
|
||||
self.albumList = tmpAlbumList.sort{ $0.date?.timeIntervalSince1970 < $1.date?.timeIntervalSince1970 }
|
||||
if self.assetCollectionTypes == [.moment] {
|
||||
self.albumList = tmpAlbumList.sorted { $0.date!.timeIntervalSince1970 < $1.date!.timeIntervalSince1970 }
|
||||
} else {
|
||||
self.albumList = tmpAlbumList
|
||||
}
|
||||
|
||||
|
||||
if let handler = handler {
|
||||
handler()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public subscript (index: Int) -> Item {
|
||||
get {
|
||||
return albumList[index] as Item
|
||||
}
|
||||
|
||||
open subscript (index: Int) -> Item {
|
||||
return albumList[index] as Item
|
||||
}
|
||||
|
||||
|
||||
// MARK: - CollectionType
|
||||
|
||||
public var startIndex: Int {
|
||||
get {
|
||||
return albumList.startIndex
|
||||
}
|
||||
|
||||
open var startIndex: Int {
|
||||
return albumList.startIndex
|
||||
}
|
||||
|
||||
public var endIndex: Int {
|
||||
get {
|
||||
return albumList.endIndex
|
||||
}
|
||||
|
||||
open var endIndex: Int {
|
||||
return albumList.endIndex
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,42 +15,38 @@
|
|||
*/
|
||||
import Photos
|
||||
|
||||
public class PhotoKitAsset :AssetType {
|
||||
|
||||
public class PhotoKitAsset: Asset {
|
||||
|
||||
let asset: PHAsset
|
||||
|
||||
|
||||
public init(asset: PHAsset) {
|
||||
self.asset = asset
|
||||
}
|
||||
|
||||
|
||||
public var originalAsset: PHAsset {
|
||||
get {
|
||||
return asset as PHAsset
|
||||
}
|
||||
return asset as PHAsset
|
||||
}
|
||||
|
||||
// MARK: - AssetType
|
||||
|
||||
public var identifier:Int {
|
||||
get {
|
||||
return asset.localIdentifier.hash
|
||||
}
|
||||
|
||||
// MARK: - Asset
|
||||
|
||||
public var identifier: Int {
|
||||
return asset.localIdentifier.hash
|
||||
}
|
||||
|
||||
public func image(targetSize:CGSize, handler: (ImageData?) -> Void) {
|
||||
|
||||
public func image(targetSize: CGSize, handler: @escaping (ImageData?) -> Void) {
|
||||
let option = PHImageRequestOptions()
|
||||
option.networkAccessAllowed = true
|
||||
|
||||
PHImageManager.defaultManager().requestImageForAsset(
|
||||
self.asset,
|
||||
option.isNetworkAccessAllowed = true
|
||||
|
||||
_ = PHImageManager.default().requestImage(
|
||||
for: self.asset,
|
||||
targetSize: targetSize,
|
||||
contentMode: .AspectFit,
|
||||
contentMode: .aspectFit,
|
||||
options: option ) { (image, info) -> Void in
|
||||
guard let image = image else {
|
||||
handler(nil)
|
||||
return
|
||||
}
|
||||
handler(ImageData(image: image, info: info))
|
||||
handler(ImageData(image: image, info: info as Dictionary<NSObject, AnyObject>?))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,72 +16,59 @@
|
|||
|
||||
import Photos
|
||||
|
||||
public class PhotoKitAssetList :ItemListType {
|
||||
|
||||
private let mediaType: MediaType
|
||||
open class PhotoKitAssetList: ItemList {
|
||||
|
||||
fileprivate let mediaType: MediaType
|
||||
public let assetList: PHAssetCollection
|
||||
private var fetchResult: PHFetchResult!
|
||||
|
||||
fileprivate var fetchResult: PHFetchResult<PHAsset>!
|
||||
|
||||
init(album: PHAssetCollection, mediaType: MediaType) {
|
||||
self.assetList = album
|
||||
self.mediaType = mediaType
|
||||
update()
|
||||
}
|
||||
|
||||
// MARK: - ItemListType
|
||||
|
||||
|
||||
// MARK: - ItemList
|
||||
|
||||
public typealias Item = PhotoKitAsset
|
||||
|
||||
public var title: String {
|
||||
get{
|
||||
return assetList.localizedTitle ?? ""
|
||||
}
|
||||
|
||||
open var title: String {
|
||||
return assetList.localizedTitle ?? ""
|
||||
}
|
||||
|
||||
public var date: NSDate? {
|
||||
get {
|
||||
return assetList.startDate
|
||||
}
|
||||
|
||||
open var date: Date? {
|
||||
return assetList.startDate
|
||||
}
|
||||
|
||||
class func fetchOptions(mediaType: MediaType) -> PHFetchOptions {
|
||||
|
||||
class func fetchOptions(_ mediaType: MediaType) -> PHFetchOptions {
|
||||
let options = PHFetchOptions()
|
||||
switch mediaType {
|
||||
case .Photo:
|
||||
options.predicate = NSPredicate(format: "mediaType == %ld", PHAssetMediaType.Image.rawValue)
|
||||
case .photo:
|
||||
options.predicate = NSPredicate(format: "mediaType == %ld", PHAssetMediaType.image.rawValue)
|
||||
default:
|
||||
fatalError("not supported .Video and .Any yet")
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
public func update(handler: (() -> Void)? = nil) {
|
||||
fetchResult = PHAsset.fetchAssetsInAssetCollection(assetList, options: PhotoKitAssetList.fetchOptions(mediaType))
|
||||
|
||||
open func update(_ handler: (() -> Void)? = nil) {
|
||||
fetchResult = PHAsset.fetchAssets(in: assetList, options: PhotoKitAssetList.fetchOptions(mediaType))
|
||||
if let handler = handler {
|
||||
handler()
|
||||
}
|
||||
}
|
||||
|
||||
public subscript (index: Int) -> Item {
|
||||
get {
|
||||
guard let asset = fetchResult[index] as? PHAsset else {
|
||||
fatalError("invalid index")
|
||||
}
|
||||
return Item(asset: asset)
|
||||
}
|
||||
|
||||
open subscript (index: Int) -> Item {
|
||||
return Item(asset: fetchResult.object(at: index))
|
||||
}
|
||||
|
||||
|
||||
// MARK: - CollectionType
|
||||
|
||||
public var startIndex: Int {
|
||||
get {
|
||||
return 0
|
||||
}
|
||||
|
||||
open var startIndex: Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
public var endIndex: Int {
|
||||
get {
|
||||
return fetchResult.count
|
||||
}
|
||||
|
||||
open var endIndex: Int {
|
||||
return fetchResult.count
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,56 +16,46 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
class PickedAssetList: ItemListType {
|
||||
|
||||
var assetlist: Array<AssetType> = []
|
||||
class PickedAssetList: ItemList {
|
||||
|
||||
var assetlist: Array<Asset> = []
|
||||
weak var nohanaImagePickerController: NohanaImagePickerController?
|
||||
|
||||
// MARK: - ItemListType
|
||||
|
||||
typealias Item = AssetType
|
||||
|
||||
|
||||
// MARK: - ItemList
|
||||
|
||||
typealias Item = Asset
|
||||
|
||||
var title: String {
|
||||
get {
|
||||
return "Selected Assets"
|
||||
}
|
||||
return "Selected Assets"
|
||||
}
|
||||
|
||||
func update(handler:(() -> Void)?) {
|
||||
|
||||
func update(_ handler:(() -> Void)?) {
|
||||
fatalError("not supported")
|
||||
}
|
||||
|
||||
|
||||
|
||||
subscript (index: Int) -> Item {
|
||||
get {
|
||||
return assetlist[index]
|
||||
}
|
||||
return assetlist[index]
|
||||
}
|
||||
|
||||
|
||||
// MARK: - CollectionType
|
||||
|
||||
|
||||
var startIndex: Int {
|
||||
get {
|
||||
return 0
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
var endIndex: Int {
|
||||
get {
|
||||
return assetlist.count
|
||||
}
|
||||
return assetlist.count
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Manage assetlist
|
||||
|
||||
func pickAsset(asset: AssetType) -> Bool {
|
||||
|
||||
func pick(asset: Asset) -> Bool {
|
||||
guard !isPicked(asset) else {
|
||||
return false
|
||||
}
|
||||
let assetsCountBeforePicking = self.count
|
||||
if asset is PhotoKitAsset {
|
||||
if let canPick = nohanaImagePickerController!.delegate?.nohanaImagePicker?(nohanaImagePickerController!, willPickPhotoKitAsset: (asset as! PhotoKitAsset).originalAsset, pickedAssetsCount: assetsCountBeforePicking)
|
||||
where !canPick {
|
||||
if let canPick = nohanaImagePickerController!.delegate?.nohanaImagePicker?(nohanaImagePickerController!, willPickPhotoKitAsset: (asset as! PhotoKitAsset).originalAsset, pickedAssetsCount: assetsCountBeforePicking), !canPick {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -77,8 +67,8 @@ class PickedAssetList: ItemListType {
|
|||
if asset is PhotoKitAsset {
|
||||
let originalAsset = (asset as! PhotoKitAsset).originalAsset
|
||||
nohanaImagePickerController!.delegate?.nohanaImagePicker?(nohanaImagePickerController!, didPickPhotoKitAsset: originalAsset, pickedAssetsCount: assetsCountAfterPicking)
|
||||
NSNotificationCenter.defaultCenter().postNotification(
|
||||
NSNotification(
|
||||
NotificationCenter.default.post(
|
||||
Notification(
|
||||
name: NotificationInfo.Asset.PhotoKit.didPick,
|
||||
object: nohanaImagePickerController,
|
||||
userInfo: [
|
||||
|
|
@ -89,23 +79,23 @@ class PickedAssetList: ItemListType {
|
|||
)
|
||||
}
|
||||
return true
|
||||
|
||||
|
||||
}
|
||||
|
||||
func dropAsset(asset: AssetType) -> Bool {
|
||||
|
||||
func drop(asset: Asset) -> Bool {
|
||||
let assetsCountBeforeDropping = self.count
|
||||
if asset is PhotoKitAsset {
|
||||
if let canDrop = nohanaImagePickerController!.delegate?.nohanaImagePicker?(nohanaImagePickerController!, willDropPhotoKitAsset: (asset as! PhotoKitAsset).originalAsset, pickedAssetsCount: assetsCountBeforeDropping) where !canDrop {
|
||||
if let canDrop = nohanaImagePickerController!.delegate?.nohanaImagePicker?(nohanaImagePickerController!, willDropPhotoKitAsset: (asset as! PhotoKitAsset).originalAsset, pickedAssetsCount: assetsCountBeforeDropping), !canDrop {
|
||||
return false
|
||||
}
|
||||
}
|
||||
assetlist = assetlist.filter{ $0.identifier != asset.identifier }
|
||||
assetlist = assetlist.filter { $0.identifier != asset.identifier }
|
||||
let assetsCountAfterDropping = self.count
|
||||
if asset is PhotoKitAsset {
|
||||
let originalAsset = (asset as! PhotoKitAsset).originalAsset
|
||||
nohanaImagePickerController!.delegate?.nohanaImagePicker?(nohanaImagePickerController!, didDropPhotoKitAsset: originalAsset, pickedAssetsCount: assetsCountAfterDropping)
|
||||
NSNotificationCenter.defaultCenter().postNotification(
|
||||
NSNotification(
|
||||
NotificationCenter.default.post(
|
||||
Notification(
|
||||
name: NotificationInfo.Asset.PhotoKit.didDrop,
|
||||
object: nohanaImagePickerController,
|
||||
userInfo: [
|
||||
|
|
@ -117,9 +107,9 @@ class PickedAssetList: ItemListType {
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isPicked(asset: AssetType) -> Bool {
|
||||
return assetlist.contains{ $0.identifier == asset.identifier }
|
||||
|
||||
func isPicked(_ asset: Asset) -> Bool {
|
||||
return assetlist.contains { $0.identifier == asset.identifier }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,41 +15,51 @@
|
|||
*/
|
||||
|
||||
struct Size {
|
||||
|
||||
|
||||
static var statusBarHeight: CGFloat {
|
||||
get {
|
||||
if UIApplication.sharedApplication().statusBarHidden {
|
||||
return 0
|
||||
}
|
||||
return UIApplication.sharedApplication().statusBarFrame.size.height
|
||||
if UIApplication.shared.isStatusBarHidden {
|
||||
return 0
|
||||
}
|
||||
return UIApplication.shared.statusBarFrame.size.height
|
||||
}
|
||||
|
||||
static func navigationBarHeight(viewController: UIViewController) -> CGFloat {
|
||||
|
||||
static func navigationBarHeight(_ viewController: UIViewController) -> CGFloat {
|
||||
return viewController.navigationController?.navigationBar.frame.size.height ?? CGFloat(0)
|
||||
}
|
||||
|
||||
static func appBarHeight(viewController: UIViewController) -> CGFloat {
|
||||
|
||||
static func appBarHeight(_ viewController: UIViewController) -> CGFloat {
|
||||
return statusBarHeight + navigationBarHeight(viewController)
|
||||
}
|
||||
|
||||
static func toolbarHeight(viewController: UIViewController) -> CGFloat {
|
||||
|
||||
static func toolbarHeight(_ viewController: UIViewController) -> CGFloat {
|
||||
guard let navigationController = viewController.navigationController else {
|
||||
return 0
|
||||
}
|
||||
guard !navigationController.toolbarHidden else {
|
||||
guard !navigationController.isToolbarHidden else {
|
||||
return 0
|
||||
}
|
||||
return navigationController.toolbar.frame.size.height
|
||||
}
|
||||
|
||||
static func screenRectWithoutAppBar(viewController: UIViewController) -> CGRect {
|
||||
let appBarHeight = Size.appBarHeight(viewController)
|
||||
let toolbarHeight = Size.toolbarHeight(viewController)
|
||||
|
||||
static func screenRectWithoutAppBar(_ viewController: UIViewController) -> CGRect {
|
||||
let appBarHeight: CGFloat = {
|
||||
if #available(iOS 11.0, *) {
|
||||
return viewController.view.safeAreaInsets.top
|
||||
} else {
|
||||
return Size.appBarHeight(viewController)
|
||||
}
|
||||
}()
|
||||
let toolbarHeight: CGFloat = {
|
||||
if #available(iOS 11.0, *) {
|
||||
return viewController.view.safeAreaInsets.bottom
|
||||
} else {
|
||||
return Size.toolbarHeight(viewController)
|
||||
}
|
||||
}()
|
||||
return CGRect(
|
||||
x: 0,
|
||||
y: appBarHeight,
|
||||
width: UIScreen.mainScreen().bounds.width,
|
||||
height: UIScreen.mainScreen().bounds.height - appBarHeight - toolbarHeight)
|
||||
width: UIScreen.main.bounds.width,
|
||||
height: UIScreen.main.bounds.height - appBarHeight - toolbarHeight)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,16 +17,17 @@
|
|||
import UIKit
|
||||
|
||||
class SwipeInteractionController: UIPercentDrivenInteractiveTransition {
|
||||
|
||||
|
||||
var viewController: UIViewController?
|
||||
|
||||
func attachToViewController(viewController: UIViewController) {
|
||||
guard viewController.navigationController?.viewControllers.count > 1 else {
|
||||
|
||||
func attachToViewController(_ viewController: UIViewController) {
|
||||
let count: Int? = viewController.navigationController?.viewControllers.count
|
||||
guard count != nil && count! > 1 else {
|
||||
return
|
||||
}
|
||||
let target = viewController.navigationController?.valueForKey("_cachedInteractionController")
|
||||
let gesture = UIScreenEdgePanGestureRecognizer(target: target, action: Selector("handleNavigationTransition:"))
|
||||
gesture.edges = .Left
|
||||
let target = viewController.navigationController?.value(forKey: "_cachedInteractionController")
|
||||
let gesture = UIScreenEdgePanGestureRecognizer(target: target, action: Selector(("handleNavigationTransition:")))
|
||||
gesture.edges = .left
|
||||
viewController.view.addGestureRecognizer(gesture)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,11 +14,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
public struct ColorConfig {
|
||||
public static var backgroundColor = UIColor.whiteColor()
|
||||
public static var emptyIndicator = UIColor(red: 0x88/0xff, green: 0x88/0xff, blue: 0x88/0xff, alpha: 1)
|
||||
|
||||
public struct AlbumList {
|
||||
public static var momentCellSeparator = UIColor(red: 0xbb/0xff, green: 0xbb/0xff, blue: 0xbb/0xff, alpha: 1)
|
||||
}
|
||||
}
|
||||
"albumlist.title" = "Fotos";
|
||||
"albumlist.empty.message" = "Keine Fotos";
|
||||
"albumlist.empty.description" = "Nimm Fotos mit der Kamera App auf.";
|
||||
"albumlist.moment.title" = "Moment";
|
||||
"toolbar.title.nolimit" = "Ausgewählte Fotos: %ld";
|
||||
"toolbar.title.haslimit" = "Ausgewählte Fotos: %ld / %ld";
|
||||
|
|
@ -14,17 +14,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
struct ImageName {
|
||||
struct AssetCell {
|
||||
struct PickButton {
|
||||
struct SizeM {
|
||||
static let picked = "btn_selected_m"
|
||||
static let dropped = "btn_select_m"
|
||||
}
|
||||
struct SizeL {
|
||||
static let picked = "btn_selected_l"
|
||||
static let dropped = "btn_select_l"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"albumlist.title" = "Фотографии";
|
||||
"albumlist.empty.message" = "Нет фотографий";
|
||||
"albumlist.empty.description" = "Получить фото с камеры";
|
||||
"albumlist.moment.title" = "Моменты";
|
||||
"toolbar.title.nolimit" = "Выбрано: %ld";
|
||||
"toolbar.title.haslimit" = "Выбрано: %ld / %ld";
|
||||
64
README.md
|
|
@ -1,4 +1,4 @@
|
|||
<p align="center"><img src="./Images/logo.png" width="480" height="280" /></p>
|
||||
<p align="center"><img src="./Images/logo.png" width="480" /></p>
|
||||
|
||||
## Description
|
||||
|
||||
|
|
@ -10,33 +10,37 @@ NohanaImagePicker enables your app to pick images from multiple album, and the m
|
|||
|
||||
## Usage
|
||||
|
||||
```
|
||||
```swift
|
||||
import UIKit
|
||||
import Photos
|
||||
import NohanaImagePicker
|
||||
class ViewController: UIViewController, NohanaImagePickerControllerDelegate {
|
||||
class MyViewController: UIViewController {
|
||||
let picker = NohanaImagePickerController()
|
||||
|
||||
override func viewDidAppear(animated: Bool) {
|
||||
super.viewDidAppear(true)
|
||||
let picker = NohanaImagePickerController()
|
||||
picker.delegate = self
|
||||
presentViewController(picker, animated: true, completion: nil)
|
||||
# override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
self.picker.delegate = self
|
||||
present(self.picker, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
func nohanaImagePickerDidCancel(picker: NohanaImagePickerController) {
|
||||
extension MyViewController: NohanaImagePickerControllerDelegate {
|
||||
|
||||
func nohanaImagePickerDidCancel(_ picker: NohanaImagePickerController) {
|
||||
print("🐷Canceled🙅")
|
||||
picker.dismissViewControllerAnimated(true, completion: nil)
|
||||
picker.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
func nohanaImagePicker(picker: NohanaImagePickerController, didFinishPickingPhotoKitAssets pickedAssts :[PHAsset]) {
|
||||
func nohanaImagePicker(_ picker: NohanaImagePickerController, didFinishPickingPhotoKitAssets pickedAssts :[PHAsset]) {
|
||||
print("🐷Completed🙆\n\tpickedAssets = \(pickedAssts)")
|
||||
picker.dismissViewControllerAnimated(true, completion: nil)
|
||||
picker.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### Customize
|
||||
|
||||
```
|
||||
```swift
|
||||
let picker = NohanaImagePickerController()
|
||||
|
||||
// Set the maximum number of selectable images
|
||||
|
|
@ -56,41 +60,33 @@ picker.shouldShowMoment = shouldShowEmptyAlbum = true
|
|||
picker.shouldShowEmptyAlbum = true
|
||||
|
||||
// Disable to pick asset
|
||||
picker.canPickAsset = { (asset:AssetType) -> Bool in
|
||||
picker.canPickAsset = { (asset:Asset) -> Bool in
|
||||
return false
|
||||
}
|
||||
|
||||
// Color
|
||||
ColorConfig.backgroundColor = UIColor.redColor()
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- Swift2.2
|
||||
- iOS8.0 later
|
||||
- Swift 2.2 later
|
||||
- iOS 8.0 later
|
||||
|
||||
## Installation
|
||||
|
||||
### Carthage (preferable)
|
||||
### Carthage
|
||||
|
||||
Use [Carthage](https://github.com/Carthage/Carthage).
|
||||
|
||||
- Add `github "nohana/NohanaImagePicker"` to your Cartfile.
|
||||
- If you want to use Swift3.0, add `github "nohana/NohanaImagePicker", "0.8.0"` instead.
|
||||
- If you want to use Swift2.3, add `github "nohana/NohanaImagePicker", "0.6.1"` instead.
|
||||
- If you want to use Swift2.2, add `github "nohana/NohanaImagePicker", "0.5.0"` instead.
|
||||
- Run `carthage update`.
|
||||
- Add following lines to your Info.plist:
|
||||
|
||||
### Framework with CocoaPods
|
||||
|
||||
Use [CocoaPods](https://cocoapods.org/).
|
||||
|
||||
- Add the followings to your Podfile:
|
||||
|
||||
```ruby
|
||||
use_frameworks!
|
||||
pod "NohanaImagePicker"
|
||||
```
|
||||
|
||||
- Run `pod install`.
|
||||
|
||||
```
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>To pick some photos.</string>
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
|||