Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added camera type to callback when a photo is taken #696

Merged
merged 1 commit into from
Mar 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions ChattoAdditions/Source/Input/Photos/Camera/DeviceImagePicker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ import UIKit

final class DeviceImagePicker: NSObject, ImagePicker, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
let controller: UIViewController
var cameraType: CameraType { CameraType(self.pickerController.cameraDevice) }

private weak var delegate: ImagePickerDelegate?
private let pickerController = UIImagePickerController()

init(_ delegate: ImagePickerDelegate) {
let pickerController = UIImagePickerController()
self.controller = pickerController
self.controller = self.pickerController
self.delegate = delegate
super.init()
pickerController.delegate = self
Expand All @@ -56,3 +58,14 @@ final class DeviceImagePickerFactory: ImagePickerFactory {
return DeviceImagePicker(delegate)
}
}

private extension CameraType {

init(_ device: UIImagePickerController.CameraDevice) {
switch device {
case .front: self = .front
case .rear: self = .rear
@unknown default: fatalError("Unable to map unknown device type \(device.rawValue). Do you have a fancy device with a third camera type?!")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public protocol ImagePickerDelegate: class {

public protocol ImagePicker: class {
var controller: UIViewController { get }
var cameraType: CameraType { get }
}

public protocol ImagePickerFactory: class {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@
import UIKit

final class PhotosInputCameraPicker: ImagePickerDelegate {

typealias TakenImage = (image: UIImage, cameraType: CameraType)

private let presentingControllerProvider: () -> UIViewController?
private var imagePicker: ImagePicker?
private var completionBlocks: (onImageTaken: (UIImage?) -> Void, onCameraPickerDismissed: () -> Void)?
private var completionBlocks: (onImageTaken: (TakenImage?) -> Void, onCameraPickerDismissed: () -> Void)?

convenience init(presentingController: UIViewController?) {
self.init(presentingControllerProvider: { [weak presentingController] in presentingController })
Expand All @@ -37,7 +40,7 @@ final class PhotosInputCameraPicker: ImagePickerDelegate {
self.presentingControllerProvider = presentingControllerProvider
}

func presentCameraPicker(onImageTaken: @escaping (UIImage?) -> Void, onCameraPickerDismissed: @escaping () -> Void) {
func presentCameraPicker(onImageTaken: @escaping (TakenImage?) -> Void, onCameraPickerDismissed: @escaping () -> Void) {
guard let presentingController = self.presentingControllerProvider(),
let imagePicker = ImagePickerStore.factory.makeImagePicker(delegate: self) else {
onImageTaken(nil)
Expand All @@ -51,16 +54,20 @@ final class PhotosInputCameraPicker: ImagePickerDelegate {

func imagePickerDidFinish(_ picker: ImagePicker, mediaInfo: [UIImagePickerController.InfoKey: Any]) {
let image = mediaInfo[UIImagePickerController.InfoKey.originalImage] as? UIImage
self.finishPickingImage(image, fromPicker: picker.controller)
self.finishPickingImage(image, fromPicker: picker)
}

func imagePickerDidCancel(_ picker: ImagePicker) {
self.finishPickingImage(nil, fromPicker: picker.controller)
self.finishPickingImage(nil, fromPicker: picker)
}

private func finishPickingImage(_ image: UIImage?, fromPicker picker: UIViewController) {
picker.dismiss(animated: true, completion: self.completionBlocks?.onCameraPickerDismissed)
self.completionBlocks?.onImageTaken(image)
private func finishPickingImage(_ image: UIImage?, fromPicker picker: ImagePicker) {
picker.controller.dismiss(animated: true, completion: self.completionBlocks?.onCameraPickerDismissed)
if let image = image {
self.completionBlocks?.onImageTaken((image, picker.cameraType))
} else {
self.completionBlocks?.onImageTaken(nil)
}
self.completionBlocks = nil
self.imagePicker = nil
}
Expand Down
15 changes: 9 additions & 6 deletions ChattoAdditions/Source/Input/Photos/PhotosInputView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ public protocol PhotosInputViewProtocol {
var presentingController: UIViewController? { get }
}

public enum PhotosInputViewPhotoSource {
case camera
public enum CameraType {
case front, rear
}

public enum PhotosInputViewPhotoSource: Equatable {
case camera(CameraType)
case gallery
}

Expand Down Expand Up @@ -230,11 +234,10 @@ extension PhotosInputView: UICollectionViewDelegateFlowLayout {
self.delegate?.inputViewDidRequestCameraPermission(self)
} else {
self.liveCameraPresenter.cameraPickerWillAppear()
self.cameraPicker.presentCameraPicker(onImageTaken: { [weak self] (image) in
self.cameraPicker.presentCameraPicker(onImageTaken: { [weak self] (result) in
guard let sSelf = self else { return }

if let image = image {
sSelf.delegate?.inputView(sSelf, didSelectImage: image, source: .camera)
if let result = result {
sSelf.delegate?.inputView(sSelf, didSelectImage: result.image, source: .camera(result.cameraType))
}
}, onCameraPickerDismissed: { [weak self] in
self?.liveCameraPresenter.cameraPickerDidDisappear()
Expand Down
20 changes: 18 additions & 2 deletions ChattoAdditions/Tests/Input/PhotosChatInputItemTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,31 @@ class PhotosChatInputItemTests: XCTestCase {
XCTAssertFalse(handled)
}

func testThat_WhenInputViewSelectsImage_ItemPassedImageIntoPhotoHandler() {
func testThat_WhenInputViewSelectsImageFromFrontCamera_ItemPassedImageIntoPhotoHandler() {
var handledImage: UIImage?
var handledSource: PhotosInputViewPhotoSource?
self.inputItem.photoInputHandler = { image, source in
handledImage = image
handledSource = source
}
let image = UIImage()
let source = PhotosInputViewPhotoSource.camera
let source = PhotosInputViewPhotoSource.camera(.front)
let inputView = MockPhotosInputView()
self.inputItem.inputView(inputView, didSelectImage: image, source: source)

XCTAssertEqual(handledImage!, image)
XCTAssertEqual(handledSource!, source)
}

func testThat_WhenInputViewSelectsImageFromRearCamera_ItemPassedImageIntoPhotoHandler() {
var handledImage: UIImage?
var handledSource: PhotosInputViewPhotoSource?
self.inputItem.photoInputHandler = { image, source in
handledImage = image
handledSource = source
}
let image = UIImage()
let source = PhotosInputViewPhotoSource.camera(.rear)
let inputView = MockPhotosInputView()
self.inputItem.inputView(inputView, didSelectImage: image, source: source)

Expand Down
20 changes: 19 additions & 1 deletion ChattoAdditions/Tests/Input/PhotosInputCameraPickerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,28 @@ class PhotosInputCameraPickerTests: XCTestCase {
XCTAssertTrue(onCameraPickerDismissedCalled)
}

func testThat_GivenPresentedPicker_WhenPickerFinishedWithImage_ThenOnImageTakenCallbackReceivedImage() {
func testThat_GivenPresentedPicker_WhenPickerFinishedWithImageFromFrontCamera_ThenOnImageTakenCallbackReceivedImage() {
// Given
var onImageTakenCalled = false
self.sut.presentCameraPicker(onImageTaken: { (image) in
onImageTakenCalled = true
XCTAssertNotNil(image)
XCTAssertEqual(image?.cameraType, .front)
}, onCameraPickerDismissed: {})
// When
self.fakeImagePicker.finish(with: [UIImagePickerController.InfoKey.originalImage: UIImage()])
// Then
XCTAssertTrue(onImageTakenCalled)
}

func testThat_GivenPresentedPicker_WhenPickerFinishedWithImageFromRearCamera_ThenOnImageTakenCallbackReceivedImage() {
// Given
var onImageTakenCalled = false
self.fakeImagePicker.cameraType = .rear
self.sut.presentCameraPicker(onImageTaken: { (image) in
onImageTakenCalled = true
XCTAssertNotNil(image)
XCTAssertEqual(image?.cameraType, .rear)
}, onCameraPickerDismissed: {})
// When
self.fakeImagePicker.finish(with: [UIImagePickerController.InfoKey.originalImage: UIImage()])
Expand Down Expand Up @@ -111,6 +127,8 @@ class PhotosInputCameraPickerTests: XCTestCase {
}

private class FakeImagePicker: ImagePicker {
var cameraType: CameraType = .front

let controller: UIViewController = DummyViewController()
weak var delegate: ImagePickerDelegate?

Expand Down