Skip to content

Commit dfa3336

Browse files
committed
Merge branch 'develop'
2 parents 8174281 + f860536 commit dfa3336

14 files changed

+432
-115
lines changed

ExampleApp/ViewController.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ let sectionsData: [(String?, String?)] = [
5252
("Assets Source", nil),
5353
("Asset Items in a row", nil),
5454
("Capture mode", nil),
55-
("Save Assets", "Assets will be saved to Photo Library")
55+
("Save Assets", "Assets will be saved to Photo Library. This applies to photos only. Live photos and videos are always saved.")
5656
]
5757

5858
///
@@ -227,7 +227,7 @@ class ViewController: UITableViewController {
227227
}
228228

229229
// save capture assets to photo library?
230-
imagePicker.captureSettings.savesCapturedAssetToPhotoLibrary = savesCapturedAssets
230+
imagePicker.captureSettings.savesCapturedPhotosToPhotoLibrary = savesCapturedAssets
231231

232232
// presentation
233233
// before we present VC we can ask for authorization to photo library,

ImagePicker.xcodeproj/project.pbxproj

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,15 @@
3333
425777531F98D110000824F0 /* ActionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 425777511F98D10F000824F0 /* ActionCell.swift */; };
3434
425777541F98D119000824F0 /* ActionCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 425777521F98D10F000824F0 /* ActionCell.xib */; };
3535
425BEC851F7D351A0091D008 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 425BEC841F7D351A0091D008 /* Assets.xcassets */; };
36+
427271701FA1D304008AC2B4 /* CarvedLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4272716F1FA1D304008AC2B4 /* CarvedLabel.swift */; };
3637
427925F31F9636D700B6D55F /* StationaryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 427925F21F9636D700B6D55F /* StationaryButton.swift */; };
3738
427925F51F96381400B6D55F /* ShutterButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 427925F41F96381400B6D55F /* ShutterButton.swift */; };
3839
427925F71F96388000B6D55F /* RecordButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 427925F61F96388000B6D55F /* RecordButton.swift */; };
3940
427925FD1F963A8D00B6D55F /* VideoCameraCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 427925FB1F963A8C00B6D55F /* VideoCameraCell.swift */; };
4041
427925FE1F963B2800B6D55F /* VideoCameraCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 427925FC1F963A8C00B6D55F /* VideoCameraCell.xib */; };
4142
427926011F963E9C00B6D55F /* LivePhotoCameraCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 427925FF1F963E9B00B6D55F /* LivePhotoCameraCell.swift */; };
4243
427926021F96407900B6D55F /* LivePhotoCameraCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 427926001F963E9C00B6D55F /* LivePhotoCameraCell.xib */; };
44+
42990DBF1FA07AF7001658C4 /* RecordDurationLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42990DBE1FA07AF7001658C4 /* RecordDurationLabel.swift */; };
4345
429BFDAA1F68161D00029440 /* ImagePickerAssetModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 429BFDA91F68161D00029440 /* ImagePickerAssetModel.swift */; };
4446
42A037E01F66C9E700534350 /* CustomVideoCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 42A037DF1F66C9E700534350 /* CustomVideoCell.xib */; };
4547
42D097991F7BD6E200A66E33 /* UIImageEffects.m in Sources */ = {isa = PBXBuildFile; fileRef = 42D097971F7BD6E100A66E33 /* UIImageEffects.m */; };
@@ -110,13 +112,15 @@
110112
425777511F98D10F000824F0 /* ActionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionCell.swift; sourceTree = "<group>"; };
111113
425777521F98D10F000824F0 /* ActionCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ActionCell.xib; sourceTree = "<group>"; };
112114
425BEC841F7D351A0091D008 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
115+
4272716F1FA1D304008AC2B4 /* CarvedLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarvedLabel.swift; sourceTree = "<group>"; };
113116
427925F21F9636D700B6D55F /* StationaryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StationaryButton.swift; sourceTree = "<group>"; };
114117
427925F41F96381400B6D55F /* ShutterButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShutterButton.swift; sourceTree = "<group>"; };
115118
427925F61F96388000B6D55F /* RecordButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordButton.swift; sourceTree = "<group>"; };
116119
427925FB1F963A8C00B6D55F /* VideoCameraCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoCameraCell.swift; sourceTree = "<group>"; };
117120
427925FC1F963A8C00B6D55F /* VideoCameraCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = VideoCameraCell.xib; sourceTree = "<group>"; };
118121
427925FF1F963E9B00B6D55F /* LivePhotoCameraCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LivePhotoCameraCell.swift; sourceTree = "<group>"; };
119122
427926001F963E9C00B6D55F /* LivePhotoCameraCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LivePhotoCameraCell.xib; sourceTree = "<group>"; };
123+
42990DBE1FA07AF7001658C4 /* RecordDurationLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordDurationLabel.swift; sourceTree = "<group>"; };
120124
429BFDA91F68161D00029440 /* ImagePickerAssetModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePickerAssetModel.swift; sourceTree = "<group>"; };
121125
42A037DF1F66C9E700534350 /* CustomVideoCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CustomVideoCell.xib; sourceTree = "<group>"; };
122126
42D097971F7BD6E100A66E33 /* UIImageEffects.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UIImageEffects.m; sourceTree = "<group>"; };
@@ -190,23 +194,14 @@
190194
420C24181F5D82F9008935D4 /* ImagePicker.h */,
191195
42D7036F1F7909100057D557 /* Public */,
192196
42D703701F790A3F0057D557 /* Media */,
197+
42990DBD1FA07A6C001658C4 /* Views */,
193198
420C24351F5ED4AA008935D4 /* ImagePickerLayout.swift */,
194199
429BFDA91F68161D00029440 /* ImagePickerAssetModel.swift */,
195200
420C24271F5D925A008935D4 /* ImagePickerDataSource.swift */,
196201
420C24331F5DA022008935D4 /* ImagePickerDelegate.swift */,
197202
420C243E1F5EEA19008935D4 /* LayoutModel.swift */,
198203
4214426E1F604498006BA45A /* ImagePickerSelectionPolicy.swift */,
199204
42EDD4151F712B2A00EAD2F5 /* Miscellaneous.swift */,
200-
42D0979B1F7BF6B300A66E33 /* AssetCell.swift */,
201-
427925F21F9636D700B6D55F /* StationaryButton.swift */,
202-
427925F41F96381400B6D55F /* ShutterButton.swift */,
203-
427925F61F96388000B6D55F /* RecordButton.swift */,
204-
427925FB1F963A8C00B6D55F /* VideoCameraCell.swift */,
205-
427925FC1F963A8C00B6D55F /* VideoCameraCell.xib */,
206-
427925FF1F963E9B00B6D55F /* LivePhotoCameraCell.swift */,
207-
427926001F963E9C00B6D55F /* LivePhotoCameraCell.xib */,
208-
425777511F98D10F000824F0 /* ActionCell.swift */,
209-
425777521F98D10F000824F0 /* ActionCell.xib */,
210205
425BEC841F7D351A0091D008 /* Assets.xcassets */,
211206
42D097981F7BD6E100A66E33 /* UIImageEffects.h */,
212207
42D097971F7BD6E100A66E33 /* UIImageEffects.m */,
@@ -228,6 +223,25 @@
228223
path = "Custom Views";
229224
sourceTree = "<group>";
230225
};
226+
42990DBD1FA07A6C001658C4 /* Views */ = {
227+
isa = PBXGroup;
228+
children = (
229+
425777511F98D10F000824F0 /* ActionCell.swift */,
230+
425777521F98D10F000824F0 /* ActionCell.xib */,
231+
42D0979B1F7BF6B300A66E33 /* AssetCell.swift */,
232+
427925FF1F963E9B00B6D55F /* LivePhotoCameraCell.swift */,
233+
427926001F963E9C00B6D55F /* LivePhotoCameraCell.xib */,
234+
427925F61F96388000B6D55F /* RecordButton.swift */,
235+
42990DBE1FA07AF7001658C4 /* RecordDurationLabel.swift */,
236+
427925F41F96381400B6D55F /* ShutterButton.swift */,
237+
427925F21F9636D700B6D55F /* StationaryButton.swift */,
238+
427925FB1F963A8C00B6D55F /* VideoCameraCell.swift */,
239+
427925FC1F963A8C00B6D55F /* VideoCameraCell.xib */,
240+
4272716F1FA1D304008AC2B4 /* CarvedLabel.swift */,
241+
);
242+
name = Views;
243+
sourceTree = "<group>";
244+
};
231245
42D7036F1F7909100057D557 /* Public */ = {
232246
isa = PBXGroup;
233247
children = (
@@ -399,6 +413,7 @@
399413
42E736521F8510B70060E24D /* VideoCaptureDelegate.swift in Sources */,
400414
429BFDAA1F68161D00029440 /* ImagePickerAssetModel.swift in Sources */,
401415
42D7036B1F7908B10057D557 /* CaptureSettings.swift in Sources */,
416+
42990DBF1FA07AF7001658C4 /* RecordDurationLabel.swift in Sources */,
402417
42EDD41A1F716F6300EAD2F5 /* PhotoCaptureDelegate.swift in Sources */,
403418
420C24341F5DA022008935D4 /* ImagePickerDelegate.swift in Sources */,
404419
420C24281F5D925A008935D4 /* ImagePickerDataSource.swift in Sources */,
@@ -413,6 +428,7 @@
413428
42EDD4161F712B2A00EAD2F5 /* Miscellaneous.swift in Sources */,
414429
427926011F963E9C00B6D55F /* LivePhotoCameraCell.swift in Sources */,
415430
42311FFC1F73DBBF00B1AEB4 /* VideoOuptutSampleBufferDelegate.swift in Sources */,
431+
427271701FA1D304008AC2B4 /* CarvedLabel.swift in Sources */,
416432
42F7D8011F7A5B72009D378A /* Appearance.swift in Sources */,
417433
420C24261F5D8393008935D4 /* ImagePickerController.swift in Sources */,
418434
42EDD4051F7125C700EAD2F5 /* CaptureSession.swift in Sources */,

ImagePicker/CaptureSession.swift

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,6 @@ final class CaptureSession : NSObject {
106106

107107
var presetConfiguration: SessionPresetConfiguration = .photos
108108

109-
///
110-
/// Save assets to library or not. Appropriate delegate is called in all cases.
111-
///
112-
var saveCapturedAssetsToPhotoLibrary = false
113-
114109
///
115110
/// Set this method to orientation that mathches UI orientation before `prepare()`
116111
/// method is called. If you need to update orientation when session is running,
@@ -699,7 +694,7 @@ extension CaptureSession {
699694

700695
extension CaptureSession {
701696

702-
func capturePhoto(livePhotoMode: LivePhotoMode) {
697+
func capturePhoto(livePhotoMode: LivePhotoMode, saveToPhotoLibrary: Bool) {
703698
/*
704699
Retrieve the video preview layer's video orientation on the main queue before
705700
entering the session queue. We do this to ensure UI elements are accessed on
@@ -795,7 +790,7 @@ extension CaptureSession {
795790
}
796791
})
797792

798-
photoCaptureDelegate.savesPhotoToLibrary = self.saveCapturedAssetsToPhotoLibrary
793+
photoCaptureDelegate.savesPhotoToLibrary = saveToPhotoLibrary
799794

800795
/*
801796
The Photo Output keeps a weak reference to the photo capture delegate so
@@ -811,7 +806,7 @@ extension CaptureSession {
811806

812807
extension CaptureSession {
813808

814-
func startVideoRecording() {
809+
func startVideoRecording(saveToPhotoLibrary: Bool) {
815810

816811
guard let movieFileOutput = self.videoFileOutput else {
817812
return log("capture session: trying to record a video but no movie file output is set")
@@ -884,7 +879,7 @@ extension CaptureSession {
884879
}
885880
}
886881
})
887-
recordingDelegate.savesPhotoToLibrary = strongSelf.saveCapturedAssetsToPhotoLibrary
882+
recordingDelegate.savesVideoToLibrary = saveToPhotoLibrary
888883

889884
// start recording
890885
movieFileOutput.startRecording(to: outputURL, recordingDelegate: recordingDelegate)

ImagePicker/CaptureSettings.swift

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,23 @@ public struct CaptureSettings {
3636
public var cameraMode: CameraMode
3737

3838
///
39-
/// Return true if captured assets will be saved to photo library. Image picker
40-
/// will prompt user with request for permisssions when needed. Default value is false.
39+
/// Return true if captured photos will be saved to photo library. Image picker
40+
/// will prompt user with request for permisssions when needed. Default value is false
41+
/// for photos. Live photos and videos are always true.
4142
///
42-
public var savesCapturedAssetToPhotoLibrary: Bool
43+
/// - note: please note, that at current implementation this applies to photos only. For
44+
/// live photos and videos this is always true.
45+
///
46+
public var savesCapturedPhotosToPhotoLibrary: Bool
47+
48+
let savesCapturedLivePhotosToPhotoLibrary: Bool = true
49+
let savesCapturedVideosToPhotoLibrary: Bool = true
4350

4451
/// Default configuration
4552
public static var `default`: CaptureSettings {
4653
return CaptureSettings(
4754
cameraMode: .photo,
48-
savesCapturedAssetToPhotoLibrary: false
55+
savesCapturedPhotosToPhotoLibrary: false
4956
)
5057
}
5158
}

ImagePicker/CarvedLabel.swift

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
//
2+
// CarvedLabel.swift
3+
// ImagePicker
4+
//
5+
// Created by Peter Stajger on 26/10/2017.
6+
// Copyright © 2017 Inloop. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
fileprivate typealias TextAttributes = [NSAttributedStringKey: Any]
12+
13+
///
14+
/// A label whose transparent text is carved into solid color.
15+
///
16+
/// - please note that text is always aligned to center
17+
///
18+
@IBDesignable
19+
final class CarvedLabel : UIView {
20+
21+
@IBInspectable var text: String? {
22+
didSet {
23+
invalidateIntrinsicContentSize()
24+
setNeedsDisplay()
25+
}
26+
}
27+
28+
var font: UIFont? {
29+
didSet {
30+
invalidateIntrinsicContentSize()
31+
setNeedsDisplay()
32+
}
33+
}
34+
35+
@IBInspectable var cornerRadius: CGFloat = 0 {
36+
didSet { setNeedsDisplay() }
37+
}
38+
39+
@IBInspectable var verticalInset: CGFloat = 0 {
40+
didSet {
41+
invalidateIntrinsicContentSize()
42+
setNeedsDisplay()
43+
}
44+
}
45+
46+
@IBInspectable var horizontalInset: CGFloat = 0 {
47+
didSet {
48+
invalidateIntrinsicContentSize()
49+
setNeedsDisplay()
50+
}
51+
52+
}
53+
54+
override init(frame: CGRect) {
55+
super.init(frame: frame)
56+
_ = backgroundColor
57+
isOpaque = false
58+
}
59+
60+
required init?(coder aDecoder: NSCoder) {
61+
super.init(coder: aDecoder)
62+
_ = backgroundColor
63+
isOpaque = false
64+
}
65+
66+
override var backgroundColor: UIColor? {
67+
get { return UIColor.clear }
68+
set { super.backgroundColor = UIColor.clear }
69+
}
70+
71+
fileprivate var textAttributes: TextAttributes {
72+
let activeFont = font ?? UIFont.systemFont(ofSize: 12, weight: .regular)
73+
return [
74+
NSAttributedStringKey.font: activeFont
75+
]
76+
}
77+
78+
fileprivate var attributedString: NSAttributedString {
79+
return NSAttributedString(string: text ?? "", attributes: textAttributes)
80+
}
81+
82+
override func draw(_ rect: CGRect) {
83+
let color = tintColor!
84+
color.setFill()
85+
86+
let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius)
87+
path.fill()
88+
89+
guard let context = UIGraphicsGetCurrentContext(), (text?.characters.count ?? 0) > 0 else {
90+
return
91+
}
92+
93+
let attributedString = self.attributedString
94+
let stringSize = attributedString.size()
95+
96+
let xOrigin: CGFloat = max(horizontalInset, (rect.width - stringSize.width)/2)
97+
let yOrigin: CGFloat = max(verticalInset, (rect.height - stringSize.height)/2)
98+
99+
context.saveGState()
100+
context.setBlendMode(.destinationOut)
101+
attributedString.draw(at: CGPoint(x: xOrigin, y: yOrigin))
102+
context.restoreGState()
103+
}
104+
105+
override func sizeThatFits(_ size: CGSize) -> CGSize {
106+
let stringSize = attributedString.size()
107+
return CGSize(width: stringSize.width + horizontalInset*2, height: stringSize.height + verticalInset*2)
108+
}
109+
110+
override var intrinsicContentSize: CGSize {
111+
return sizeThatFits(.zero)
112+
}
113+
}

ImagePicker/ImagePickerController.swift

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ public protocol ImagePickerControllerDelegate : class {
3535
///
3636
func imagePicker(controller: ImagePickerController, didTake image: UIImage)
3737

38+
///
39+
/// Called when user takes new photo.
40+
///
41+
//TODO:
42+
//func imagePicker(controller: ImagePickerController, didCaptureVideo url: UIImage)
43+
//func imagePicker(controller: ImagePickerController, didTake livePhoto: UIImage, videoUrl: UIImage)
44+
3845
///
3946
/// Called right before an action item collection view cell is displayed. Use this method
4047
/// to configure your cell.
@@ -303,7 +310,7 @@ open class ImagePickerController : UIViewController {
303310
collectionViewDataSource.cellRegistrator = cellRegistrator
304311
collectionViewDelegate.delegate = self
305312
collectionViewDelegate.layout = ImagePickerLayout(configuration: layoutConfiguration)
306-
313+
307314
//register for photo library updates - this is needed when changing permissions to photo library
308315
//TODO: this is expensive (loading library for the first time)
309316
PHPhotoLibrary.shared().register(self)
@@ -316,7 +323,6 @@ open class ImagePickerController : UIViewController {
316323
let session = CaptureSession()
317324
captureSession = session
318325
session.presetConfiguration = captureSettings.cameraMode.captureSessionPresetConfiguration
319-
session.saveCapturedAssetsToPhotoLibrary = captureSettings.savesCapturedAssetToPhotoLibrary
320326
session.videoOrientation = UIApplication.shared.statusBarOrientation.captureVideoOrientation
321327
session.delegate = self
322328
session.videoRecordingDelegate = self
@@ -678,15 +684,15 @@ extension ImagePickerController : CaptureSessionVideoRecordingDelegate {
678684
extension ImagePickerController: CameraCollectionViewCellDelegate {
679685

680686
func takePicture() {
681-
captureSession?.capturePhoto(livePhotoMode: .off)
687+
captureSession?.capturePhoto(livePhotoMode: .off, saveToPhotoLibrary: captureSettings.savesCapturedPhotosToPhotoLibrary)
682688
}
683689

684690
func takeLivePhoto() {
685-
captureSession?.capturePhoto(livePhotoMode: .on)
691+
captureSession?.capturePhoto(livePhotoMode: .on, saveToPhotoLibrary: captureSettings.savesCapturedLivePhotosToPhotoLibrary)
686692
}
687693

688694
func startVideoRecording() {
689-
captureSession?.startVideoRecording()
695+
captureSession?.startVideoRecording(saveToPhotoLibrary: captureSettings.savesCapturedVideosToPhotoLibrary)
690696
}
691697

692698
func stopVideoRecording() {

0 commit comments

Comments
 (0)