Compare commits

...

90 Commits

Author SHA1 Message Date
DashaGitHub 52716045fc Update podspec 2019-08-29 18:17:41 +03:00
DashaGitHub 2bcf6d33df Some refactoring 2019-08-29 17:09:13 +03:00
DashaGitHub c19996eddb Added podspec 2019-08-29 17:01:32 +03:00
Kazushi Hara 42e4b4fcf3
Merge pull request #109 from nohana/Swift4.2
Swift4.2
2018-10-14 22:42:54 +09:00
izumi 9362d7ebd1 fix swift version. 2018-10-11 10:31:47 +09:00
izumi 324f4bf207 fix warning. 2018-10-11 10:14:45 +09:00
izumi f39a38a615 update project settings. 2018-10-11 10:12:35 +09:00
izumi 5c7102fad6 Swift4.2 2018-10-05 18:21:50 +09:00
Kazushi Hara f44c660e17
Merge pull request #102 from Gapless-PDLB/german-localisation
Add german localisation
2018-04-13 17:07:04 +09:00
Piet Brauer f86c28822b Add german localisation 2018-04-10 14:54:30 +02:00
Kazushi Hara 51e3c6c870
Merge pull request #99 from nohana/goodbye-pods
good bye pods
2017-12-16 19:11:09 +09:00
haranicle 78a1861f04 good bye pods 2017-12-16 19:10:19 +09:00
Kazushi Hara 7160ddb436
Merge pull request #98 from nohana/fix/readme
fix readme
2017-12-16 19:02:40 +09:00
haranicle d28c68a2c2 fix readme 2017-12-16 19:01:26 +09:00
Kazushi Hara 4334d458eb
Merge pull request #97 from nohana/iphone-x
iPhone X
2017-12-16 16:29:52 +09:00
haranicle 60216c5f90 iPhone X 2017-12-16 16:27:54 +09:00
Kazushi Hara 27997da165 Merge pull request #93 from nohana/fix/swift-version
fix swift version 🙏
2017-10-05 21:43:39 +09:00
haranicle d17ebd4820 fix swift version 🙏 2017-10-05 21:42:43 +09:00
Kazushi Hara ac6edd1e3b Merge pull request #92 from nohana/Xcode9
Xcode9/Swift4
2017-10-05 00:05:06 +09:00
haranicle e067d8c68f README 2017-10-05 00:03:18 +09:00
haranicle 2476d779d4 update podspec 2017-10-04 23:44:20 +09:00
haranicle 973f672b12 fix collection view cell size 2017-10-04 23:24:17 +09:00
haranicle 555a19bcc9 fix demo code 2017-10-04 22:12:02 +09:00
haranicle 0768a23570 dot swift version 2017-10-04 22:09:11 +09:00
haranicle a31ead43ab Swift3 @objc 2017-10-02 23:20:40 +09:00
haranicle 54042e744b swiftlint autocorrect 2017-10-02 23:16:37 +09:00
haranicle 338efc533f fix @objc position 2017-10-02 23:15:58 +09:00
haranicle 688ced9981 Swift4 auto convert 2017-10-02 23:08:23 +09:00
haranicle df819fffb9 update build settings 2017-10-02 23:00:20 +09:00
Kazushi Hara 753332e8ff Merge pull request #90 from nohana/release/0.8.1
Release/0.8.1
2017-10-02 21:47:37 +09:00
Kazushi Hara 8eb6575aaf Merge pull request #84 from nohana/swiftlint
swiftlint autocorrect
2017-07-01 15:07:06 +09:00
haranicle dac1bba0cb swiftlint autocorrect 2017-07-01 15:02:21 +09:00
Kazushi Hara c6a501b4cb Merge pull request #83 from nohana/fix/readme-logo
fix readme logo image
2017-06-19 22:06:51 +09:00
haranicle 98a17c6e2b fix readme logo image 2017-06-19 22:06:09 +09:00
Kazushi Hara cf3868fcaf Merge pull request #80 from nohana/release/0.8.0
Release/0.8.0
2017-06-17 22:39:43 +09:00
haranicle 919d6d6873 fix README and podspec 2017-06-17 22:37:16 +09:00
Kazushi Hara 357443a6b7 Merge pull request #73 from nohana/development/0.7.2
Development/0.8.0
2017-06-17 22:13:12 +09:00
Kazushi Hara 8846e8c28d Merge pull request #79 from nohana/feature/config-for-custom-strings
config color, image, strings
2017-06-17 22:11:18 +09:00
haranicle 4f31eaafc7 fix demo 2017-06-17 22:09:38 +09:00
haranicle d1d65e9cf1 configure color 2017-06-17 21:52:54 +09:00
haranicle 9b66207137 configure strings 2017-06-17 21:25:23 +09:00
Kazushi Hara 2698510de5 Merge pull request #76 from nohana/fix/label-constraints
fix label constraints
2017-05-20 22:00:17 +09:00
haranicle dd9017ec9e fix label constraints 2017-05-20 21:56:45 +09:00
Kazushi Hara 677eb1a51d Merge pull request #74 from nohana/new-config
new config
2017-05-16 12:32:32 +09:00
haranicle 97f6814c1d fix 2017-05-12 03:23:57 +09:00
haranicle e1fa97ea2d new config 2017-05-12 03:17:12 +09:00
KazukiTanaka 5b4c6b5c3a cocoa pods 対応 2017-05-11 11:36:32 +09:00
KazukiTanaka d822cdf449 change README 2017-05-09 16:56:47 +09:00
KazukiTanaka b0fdba4fd2 fix Localization #71 2017-05-09 16:30:53 +09:00
KazukiTanaka c0c34eae5d public var assetBundle 2017-05-09 16:27:35 +09:00
KazukiTanaka 4536b5a2d9 change README 2017-05-02 17:17:40 +09:00
Kazushi Hara 0e98d5acfb Merge pull request #68 from nohana/fix-filename
fix filename
2016-11-26 15:36:17 +09:00
haranicle 790b948574 fix filename 2016-11-26 15:34:15 +09:00
Kazushi Hara 91249c4459 Merge pull request #66 from BasThomas/patch-1
Add syntax highlighting to README
2016-11-17 19:16:47 +09:00
Bas Broek 7250e1d962 Update README.md 2016-11-17 11:15:35 +01:00
Bas Broek 0130329564 Add syntax highlighting to README 2016-11-17 11:14:47 +01:00
Kazushi Hara ef9b35d64a Merge pull request #63 from nohana/release/0.7.1
Release/0.7.1
2016-10-02 23:40:50 +09:00
Kazushi Hara 22971c96a6 Merge pull request #62 from nohana/update=podspec
update podspec
2016-10-02 23:30:30 +09:00
haranicle 38dfaa16c0 update podspec 2016-10-02 23:29:37 +09:00
Kazushi Hara eafd52c8ac Merge pull request #61 from nohana/fix-readme-for-0.7.1
fix readme
2016-10-02 23:27:52 +09:00
haranicle d58a9bd994 fix readme 2016-10-02 23:26:34 +09:00
Kazushi Hara 7d9503ce0c Merge pull request #60 from nohana/fix-readme-for-0.7.1
fix rename
2016-10-02 23:24:09 +09:00
haranicle f5fcd704bb fix rename 2016-10-02 23:23:12 +09:00
Kazushi Hara 9008253a55 Merge pull request #59 from nohana/rename-protocols
Rename protocols
2016-10-02 23:21:00 +09:00
haranicle 01bdb7fcca rename AssetType to Asset 2016-10-02 23:13:57 +09:00
haranicle 2454d1057b rename ItemListType to ItemList 2016-10-02 23:12:51 +09:00
Kazushi Hara c16999c312 Merge pull request #52 from nohana/disable-legacy-swift-version
disable legacy swift version
2016-09-23 17:35:19 +09:00
haranicle 840e133ae2 disable legacy swift version 2016-09-23 17:34:29 +09:00
Kazushi Hara b939ab137c Merge pull request #51 from nohana/add-swift-version-file
add .swift-version file
2016-09-23 17:27:59 +09:00
haranicle d508cf3461 add .swift-version file 2016-09-23 17:27:07 +09:00
Kazushi Hara 860285d6d9 Merge pull request #50 from nohana/release/0.7.0
Release/0.7.0
2016-09-23 17:15:43 +09:00
Kazushi Hara 459e51f56e Merge pull request #49 from nohana/fix-readme-sample-code
fix readme sample cod
2016-09-23 16:51:11 +09:00
haranicle 6d1e4529ef fix readme sample cod 2016-09-23 16:49:50 +09:00
Kazushi Hara 6d091690e5 Merge pull request #47 from nohana/fix-readme-for-0.7.0
fix readme
2016-09-23 16:15:45 +09:00
Kazushi Hara 6820091576 Merge pull request #48 from nohana/fix-podspec-for-0.7.0
fix podspec
2016-09-23 16:14:29 +09:00
haranicle f59be657cd fix podspec 2016-09-23 16:13:54 +09:00
haranicle accfe28f8e fix readme 2016-09-23 16:00:06 +09:00
Kazushi Hara 15a97c706e Merge pull request #42 from nohana/Swift3.0
Swift3.0
2016-09-23 15:36:43 +09:00
Kazushi Hara f4d9d0e1f5 Merge pull request #46 from nohana/replace-NSIndexPath
Replace ns index path
2016-09-23 15:31:28 +09:00
haranicle 9cfe813b85 replace NSIndexPath 2016-09-23 15:30:20 +09:00
Kazushi Hara d4062ef8c8 Merge pull request #45 from nohana/convert-NSIndexPath-to-IndexPath
replace NSIndexPath to IndexPath
2016-09-23 15:22:44 +09:00
haranicle de500efa96 replace NSIndexPath to IndexPath 2016-09-23 15:21:57 +09:00
Kazushi Hara cf077f0d56 Merge pull request #41 from nohana/add-photo-library-usage-description
add "Privacy - Photo Library Usage Description" value to plist
2016-09-23 12:28:12 +09:00
haranicle 5bff5ee1fb add "Privacy - Photo Library Usage Description" value to plist 2016-09-23 12:26:17 +09:00
Kazushi Hara ddbb570c7b Merge pull request #40 from nohana/swift3.0-compatible
Swift3.0 compatible
2016-09-23 12:00:51 +09:00
haranicle b2c890658f fix project settings 2016-09-23 11:59:48 +09:00
haranicle 512b5202be remove "get {}" 2016-09-21 19:07:11 +09:00
haranicle 25a6f81aa3 rename pick or drop functions 2016-09-21 19:00:35 +09:00
haranicle 567ee0d93d buildable 2016-09-21 18:53:27 +09:00
haranicle 4381c4e614 auto convert 2016-09-21 17:08:35 +09:00
61 changed files with 1073 additions and 930 deletions

1
.swift-version Normal file
View File

@ -0,0 +1 @@
4.2

47
.swiftlint.yml Normal file
View File

@ -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

View File

@ -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:.
}
}

View File

@ -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" : {

View File

@ -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"/>

View File

@ -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)")
}
}

View File

@ -43,5 +43,7 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>NSPhotoLibraryUsageDescription</key>
<string>To pick some photos.</string>
</dict>
</plist>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -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

View File

@ -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;
};

View File

@ -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>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0720"
LastUpgradeVersion = "1000"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -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()
}
}
}
}

View File

@ -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")
}
}
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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) )
}
}
}

View File

@ -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
}
}
}

127
NohanaImagePicker/AssetDetailListViewController.swift Normal file → Executable file
View File

@ -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
}
}
}

View File

@ -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 )
}
}

View File

@ -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)
}
}
}
}

View File

@ -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()
}
}
}
}

50
NohanaImagePicker/ExpandingAnimationController.swift Normal file → Executable file
View File

@ -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)
}
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -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>?
}
}

View File

@ -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))
}

View File

@ -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)
}
}
}

View File

@ -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>

View File

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -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"
}
],

View File

@ -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"
}
],

View File

@ -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()
}
}

View File

@ -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"
}
}
}
}

View File

@ -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
}
}

View File

@ -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>?))
}
}
}

View File

@ -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
}
}

View File

@ -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 }
}
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}
}

View File

@ -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";

View File

@ -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";

View File

@ -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