From 8fa64742b40feef7cf8080f77a6a96de026cc8f0 Mon Sep 17 00:00:00 2001 From: Shai Mishali Date: Mon, 24 Apr 2017 21:46:13 +0300 Subject: [PATCH 1/5] Update RxMediaPicker to Swift 3.1 and cleaned up --- RxMediaPicker/RxMediaPicker.swift | 100 ++++++++++++++++-------------- 1 file changed, 53 insertions(+), 47 deletions(-) diff --git a/RxMediaPicker/RxMediaPicker.swift b/RxMediaPicker/RxMediaPicker.swift index f6d3ecf..1fd4a24 100644 --- a/RxMediaPicker/RxMediaPicker.swift +++ b/RxMediaPicker/RxMediaPicker.swift @@ -51,7 +51,7 @@ public enum RxMediaPickerError: Error { picker.cameraDevice = device } - self.delegate?.present(picker: picker) + self.presentPicker(picker) return Disposables.create() } @@ -59,7 +59,7 @@ public enum RxMediaPickerError: Error { open func selectVideo(source: UIImagePickerControllerSourceType = .photoLibrary, maximumDuration: TimeInterval = 600, editable: Bool = false) -> Observable { - return Observable.create({ observer in + return Observable.create { [unowned self] observer in self.currentAction = RxMediaPickerAction.video(observer: observer, maxDuration: maximumDuration) let picker = UIImagePickerController() @@ -67,16 +67,17 @@ public enum RxMediaPickerError: Error { picker.mediaTypes = [kUTTypeMovie as String] picker.allowsEditing = editable picker.delegate = self + picker.videoMaximumDuration = maximumDuration - self.delegate?.present(picker: picker) + self.presentPicker(picker) return Disposables.create() - }) + } } open func takePhoto(device: UIImagePickerControllerCameraDevice = .rear, flashMode: UIImagePickerControllerCameraFlashMode = .auto, editable: Bool = false) -> Observable<(UIImage, UIImage?)> { - return Observable.create({ observer in + return Observable.create { [unowned self] observer in self.currentAction = RxMediaPickerAction.photo(observer: observer) let picker = UIImagePickerController() @@ -92,15 +93,15 @@ public enum RxMediaPickerError: Error { picker.cameraFlashMode = flashMode } - self.delegate?.present(picker: picker) + self.presentPicker(picker) return Disposables.create() - }) + } } open func selectImage(source: UIImagePickerControllerSourceType = .photoLibrary, editable: Bool = false) -> Observable<(UIImage, UIImage?)> { - return Observable.create { observer in + return Observable.create { [unowned self] observer in self.currentAction = RxMediaPickerAction.photo(observer: observer) let picker = UIImagePickerController() @@ -108,63 +109,62 @@ public enum RxMediaPickerError: Error { picker.allowsEditing = editable picker.delegate = self - self.delegate?.present(picker: picker) + self.presentPicker(picker) return Disposables.create() } } func processPhoto(info: [String : AnyObject], observer: AnyObserver<(UIImage, UIImage?)>) { - if let image = info[UIImagePickerControllerOriginalImage] as? UIImage { - let editedImage: UIImage? = info[UIImagePickerControllerEditedImage] as? UIImage - observer.on(.next(image, editedImage)) - observer.on(.completed) - } else { + guard let image = info[UIImagePickerControllerOriginalImage] as? UIImage, + let editedImage = info[UIImagePickerControllerEditedImage] as? UIImage else { observer.on(.error(RxMediaPickerError.generalError)) + return } + + observer.on(.next(image, editedImage)) + observer.on(.completed) } func processVideo(info: [String : Any], observer: AnyObserver, maxDuration: TimeInterval, picker: UIImagePickerController) { - guard let videoURL = info[UIImagePickerControllerMediaURL] as? URL else { observer.on(.error(RxMediaPickerError.generalError)) dismissPicker(picker) return } + + guard let editedStart = info["_UIImagePickerControllerVideoEditingStart"] as? NSNumber, + let editedEnd = info["_UIImagePickerControllerVideoEditingEnd"] as? NSNumber else { + processVideo(url: videoURL, observer: observer, maxDuration: maxDuration, picker: picker) + return + } + + let start = Int64(editedStart.doubleValue * 1000) + let end = Int64(editedEnd.doubleValue * 1000) + let cachesDirectory = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first! + let editedVideoURL = URL(fileURLWithPath: cachesDirectory).appendingPathComponent("\(UUID().uuidString).mov", isDirectory: false) + let asset = AVURLAsset(url: videoURL) - if let editedStart = info["_UIImagePickerControllerVideoEditingStart"] as? NSNumber, - let editedEnd = info["_UIImagePickerControllerVideoEditingEnd"] as? NSNumber { - - let start = Int64(editedStart.doubleValue * 1000) - let end = Int64(editedEnd.doubleValue * 1000) - let cachesDirectory = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first! - let editedVideoURL = URL(fileURLWithPath: cachesDirectory).appendingPathComponent("\(UUID().uuidString).mov", isDirectory: false) - let asset = AVURLAsset(url: videoURL) - - if let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality) { - exportSession.outputURL = editedVideoURL - exportSession.outputFileType = AVFileTypeQuickTimeMovie - exportSession.timeRange = CMTimeRange(start: CMTime(value: start, timescale: 1000), duration: CMTime(value: end - start, timescale: 1000)) - - exportSession.exportAsynchronously(completionHandler: { - switch exportSession.status { - case .completed: - self.processVideo(url: editedVideoURL, observer: observer, maxDuration: maxDuration, picker: picker) - case .failed: fallthrough - case .cancelled: - observer.on(.error(RxMediaPickerError.generalError)) - self.dismissPicker(picker) - default: break - } - }) + if let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality) { + exportSession.outputURL = editedVideoURL + exportSession.outputFileType = AVFileTypeQuickTimeMovie + exportSession.timeRange = CMTimeRange(start: CMTime(value: start, timescale: 1000), duration: CMTime(value: end - start, timescale: 1000)) + + exportSession.exportAsynchronously(completionHandler: { + switch exportSession.status { + case .completed: + self.processVideo(url: editedVideoURL, observer: observer, maxDuration: maxDuration, picker: picker) + case .failed: fallthrough + case .cancelled: + observer.on(.error(RxMediaPickerError.generalError)) + self.dismissPicker(picker) + default: break } - } else { - processVideo(url: videoURL, observer: observer, maxDuration: maxDuration, picker: picker) + }) } } fileprivate func processVideo(url: URL, observer: AnyObserver, maxDuration: TimeInterval, picker: UIImagePickerController) { - let asset = AVURLAsset(url: url) let duration = CMTimeGetSeconds(asset.duration) @@ -177,15 +177,21 @@ public enum RxMediaPickerError: Error { dismissPicker(picker) } + + fileprivate func presentPicker(_ picker: UIImagePickerController) { + DispatchQueue.main.async { [weak self] in + self?.delegate?.present(picker: picker) + } + } fileprivate func dismissPicker(_ picker: UIImagePickerController) { - delegate?.dismiss(picker: picker) + DispatchQueue.main.async { [weak self] in + self?.delegate?.dismiss(picker: picker) + } } - // UIImagePickerControllerDelegate - + // MARK: UIImagePickerControllerDelegate open func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { - if let action = currentAction { switch action { case .photo(let observer): From 26da1ba633602136a5dbc0730a90aeb2f073bfde Mon Sep 17 00:00:00 2001 From: Shai Mishali Date: Mon, 24 Apr 2017 21:49:09 +0300 Subject: [PATCH 2/5] Update Podspec and Cartfile for RxSwift 3.4.0. --- Cartfile | 2 +- Cartfile.resolved | 2 +- RxMediaPicker.podspec | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cartfile b/Cartfile index 221042f..76a9135 100644 --- a/Cartfile +++ b/Cartfile @@ -1 +1 @@ -github "ReactiveX/RxSwift" ~> 3.0 +github "ReactiveX/RxSwift" ~> 3.4.0 diff --git a/Cartfile.resolved b/Cartfile.resolved index 67b44d7..5c3e9fa 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "ReactiveX/RxSwift" "3.0.0-beta.1" +github "ReactiveX/RxSwift" "3.4.0" diff --git a/RxMediaPicker.podspec b/RxMediaPicker.podspec index b3d138e..df42828 100644 --- a/RxMediaPicker.podspec +++ b/RxMediaPicker.podspec @@ -1,13 +1,13 @@ Pod::Spec.new do |s| s.name = "RxMediaPicker" - s.version = "0.0.1" + s.version = "1.0.0" s.summary = "A reactive wrapper built around UIImagePickerController." - s.homepage = "https://github.com/ruipfcosta/RxMediaPicker" + s.homepage = "https://github.com/RxSwiftCommunity/RxMediaPicker" s.license = { :type => "MIT", :file => "LICENSE" } - s.authors = { "Rui Costa" => "rui.pfcosta@gmail.com" } + s.authors = { "Rui Costa" => "rui.pfcosta@gmail.com", "Shai Mishali" => "freak4pc@gmail.com" } s.platform = :ios, "8.0" - s.source = { :git => 'https://github.com/ruipfcosta/RxMediaPicker.git', :tag => s.version } + s.source = { :git => 'https://github.com/RxSwiftCommunity/RxMediaPicker.git', :tag => s.version } s.source_files = "RxMediaPicker/*.swift" s.requires_arc = true - s.dependency 'RxSwift', '~> 2.0' + s.dependency 'RxSwift', '~> 3.4.0' end From b2aa2ee2d2372ce2aa54bb264d5fdadcc09c6143 Mon Sep 17 00:00:00 2001 From: Shai Mishali Date: Mon, 24 Apr 2017 21:49:54 +0300 Subject: [PATCH 3/5] Fixed up iOS Example & Xcode project --- RxMediaPicker.xcodeproj/project.pbxproj | 18 +++++ iOS Example/Cartfile | 2 +- iOS Example/Cartfile.resolved | 2 +- .../iOS Example.xcodeproj/project.pbxproj | 42 ++++------ iOS Example/iOS Example/AppDelegate.swift | 10 +-- iOS Example/iOS Example/Info.plist | 6 ++ iOS Example/iOS Example/ViewController.swift | 81 ++++++++++--------- 7 files changed, 88 insertions(+), 73 deletions(-) diff --git a/RxMediaPicker.xcodeproj/project.pbxproj b/RxMediaPicker.xcodeproj/project.pbxproj index 09c5edf..8376824 100644 --- a/RxMediaPicker.xcodeproj/project.pbxproj +++ b/RxMediaPicker.xcodeproj/project.pbxproj @@ -81,6 +81,7 @@ B388AAD81C6561B700726BCA /* Frameworks */, B388AAD91C6561B700726BCA /* Headers */, B388AADA1C6561B700726BCA /* Resources */, + 7810985A1EAE774900FC4CF2 /* ShellScript */, ); buildRules = ( ); @@ -133,6 +134,23 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 7810985A1EAE774900FC4CF2 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/Carthage/Build/iOS/RxSwift.framework", + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ B388AAD71C6561B700726BCA /* Sources */ = { isa = PBXSourcesBuildPhase; diff --git a/iOS Example/Cartfile b/iOS Example/Cartfile index b4dbcc0..76a9135 100644 --- a/iOS Example/Cartfile +++ b/iOS Example/Cartfile @@ -1 +1 @@ -github "ReactiveX/RxSwift" ~> 2.0 +github "ReactiveX/RxSwift" ~> 3.4.0 diff --git a/iOS Example/Cartfile.resolved b/iOS Example/Cartfile.resolved index 6d5907a..5c3e9fa 100644 --- a/iOS Example/Cartfile.resolved +++ b/iOS Example/Cartfile.resolved @@ -1 +1 @@ -github "ReactiveX/RxSwift" "2.1.0" +github "ReactiveX/RxSwift" "3.4.0" diff --git a/iOS Example/iOS Example.xcodeproj/project.pbxproj b/iOS Example/iOS Example.xcodeproj/project.pbxproj index 17896f7..63a9f65 100644 --- a/iOS Example/iOS Example.xcodeproj/project.pbxproj +++ b/iOS Example/iOS Example.xcodeproj/project.pbxproj @@ -7,23 +7,25 @@ objects = { /* Begin PBXBuildFile section */ + 7810985B1EAE77E900FC4CF2 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B388AAE91C65640700726BCA /* RxSwift.framework */; }; + 7810985C1EAE77E900FC4CF2 /* RxSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B388AAE91C65640700726BCA /* RxSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 78FCA1D61EAE75FA00532F8B /* RxMediaPicker.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 78FCA1D51EAE75FA00532F8B /* RxMediaPicker.framework */; }; + 78FCA1D71EAE75FA00532F8B /* RxMediaPicker.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 78FCA1D51EAE75FA00532F8B /* RxMediaPicker.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; B388AAF91C65648700726BCA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B388AAF81C65648700726BCA /* AppDelegate.swift */; }; B388AAFB1C65648700726BCA /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B388AAFA1C65648700726BCA /* ViewController.swift */; }; B388AB001C65648700726BCA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B388AAFF1C65648700726BCA /* Assets.xcassets */; }; B388AB031C65648700726BCA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B388AB011C65648700726BCA /* LaunchScreen.storyboard */; }; - B388AB0D1C6567FA00726BCA /* RxMediaPicker.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B388AB0C1C6567FA00726BCA /* RxMediaPicker.framework */; }; - B388AB0E1C6567FA00726BCA /* RxMediaPicker.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B388AB0C1C6567FA00726BCA /* RxMediaPicker.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - B388AB121C65695000726BCA /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B388AB111C65695000726BCA /* RxSwift.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ - B388AB0F1C6567FA00726BCA /* Embed Frameworks */ = { + 78FCA1D81EAE75FA00532F8B /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( - B388AB0E1C6567FA00726BCA /* RxMediaPicker.framework in Embed Frameworks */, + 7810985C1EAE77E900FC4CF2 /* RxSwift.framework in Embed Frameworks */, + 78FCA1D71EAE75FA00532F8B /* RxMediaPicker.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -31,6 +33,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 78FCA1D51EAE75FA00532F8B /* RxMediaPicker.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RxMediaPicker.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B388AAE91C65640700726BCA /* RxSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxSwift.framework; path = Carthage/Build/iOS/RxSwift.framework; sourceTree = ""; }; B388AAF51C65648700726BCA /* iOS Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; B388AAF81C65648700726BCA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; B388AAFA1C65648700726BCA /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; @@ -46,8 +50,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - B388AB121C65695000726BCA /* RxSwift.framework in Frameworks */, - B388AB0D1C6567FA00726BCA /* RxMediaPicker.framework in Frameworks */, + 78FCA1D61EAE75FA00532F8B /* RxMediaPicker.framework in Frameworks */, + 7810985B1EAE77E900FC4CF2 /* RxSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -57,6 +61,7 @@ B388AAEC1C65648700726BCA = { isa = PBXGroup; children = ( + 78FCA1D51EAE75FA00532F8B /* RxMediaPicker.framework */, B388AB111C65695000726BCA /* RxSwift.framework */, B388AB0C1C6567FA00726BCA /* RxMediaPicker.framework */, B388AAF71C65648700726BCA /* iOS Example */, @@ -94,8 +99,7 @@ B388AAF11C65648700726BCA /* Sources */, B388AAF21C65648700726BCA /* Frameworks */, B388AAF31C65648700726BCA /* Resources */, - B388AB0F1C6567FA00726BCA /* Embed Frameworks */, - B388AB101C65685E00726BCA /* ShellScript */, + 78FCA1D81EAE75FA00532F8B /* Embed Frameworks */, ); buildRules = ( ); @@ -118,6 +122,7 @@ TargetAttributes = { B388AAF41C65648700726BCA = { CreatedOnToolsVersion = 7.2.1; + DevelopmentTeam = 395DA82334; LastSwiftMigration = 0800; }; }; @@ -152,23 +157,6 @@ }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - B388AB101C65685E00726BCA /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "$(SRCROOT)/Carthage/Build/iOS/RxSwift.framework", - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = "/usr/local/bin/carthage copy-frameworks"; - shellScript = ""; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ B388AAF11C65648700726BCA /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -287,6 +275,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEVELOPMENT_TEAM = 395DA82334; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", @@ -307,6 +296,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEVELOPMENT_TEAM = 395DA82334; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", diff --git a/iOS Example/iOS Example/AppDelegate.swift b/iOS Example/iOS Example/AppDelegate.swift index 8b914a1..fb7e48f 100644 --- a/iOS Example/iOS Example/AppDelegate.swift +++ b/iOS Example/iOS Example/AppDelegate.swift @@ -5,15 +5,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - + func applicationDidFinishLaunching(_ application: UIApplication) { + window = UIWindow(frame: UIScreen.main.bounds) - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { - window = UIWindow(frame: UIScreen.mainScreen().bounds) - window?.rootViewController = ViewController() window?.makeKeyAndVisible() - window?.backgroundColor = UIColor.whiteColor() - - return true + window?.backgroundColor = .white } } diff --git a/iOS Example/iOS Example/Info.plist b/iOS Example/iOS Example/Info.plist index eabb3ae..a0f0f9f 100644 --- a/iOS Example/iOS Example/Info.plist +++ b/iOS Example/iOS Example/Info.plist @@ -22,6 +22,12 @@ 1 LSRequiresIPhoneOS + NSCameraUsageDescription + RxMediaPicker Example + NSMicrophoneUsageDescription + RxMediaPicker Example + NSPhotoLibraryUsageDescription + RxMediaPicker Example UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities diff --git a/iOS Example/iOS Example/ViewController.swift b/iOS Example/iOS Example/ViewController.swift index 4ef547b..8172427 100644 --- a/iOS Example/iOS Example/ViewController.swift +++ b/iOS Example/iOS Example/ViewController.swift @@ -9,27 +9,28 @@ class ViewController: UIViewController, RxMediaPickerDelegate { var moviePlayer: MPMoviePlayerController! let disposeBag = DisposeBag() - lazy var buttonPhoto: UIButton = self.makeButton("Pick photo", target: self, action: "pickPhoto") - lazy var buttonVideo: UIButton = self.makeButton("Record video", target: self, action: "recordVideo") + lazy var buttonPhoto: UIButton = self.makeButton(title: "Pick photo", target: self, action: #selector(ViewController.pickPhoto)) + lazy var buttonVideo: UIButton = self.makeButton(title: "Record video", target: self, action: #selector(ViewController.recordVideo)) lazy var container: UIView = self.makeContainer() override func loadView() { super.loadView() - + view.addSubview(buttonPhoto) view.addSubview(buttonVideo) view.addSubview(container) let views = ["buttonPhoto": buttonPhoto, "buttonVideo": buttonVideo, "container": container] + + var constraints = NSLayoutConstraint.constraints(withVisualFormat: "V:|-50-[buttonPhoto]-20-[buttonVideo]-20-[container(==200)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: .none, views: views) + + constraints += NSLayoutConstraint.constraints(withVisualFormat: "H:[container(==200)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: .none, views: views) - var constraints = NSLayoutConstraint.constraintsWithVisualFormat("V:|-50-[buttonPhoto]-20-[buttonVideo]-20-[container(==200)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: .None, views: views) - constraints += NSLayoutConstraint.constraintsWithVisualFormat("H:[container(==200)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: .None, views: views) - - constraints.append(NSLayoutConstraint(item: buttonPhoto, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: 0)) - constraints.append(NSLayoutConstraint(item: buttonVideo, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: 0)) - constraints.append(NSLayoutConstraint(item: container, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: 0)) + constraints.append(NSLayoutConstraint(item: buttonPhoto, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 0)) + constraints.append(NSLayoutConstraint(item: buttonVideo, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 0)) + constraints.append(NSLayoutConstraint(item: container, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 0)) - NSLayoutConstraint.activateConstraints(constraints) + NSLayoutConstraint.activate(constraints) } override func viewDidLoad() { @@ -40,9 +41,9 @@ class ViewController: UIViewController, RxMediaPickerDelegate { func makeButton(title: String, target: AnyObject, action: Selector) -> UIButton { let b = UIButton() b.translatesAutoresizingMaskIntoConstraints = false - b.setTitle(title, forState: .Normal) - b.addTarget(target, action: action, forControlEvents: .TouchUpInside) - b.setTitleColor(UIColor.blueColor(), forState: .Normal) + b.setTitle(title, for: .normal) + b.addTarget(target, action: action, for: .touchUpInside) + b.setTitleColor(.blue, for: .normal) return b } @@ -50,7 +51,7 @@ class ViewController: UIViewController, RxMediaPickerDelegate { func makeContainer() -> UIView { let v = UIView() v.translatesAutoresizingMaskIntoConstraints = false - v.backgroundColor = UIColor.blackColor() + v.backgroundColor = .black return v } @@ -71,37 +72,39 @@ class ViewController: UIViewController, RxMediaPickerDelegate { self.removeAllSubviews() self.container.addSubview(imageView) }, onError: { error in - print("Got an error") + print("Picker photo error: \(error)") }, onCompleted: { print("Completed") }, onDisposed: { print("Disposed") }) - .addDisposableTo(disposeBag) + .disposed(by: disposeBag) } func recordVideo() { #if (arch(i386) || arch(x86_64)) - let alert = UIAlertController(title: "Error - Simulator", message: "Video recording not available on the simulator", preferredStyle: .Alert) - alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: .None)) - presentViewController(alert, animated: true, completion: .None) + let alert = UIAlertController(title: "Error - Simulator", message: "Video recording not available on the simulator", preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "OK", style: .default, handler: .none)) + present(alert, animated: true, completion: nil) return #endif - picker.selectVideo(.Camera, maximumDuration: 10, editable: true) - .observeOn(MainScheduler.instance) - .subscribe(onNext: processUrl - , onError: { error in - print("Got an error") - }, onCompleted: { - print("Completed") - }, onDisposed: { - print("Disposed") - }) - .addDisposableTo(disposeBag) + picker.selectVideo(source: .camera, maximumDuration: 10, editable: true) + .observeOn(MainScheduler.instance) + .subscribe(onNext: processUrl, + onError: { error in + print("Record video error \(error)") + }, + onCompleted: { + print("Completed") + }, + onDisposed: { + print("Disposed") + }) + .disposed(by: disposeBag) } - func processUrl(url: NSURL) { + func processUrl(url: URL) { moviePlayer = MPMoviePlayerController(contentURL: url) removeAllSubviews() @@ -113,15 +116,17 @@ class ViewController: UIViewController, RxMediaPickerDelegate { } // RxMediaPickerDelegate - - func presentPicker(picker: UIImagePickerController) { + func present(picker: UIImagePickerController) { + if moviePlayer.playbackState == .playing { + moviePlayer.stop() + } + print("Will present picker") - presentViewController(picker, animated: true, completion: .None) + present(picker, animated: true, completion: nil) } - - func dismissPicker(picker: UIImagePickerController) { + + func dismiss(picker: UIImagePickerController) { print("Will dismiss picker") - dismissViewControllerAnimated(true, completion: .None) + dismiss(animated: true, completion: nil) } - } From b7cd13c29801f66f260f50e94081af803cf3d742 Mon Sep 17 00:00:00 2001 From: Shai Mishali Date: Tue, 25 Apr 2017 11:23:06 +0300 Subject: [PATCH 4/5] Remove build script from RxMediaPicker target --- RxMediaPicker.xcodeproj/project.pbxproj | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/RxMediaPicker.xcodeproj/project.pbxproj b/RxMediaPicker.xcodeproj/project.pbxproj index 8376824..09c5edf 100644 --- a/RxMediaPicker.xcodeproj/project.pbxproj +++ b/RxMediaPicker.xcodeproj/project.pbxproj @@ -81,7 +81,6 @@ B388AAD81C6561B700726BCA /* Frameworks */, B388AAD91C6561B700726BCA /* Headers */, B388AADA1C6561B700726BCA /* Resources */, - 7810985A1EAE774900FC4CF2 /* ShellScript */, ); buildRules = ( ); @@ -134,23 +133,6 @@ }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - 7810985A1EAE774900FC4CF2 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "$(SRCROOT)/Carthage/Build/iOS/RxSwift.framework", - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/usr/local/bin/carthage copy-frameworks"; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ B388AAD71C6561B700726BCA /* Sources */ = { isa = PBXSourcesBuildPhase; From 22565a0e3d49b1210adce0b767669967873f4a46 Mon Sep 17 00:00:00 2001 From: Shai Mishali Date: Tue, 25 Apr 2017 11:29:20 +0300 Subject: [PATCH 5/5] Break up method signatures for increased readability --- RxMediaPicker/RxMediaPicker.swift | 32 ++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/RxMediaPicker/RxMediaPicker.swift b/RxMediaPicker/RxMediaPicker.swift index 1fd4a24..79f5c4f 100644 --- a/RxMediaPicker/RxMediaPicker.swift +++ b/RxMediaPicker/RxMediaPicker.swift @@ -34,8 +34,9 @@ public enum RxMediaPickerError: Error { self.delegate = delegate } - open func recordVideo(device: UIImagePickerControllerCameraDevice = .rear, quality: UIImagePickerControllerQualityType = .typeMedium, maximumDuration: TimeInterval = 600, editable: Bool = false) -> Observable { - + open func recordVideo(device: UIImagePickerControllerCameraDevice = .rear, + quality: UIImagePickerControllerQualityType = .typeMedium, + maximumDuration: TimeInterval = 600, editable: Bool = false) -> Observable { return Observable.create { observer in self.currentAction = RxMediaPickerAction.video(observer: observer, maxDuration: maximumDuration) @@ -57,8 +58,9 @@ public enum RxMediaPickerError: Error { } } - open func selectVideo(source: UIImagePickerControllerSourceType = .photoLibrary, maximumDuration: TimeInterval = 600, editable: Bool = false) -> Observable { - + open func selectVideo(source: UIImagePickerControllerSourceType = .photoLibrary, + maximumDuration: TimeInterval = 600, + editable: Bool = false) -> Observable { return Observable.create { [unowned self] observer in self.currentAction = RxMediaPickerAction.video(observer: observer, maxDuration: maximumDuration) @@ -75,8 +77,9 @@ public enum RxMediaPickerError: Error { } } - open func takePhoto(device: UIImagePickerControllerCameraDevice = .rear, flashMode: UIImagePickerControllerCameraFlashMode = .auto, editable: Bool = false) -> Observable<(UIImage, UIImage?)> { - + open func takePhoto(device: UIImagePickerControllerCameraDevice = .rear, + flashMode: UIImagePickerControllerCameraFlashMode = .auto, + editable: Bool = false) -> Observable<(UIImage, UIImage?)> { return Observable.create { [unowned self] observer in self.currentAction = RxMediaPickerAction.photo(observer: observer) @@ -99,8 +102,8 @@ public enum RxMediaPickerError: Error { } } - open func selectImage(source: UIImagePickerControllerSourceType = .photoLibrary, editable: Bool = false) -> Observable<(UIImage, UIImage?)> { - + open func selectImage(source: UIImagePickerControllerSourceType = .photoLibrary, + editable: Bool = false) -> Observable<(UIImage, UIImage?)> { return Observable.create { [unowned self] observer in self.currentAction = RxMediaPickerAction.photo(observer: observer) @@ -115,7 +118,8 @@ public enum RxMediaPickerError: Error { } } - func processPhoto(info: [String : AnyObject], observer: AnyObserver<(UIImage, UIImage?)>) { + func processPhoto(info: [String : AnyObject], + observer: AnyObserver<(UIImage, UIImage?)>) { guard let image = info[UIImagePickerControllerOriginalImage] as? UIImage, let editedImage = info[UIImagePickerControllerEditedImage] as? UIImage else { observer.on(.error(RxMediaPickerError.generalError)) @@ -126,7 +130,10 @@ public enum RxMediaPickerError: Error { observer.on(.completed) } - func processVideo(info: [String : Any], observer: AnyObserver, maxDuration: TimeInterval, picker: UIImagePickerController) { + func processVideo(info: [String : Any], + observer: AnyObserver, + maxDuration: TimeInterval, + picker: UIImagePickerController) { guard let videoURL = info[UIImagePickerControllerMediaURL] as? URL else { observer.on(.error(RxMediaPickerError.generalError)) dismissPicker(picker) @@ -164,7 +171,10 @@ public enum RxMediaPickerError: Error { } } - fileprivate func processVideo(url: URL, observer: AnyObserver, maxDuration: TimeInterval, picker: UIImagePickerController) { + fileprivate func processVideo(url: URL, + observer: AnyObserver, + maxDuration: TimeInterval, + picker: UIImagePickerController) { let asset = AVURLAsset(url: url) let duration = CMTimeGetSeconds(asset.duration)