From ee5f86cbf4e115cab47f941bf7fc21291536604b Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 12 Dec 2019 19:23:54 -0800 Subject: [PATCH] hang animation until focus completes --- .../AttachmentFormatPickerView.swift | 4 ++ .../ViewControllers/Photos/PhotoCapture.swift | 39 ++++++++++++++++++- .../Photos/PhotoCaptureViewController.swift | 26 +++++++++++-- SignalMessaging/categories/UIView+OWS.swift | 10 +++++ 4 files changed, 75 insertions(+), 4 deletions(-) diff --git a/Signal/src/ViewControllers/Attachment Keyboard/AttachmentFormatPickerView.swift b/Signal/src/ViewControllers/Attachment Keyboard/AttachmentFormatPickerView.swift index 28266ef0a6..53b8977d9a 100644 --- a/Signal/src/ViewControllers/Attachment Keyboard/AttachmentFormatPickerView.swift +++ b/Signal/src/ViewControllers/Attachment Keyboard/AttachmentFormatPickerView.swift @@ -166,6 +166,10 @@ extension AttachmentFormatPickerView: PhotoCaptureDelegate { func endCaptureButtonAnimation(_ duration: TimeInterval) { owsFailDebug("\(#function) should never be called") } + + func photoCapture(_ photoCapture: PhotoCapture, didCompleteFocusingAtPoint focusPoint: CGPoint) { + owsFailDebug("\(#function) should never be called") + } } // MARK: - UICollectionViewDataSource diff --git a/Signal/src/ViewControllers/Photos/PhotoCapture.swift b/Signal/src/ViewControllers/Photos/PhotoCapture.swift index cf0eb7a44f..a04652ca5f 100644 --- a/Signal/src/ViewControllers/Photos/PhotoCapture.swift +++ b/Signal/src/ViewControllers/Photos/PhotoCapture.swift @@ -13,7 +13,7 @@ protocol PhotoCaptureDelegate: AnyObject { func photoCapture(_ photoCapture: PhotoCapture, didFinishProcessingAttachment attachment: SignalAttachment) func photoCapture(_ photoCapture: PhotoCapture, processingDidError error: Error) - // MARK: Video + // MARK: Movie func photoCaptureDidBeginMovie(_ photoCapture: PhotoCapture) func photoCaptureDidCompleteMovie(_ photoCapture: PhotoCapture) @@ -28,6 +28,9 @@ protocol PhotoCaptureDelegate: AnyObject { func beginCaptureButtonAnimation(_ duration: TimeInterval) func endCaptureButtonAnimation(_ duration: TimeInterval) + + func photoCapture(_ photoCapture: PhotoCapture, didCompleteFocusingAtPoint focusPoint: CGPoint) + } @objc @@ -61,11 +64,25 @@ class PhotoCapture: NSObject { private let recordingAudioActivity = AudioActivity(audioDescription: "PhotoCapture", behavior: .playAndRecord) + var focusObservation: NSKeyValueObservation? override init() { self.session = AVCaptureSession() self.captureOutput = CaptureOutput() } + func didCompleteFocusing() { + Logger.debug("") + guard let currentCaptureInput = currentCaptureInput else { + return + } + + let focusPoint = currentCaptureInput.device.focusPointOfInterest + + DispatchQueue.main.async { + self.delegate?.photoCapture(self, didCompleteFocusingAtPoint: focusPoint) + } + } + // MARK: - Dependencies private var audioSession: OWSAudioSession { @@ -265,6 +282,26 @@ class PhotoCapture: NSObject { session.addInput(newInput) NotificationCenter.default.addObserver(self, selector: #selector(subjectAreaDidChange), name: .AVCaptureDeviceSubjectAreaDidChange, object: newInput.device) + if let focusObservation = focusObservation { + focusObservation.invalidate() + } + self.focusObservation = newInput.observe(\.device.isAdjustingFocus, + options: [.old, .new]) { [weak self] _, change in + guard let self = self else { return } + + guard let oldValue = change.oldValue else { + return + } + + guard let newValue = change.newValue else { + return + } + + if oldValue == true && newValue == false { + self.didCompleteFocusing() + } + } + currentCaptureInput = newInput resetFocusAndExposure() diff --git a/Signal/src/ViewControllers/Photos/PhotoCaptureViewController.swift b/Signal/src/ViewControllers/Photos/PhotoCaptureViewController.swift index dad0d66061..6bb6a0dd9c 100644 --- a/Signal/src/ViewControllers/Photos/PhotoCaptureViewController.swift +++ b/Signal/src/ViewControllers/Photos/PhotoCaptureViewController.swift @@ -362,13 +362,29 @@ class PhotoCaptureViewController: OWSViewController { func didTapFocusExpose(tapGesture: UITapGestureRecognizer) { let viewLocation = tapGesture.location(in: view) let devicePoint = previewView.previewLayer.captureDevicePointConverted(fromLayerPoint: viewLocation) - + currentlyFocusingAtPoint = devicePoint tapToFocusView.center = viewLocation - tapToFocusView.play() - + startFocusAnimation() photoCapture.focus(with: .autoFocus, exposureMode: .autoExpose, at: devicePoint, monitorSubjectAreaChange: true) } + // MARK: - Focus Animations + + func startFocusAnimation() { + tapToFocusView.stop() + tapToFocusView.play(fromProgress: 0.0, toProgress: 0.9) + } + + var currentlyFocusingAtPoint = CGPoint(x: 0.5, y: 0.5) + func completeFocusAnimation(forFocusPoint focusPoint: CGPoint) { + guard currentlyFocusingAtPoint.within(0.005, of: focusPoint) else { + Logger.verbose("focus completed for obsolete focus point. User has refocused on.") + return + } + + tapToFocusView.play(toProgress: 1.0) + } + // MARK: - Orientation // MARK: - @@ -543,6 +559,10 @@ extension PhotoCaptureViewController: PhotoCaptureDelegate { photoCapture.updateVideoPreviewConnection(toOrientation: orientation) } } + + func photoCapture(_ photoCapture: PhotoCapture, didCompleteFocusingAtPoint focusPoint: CGPoint) { + completeFocusAnimation(forFocusPoint: focusPoint) + } } // MARK: - Views diff --git a/SignalMessaging/categories/UIView+OWS.swift b/SignalMessaging/categories/UIView+OWS.swift index 97a5e9fbae..9990f1db95 100644 --- a/SignalMessaging/categories/UIView+OWS.swift +++ b/SignalMessaging/categories/UIView+OWS.swift @@ -342,6 +342,16 @@ public extension CGPoint { return sqrt(x * x + y * y) } + @inlinable + func distance(_ other: CGPoint) -> CGFloat { + return sqrt(pow(x - other.x, 2) + pow(y - other.y, 2)) + } + + @inlinable + func within(_ delta: CGFloat, of other: CGPoint) -> Bool { + return distance(other) <= delta + } + static let unit: CGPoint = CGPoint(x: 1.0, y: 1.0) static let unitMidpoint: CGPoint = CGPoint(x: 0.5, y: 0.5)