Skip to content

Commit

Permalink
Merge remote-tracking branch 'hyperoslo/master'
Browse files Browse the repository at this point in the history
* hyperoslo/master:
  Add pinch to zoom
  Set no images label initial frame & center label during animation
  Apply transforms on viewDidAppear
  Use correct screen size for current orientation
  Tidy unused closure parameters and fix alignment
  Trailing closure syntax
  Remove whitespace
  Open topView property on ImagePickerController
  Open TopView class and camera buttons
  Add managesAudioSession configuration flag
  Add option to set flash button to be always hidden
  ButtonPicker title font configuration bug fix
  • Loading branch information
Haitec committed Sep 1, 2017
2 parents b66520e + 8f7952b commit 58c22ab
Show file tree
Hide file tree
Showing 13 changed files with 123 additions and 43 deletions.
6 changes: 3 additions & 3 deletions Source/AssetManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ open class AssetManager {
let fetchResult = configuration.allowVideoSelection
? PHAsset.fetchAssets(with: PHFetchOptions())
: PHAsset.fetchAssets(with: .image, options: PHFetchOptions())

if fetchResult.count > 0 {
var assets = [PHAsset]()
fetchResult.enumerateObjects({ object, index, stop in
fetchResult.enumerateObjects({ object, _, _ in
assets.insert(object, at: 0)
})

Expand Down Expand Up @@ -58,7 +58,7 @@ open class AssetManager {

var images = [UIImage]()
for asset in assets {
imageManager.requestImage(for: asset, targetSize: size, contentMode: .aspectFill, options: requestOptions) { image, info in
imageManager.requestImage(for: asset, targetSize: size, contentMode: .aspectFill, options: requestOptions) { image, _ in
if let image = image {
images.append(image)
}
Expand Down
2 changes: 1 addition & 1 deletion Source/BottomView/BottomContainerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ open class BottomContainerView: UIView {
var configuration = Configuration()

lazy var pickerButton: ButtonPicker = { [unowned self] in
let pickerButton = ButtonPicker()
let pickerButton = ButtonPicker(configuration: self.configuration)
pickerButton.setTitleColor(UIColor.white, for: UIControlState())
pickerButton.delegate = self
pickerButton.numberLabel.isHidden = !self.configuration.showsImageCountLabel
Expand Down
2 changes: 1 addition & 1 deletion Source/BottomView/ImageStack.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ open class ImageStack {
}

open func dropAsset(_ asset: PHAsset) {
assets = assets.filter() {$0 != asset}
assets = assets.filter {$0 != asset}
NotificationCenter.default.post(name: Notification.Name(rawValue: Notifications.imageDidDrop), object: self, userInfo: [imageKey: asset])
}

Expand Down
14 changes: 11 additions & 3 deletions Source/CameraView/CameraMan.swift
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,7 @@ class CameraMan {
connection.videoOrientation = Helper.videoOrientation()

queue.async {
self.stillImageOutput?.captureStillImageAsynchronously(from: connection) {
buffer, error in

self.stillImageOutput?.captureStillImageAsynchronously(from: connection) { buffer, error in
guard let buffer = buffer, error == nil && CMSampleBufferIsValid(buffer),
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer),
let image = UIImage(data: imageData)
Expand Down Expand Up @@ -206,6 +204,16 @@ class CameraMan {
}
}

func zoom(_ zoomFactor: CGFloat) {
guard let device = currentInput?.device, device.position == .back else { return }

queue.async {
self.lock {
device.videoZoomFactor = zoomFactor
}
}
}

// MARK: - Lock

func lock(_ block: () -> Void) {
Expand Down
52 changes: 48 additions & 4 deletions Source/CameraView/CameraView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ class CameraView: UIViewController, CLLocationManagerDelegate, CameraManDelegate
let button = UIButton(type: .system)
let title = NSAttributedString(string: self.configuration.settingsTitle,
attributes: [
NSFontAttributeName : self.configuration.settingsFont,
NSForegroundColorAttributeName : self.configuration.settingsColor
NSFontAttributeName: self.configuration.settingsFont,
NSForegroundColorAttributeName: self.configuration.settingsColor
])

button.setAttributedTitle(title, for: UIControlState())
Expand All @@ -81,6 +81,13 @@ class CameraView: UIViewController, CLLocationManagerDelegate, CameraManDelegate
return gesture
}()

lazy var pinchGestureRecognizer: UIPinchGestureRecognizer = { [unowned self] in
let gesture = UIPinchGestureRecognizer()
gesture.addTarget(self, action: #selector(pinchGestureRecognizerHandler(_:)))

return gesture
}()

let cameraMan = CameraMan()

var previewLayer: AVCaptureVideoPreviewLayer?
Expand All @@ -89,6 +96,12 @@ class CameraView: UIViewController, CLLocationManagerDelegate, CameraManDelegate
var locationManager: LocationManager?
var startOnFrontCamera: Bool = false

private let minimumZoomFactor: CGFloat = 1.0
private let maximumZoomFactor: CGFloat = 3.0

private var currentZoomFactor: CGFloat = 1.0
private var previousZoomFactor: CGFloat = 1.0

public init(configuration: Configuration? = nil) {
if let configuration = configuration {
self.configuration = configuration
Expand Down Expand Up @@ -118,6 +131,10 @@ class CameraView: UIViewController, CLLocationManagerDelegate, CameraManDelegate

view.addGestureRecognizer(tapGestureRecognizer)

if configuration.allowPinchToZoom {
view.addGestureRecognizer(pinchGestureRecognizer)
}

cameraMan.delegate = self
cameraMan.setup(self.startOnFrontCamera)
}
Expand Down Expand Up @@ -199,7 +216,7 @@ class CameraView: UIViewController, CLLocationManagerDelegate, CameraManDelegate
cameraMan.flash(mapping[title] ?? .auto)
}

func takePicture(_ completion: @escaping () -> ()) {
func takePicture(_ completion: @escaping () -> Void) {
guard let previewLayer = previewLayer else { return }

UIView.animate(withDuration: 0.1, animations: {
Expand Down Expand Up @@ -244,6 +261,16 @@ class CameraView: UIViewController, CLLocationManagerDelegate, CameraManDelegate
})
}

func zoomTo(_ zoomFactor: CGFloat) {
guard let device = cameraMan.currentInput?.device else { return }

let maximumDeviceZoomFactor = device.activeFormat.videoMaxZoomFactor
let newZoomFactor = previousZoomFactor * zoomFactor
currentZoomFactor = min(maximumZoomFactor, max(minimumZoomFactor, min(newZoomFactor, maximumDeviceZoomFactor)))

cameraMan.zoom(currentZoomFactor)
}

// MARK: - Tap

func tapGestureRecognizerHandler(_ gesture: UITapGestureRecognizer) {
Expand All @@ -254,6 +281,21 @@ class CameraView: UIViewController, CLLocationManagerDelegate, CameraManDelegate
focusTo(touch)
}

// MARK: - Pinch

func pinchGestureRecognizerHandler(_ gesture: UIPinchGestureRecognizer) {
switch gesture.state {
case .began:
fallthrough
case .changed:
zoomTo(gesture.scale)
case .ended:
zoomTo(gesture.scale)
previousZoomFactor = currentZoomFactor
default: break
}
}

// MARK: - Private helpers

func showNoCamera(_ show: Bool) {
Expand All @@ -270,7 +312,9 @@ class CameraView: UIViewController, CLLocationManagerDelegate, CameraManDelegate
}

func cameraMan(_ cameraMan: CameraMan, didChangeInput input: AVCaptureDeviceInput) {
delegate?.setFlashButtonHidden(!input.device.hasFlash)
if !configuration.flashButtonAlwaysHidden {
delegate?.setFlashButtonHidden(!input.device.hasFlash)
}
}

func cameraManDidStart(_ cameraMan: CameraMan) {
Expand Down
3 changes: 3 additions & 0 deletions Source/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ public struct Configuration {
public var allowMultiplePhotoSelection = true
public var allowVideoSelection = false
public var showsImageCountLabel = true
public var flashButtonAlwaysHidden = false
public var managesAudioSession = true
public var allowPinchToZoom = true
public var allowedOrientations = UIInterfaceOrientationMask.all

// MARK: Images
Expand Down
6 changes: 4 additions & 2 deletions Source/Extensions/ConstraintsSetup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,15 @@ extension BottomContainerView {
relatedBy: .equal, toItem: self, attribute: .centerY,
multiplier: 1, constant: -2))

let screenSize = Helper.screenSizeForOrientation()

addConstraint(NSLayoutConstraint(item: doneButton, attribute: .centerX,
relatedBy: .equal, toItem: self, attribute: .right,
multiplier: 1, constant: -(UIScreen.main.bounds.width - (ButtonPicker.Dimensions.buttonBorderSize + UIScreen.main.bounds.width)/2)/2))
multiplier: 1, constant: -(screenSize.width - (ButtonPicker.Dimensions.buttonBorderSize + screenSize.width)/2)/2))

addConstraint(NSLayoutConstraint(item: stackView, attribute: .centerX,
relatedBy: .equal, toItem: self, attribute: .left,
multiplier: 1, constant: UIScreen.main.bounds.width/4 - ButtonPicker.Dimensions.buttonBorderSize/3))
multiplier: 1, constant: screenSize.width/4 - ButtonPicker.Dimensions.buttonBorderSize/3))

addConstraint(NSLayoutConstraint(item: topSeparator, attribute: .height,
relatedBy: .equal, toItem: nil, attribute: .notAnAttribute,
Expand Down
9 changes: 9 additions & 0 deletions Source/Helper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,13 @@ struct Helper {
return getVideoOrientation(fromDeviceOrientation: previousOrientation)
}

static func screenSizeForOrientation() -> CGSize {
switch UIDevice.current.orientation {
case .landscapeLeft, .landscapeRight:
return CGSize(width: UIScreen.main.bounds.height,
height: UIScreen.main.bounds.width)
default:
return UIScreen.main.bounds.size
}
}
}
25 changes: 12 additions & 13 deletions Source/ImageGallery/ImageGalleryView.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import UIKit
import Photos
fileprivate func < <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
private func < <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return l < r
Expand Down Expand Up @@ -137,6 +137,7 @@ open class ImageGalleryView: UIView {
width: configuration.indicatorWidth, height: configuration.indicatorHeight)
collectionView.frame = CGRect(x: 0, y: topSeparator.frame.height, width: totalWidth, height: collectionFrame - topSeparator.frame.height)
collectionSize = CGSize(width: collectionView.frame.height, height: collectionView.frame.height)
noImagesLabel.center = CGPoint(x: bounds.width / 2, y: (bounds.height + Dimensions.galleryBarHeight) / 2)

collectionView.reloadData()
}
Expand All @@ -149,7 +150,7 @@ open class ImageGalleryView: UIView {
if threshold > height || self.collectionView.alpha != 0 {
self.noImagesLabel.alpha = 0
} else {
self.noImagesLabel.center = CGPoint(x: self.bounds.width / 2, y: height / 2)
self.noImagesLabel.center = CGPoint(x: self.bounds.width / 2, y: (height + Dimensions.galleryBarHeight) / 2)
self.noImagesLabel.alpha = (height > threshold) ? 1 : (height - Dimensions.galleryBarHeight) / threshold
}
})
Expand Down Expand Up @@ -197,8 +198,8 @@ open class ImageGalleryView: UIView {
extension ImageGalleryView: UICollectionViewDelegateFlowLayout {

public func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
guard let collectionSize = collectionSize else { return CGSize.zero }

return collectionSize
Expand All @@ -219,21 +220,19 @@ extension ImageGalleryView: UICollectionViewDelegate {
}
// Animate deselecting photos for any selected visible cells
guard let visibleCells = collectionView.visibleCells as? [ImageGalleryViewCell] else { return }
for cell in visibleCells {
if cell.selectedImageView.image != nil {
UIView.animate(withDuration: 0.2, animations: {
cell.selectedImageView.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
}, completion: { _ in
cell.selectedImageView.image = nil
})
}
for cell in visibleCells where cell.selectedImageView.image != nil {
UIView.animate(withDuration: 0.2, animations: {
cell.selectedImageView.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
}, completion: { _ in
cell.selectedImageView.image = nil
})
}
}

let asset = assets[(indexPath as NSIndexPath).row]

AssetManager.resolveAsset(asset, size: CGSize(width: 100, height: 100)) { image in
guard let _ = image else { return }
guard image != nil else { return }

if cell.selectedImageView.image != nil {
UIView.animate(withDuration: 0.2, animations: {
Expand Down
4 changes: 2 additions & 2 deletions Source/ImageGallery/ImageGalleryViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class ImageGalleryViewCell: UICollectionViewCell {
lazy var imageView = UIImageView()
lazy var selectedImageView = UIImageView()
private var videoInfoView: VideoInfoView

private let videoInfoBarHeight: CGFloat = 15
var duration: TimeInterval? {
didSet {
Expand All @@ -17,7 +17,7 @@ class ImageGalleryViewCell: UICollectionViewCell {
}
}
}

override init(frame: CGRect) {
let videoBarFrame = CGRect(x: 0, y: frame.height - self.videoInfoBarHeight,
width: frame.width, height: self.videoInfoBarHeight)
Expand Down
4 changes: 2 additions & 2 deletions Source/ImageGallery/VideoInfoView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class VideoInfoView: UIView {
videoIcon.contentMode = .scaleAspectFit
return videoIcon
}()

private lazy var videoInfoLabel: UILabel = {
let videoInfoLabel = UILabel(frame: CGRect(x: 0,
y: 0,
Expand All @@ -29,7 +29,7 @@ class VideoInfoView: UIView {
videoInfoLabel.text = self.dateFormatter.string(from: self.duration ?? 0)
return videoInfoLabel
}()

private lazy var dateFormatter: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.zeroFormattingBehavior = .pad
Expand Down
Loading

0 comments on commit 58c22ab

Please sign in to comment.