Skip to content
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
4 changes: 4 additions & 0 deletions ChattoAdditions/ChattoAdditions.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
EA13CAF2229EE8C8009340C5 /* CircleIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA13CAF1229EE8C8009340C5 /* CircleIconView.swift */; };
EA13CAF4229EE985009340C5 /* CircleProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA13CAF3229EE985009340C5 /* CircleProgressView.swift */; };
EA13CAF6229EE9A6009340C5 /* CircleProgressIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA13CAF5229EE9A6009340C5 /* CircleProgressIndicatorView.swift */; };
EA6D0D3125FA1BFA00A03C5C /* LiveCameraCellPresenterFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6D0D2F25FA1BFA00A03C5C /* LiveCameraCellPresenterFactory.swift */; };
EA7525502302E94B0069D1AF /* MessageModel+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA75254F2302E94B0069D1AF /* MessageModel+Helpers.swift */; };
EA7525522302FB930069D1AF /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7525512302FB930069D1AF /* TestHelpers.swift */; };
EA7527982302FD790069D1AF /* StubCompoundBubbleViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7527972302FD790069D1AF /* StubCompoundBubbleViewStyle.swift */; };
Expand Down Expand Up @@ -301,6 +302,7 @@
EA13CAF1229EE8C8009340C5 /* CircleIconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleIconView.swift; sourceTree = "<group>"; };
EA13CAF3229EE985009340C5 /* CircleProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleProgressView.swift; sourceTree = "<group>"; };
EA13CAF5229EE9A6009340C5 /* CircleProgressIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleProgressIndicatorView.swift; sourceTree = "<group>"; };
EA6D0D2F25FA1BFA00A03C5C /* LiveCameraCellPresenterFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LiveCameraCellPresenterFactory.swift; sourceTree = "<group>"; };
EA75254F2302E94B0069D1AF /* MessageModel+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageModel+Helpers.swift"; sourceTree = "<group>"; };
EA7525512302FB930069D1AF /* TestHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = "<group>"; };
EA7527972302FD790069D1AF /* StubCompoundBubbleViewStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubCompoundBubbleViewStyle.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -716,6 +718,7 @@
C33DEA461D23F8C8002AAD26 /* LiveCameraCaptureSession.swift */,
C3C0CC0D1BFE496A0052747C /* LiveCameraCell.swift */,
C33DEA441D23F825002AAD26 /* LiveCameraCellPresenter.swift */,
EA6D0D2F25FA1BFA00A03C5C /* LiveCameraCellPresenterFactory.swift */,
C3C0CC101BFE496A0052747C /* PhotosInputCameraPicker.swift */,
CD240FA7D32306EC2284C287 /* ImagePicker.swift */,
);
Expand Down Expand Up @@ -966,6 +969,7 @@
55127638218C9FF900731463 /* ScreenMetric.swift in Sources */,
268CD5802204876B00DEE2C2 /* CompoundBubbleLayout.swift in Sources */,
EAF2679022BD2625006B3455 /* DefaultMessageContentPresenter.swift in Sources */,
EA6D0D3125FA1BFA00A03C5C /* LiveCameraCellPresenterFactory.swift in Sources */,
268CD56321F9F92C00DEE2C2 /* CompoundBubbleViewStyle.swift in Sources */,
C3C0CC5E1BFE496A0052747C /* PhotosInputView.swift in Sources */,
CDC60FFD1FD7259200C2588E /* PhotosInputPlaceholderCell.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,41 @@
*/

import UIKit
import Photos
import AVFoundation

public struct LiveCameraSettings {
public let cameraPosition: AVCaptureDevice.Position

public init(cameraPosition: AVCaptureDevice.Position) {
self.cameraPosition = cameraPosition
}
}

public static func makeDefaultSettings() -> LiveCameraSettings {
return LiveCameraSettings(cameraPosition: .unspecified)
}
public protocol LiveCameraCellPresenterProtocol {

func registerCells(collectionView: UICollectionView)
func dequeueCell(collectionView: UICollectionView, indexPath: IndexPath) -> UICollectionViewCell

func cellWillBeShown(_ cell: UICollectionViewCell)
func cellWasHidden(_ cell: UICollectionViewCell)

func cameraPickerWillAppear()
func cameraPickerDidDisappear()
}

public final class LiveCameraCellPresenter {
public typealias AVAuthorizationStatusProvider = () -> AVAuthorizationStatus

public final class LiveCameraCellPresenter: LiveCameraCellPresenterProtocol {
private typealias Class = LiveCameraCellPresenter
public typealias AVAuthorizationStatusProvider = () -> AVAuthorizationStatus

private let cameraSettings: LiveCameraSettings
private let cellAppearance: LiveCameraCellAppearance
private let authorizationStatusProvider: () -> AVAuthorizationStatus
private var isCellAddedToWindow: Bool = false

public init(cameraSettings: LiveCameraSettings = LiveCameraSettings.makeDefaultSettings(),
cellAppearance: LiveCameraCellAppearance = LiveCameraCellAppearance.createDefaultAppearance(),
authorizationStatusProvider: @escaping AVAuthorizationStatusProvider = LiveCameraCellPresenter.createDefaultCameraAuthorizationStatusProvider()) {
public init(cameraSettings: LiveCameraSettings,
cellAppearance: LiveCameraCellAppearance,
authorizationStatusProvider: @escaping AVAuthorizationStatusProvider) {
self.cameraSettings = cameraSettings
self.cellAppearance = cellAppearance
self.authorizationStatusProvider = authorizationStatusProvider
Expand All @@ -59,13 +68,8 @@ public final class LiveCameraCellPresenter {
}

private static let reuseIdentifier = "LiveCameraCell"
public static func createDefaultCameraAuthorizationStatusProvider() -> AVAuthorizationStatusProvider {
return {
return AVCaptureDevice.authorizationStatus(for: .video)
}
}

public static func registerCells(collectionView: UICollectionView) {
public func registerCells(collectionView: UICollectionView) {
collectionView.register(LiveCameraCell.self, forCellWithReuseIdentifier: Class.reuseIdentifier)
}

Expand Down Expand Up @@ -162,12 +166,12 @@ public final class LiveCameraCellPresenter {
}

var cameraPickerIsVisible = false
func cameraPickerWillAppear() {
public func cameraPickerWillAppear() {
self.cameraPickerIsVisible = true
self.stopCapturing()
}

func cameraPickerDidDisappear() {
public func cameraPickerDidDisappear() {
self.cameraPickerIsVisible = false
if self.isCellAddedToWindow {
self.startCapturing()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
The MIT License (MIT)

Copyright (c) 2015-present Badoo Trading Limited.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

import AVFoundation

public protocol LiveCameraCellPresenterFactoryProtocol {
func makeLiveCameraCellPresenter() -> LiveCameraCellPresenterProtocol
}

public struct LiveCameraCellPresenterFactory: LiveCameraCellPresenterFactoryProtocol {

private let cameraSettings: LiveCameraSettings
private let cellAppearance: LiveCameraCellAppearance
private let authorizationStatusProvider: AVAuthorizationStatusProvider

public init(cameraSettings: LiveCameraSettings = .init(cameraPosition: .unspecified),
cellAppearance: LiveCameraCellAppearance = .createDefaultAppearance(),
authorizationStatusProvider: @escaping AVAuthorizationStatusProvider = { AVCaptureDevice.authorizationStatus(for: .video) }) {
self.cameraSettings = cameraSettings
self.cellAppearance = cellAppearance
self.authorizationStatusProvider = authorizationStatusProvider
}

public func makeLiveCameraCellPresenter() -> LiveCameraCellPresenterProtocol {
return LiveCameraCellPresenter(
cameraSettings: self.cameraSettings,
cellAppearance: self.cellAppearance,
authorizationStatusProvider: self.authorizationStatusProvider
)
}
}
15 changes: 6 additions & 9 deletions ChattoAdditions/Source/Input/Photos/PhotosChatInputItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,11 @@ open class PhotosChatInputItem: ChatInputItemProtocol {
public weak var presentingController: UIViewController?

let buttonAppearance: TabInputButtonAppearance
let inputViewAppearance: PhotosInputViewAppearance

public init(presentingController: UIViewController?,
tabInputButtonAppearance: TabInputButtonAppearance = PhotosChatInputItem.createDefaultButtonAppearance(),
inputViewAppearance: PhotosInputViewAppearance = PhotosChatInputItem.createDefaultInputViewAppearance()) {
tabInputButtonAppearance: TabInputButtonAppearance = PhotosChatInputItem.createDefaultButtonAppearance()) {
self.presentingController = presentingController
self.buttonAppearance = tabInputButtonAppearance
self.inputViewAppearance = inputViewAppearance
}

public static func createDefaultButtonAppearance() -> TabInputButtonAppearance {
Expand All @@ -54,16 +52,15 @@ open class PhotosChatInputItem: ChatInputItemProtocol {
return TabInputButtonAppearance(images: images, size: nil)
}

public static func createDefaultInputViewAppearance() -> PhotosInputViewAppearance {
return PhotosInputViewAppearance(liveCameraCellAppearence: LiveCameraCellAppearance.createDefaultAppearance())
}

lazy private var internalTabView: UIButton = {
return TabInputButton.makeInputButton(withAppearance: self.buttonAppearance, accessibilityID: "photos.chat.input.view")
}()

lazy var photosInputView: PhotosInputViewProtocol = {
let photosInputView = PhotosInputView(presentingController: self.presentingController, appearance: self.inputViewAppearance)
let photosInputView = PhotosInputView(
presentingController: self.presentingController,
customLiveCameraCellPresenterFactory: nil
)
photosInputView.delegate = self
return photosInputView
}()
Expand Down
39 changes: 14 additions & 25 deletions ChattoAdditions/Source/Input/Photos/PhotosInputView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,6 @@ import UIKit
import Photos
import Chatto

public struct PhotosInputViewAppearance {
public var liveCameraCellAppearence: LiveCameraCellAppearance
public init(liveCameraCellAppearence: LiveCameraCellAppearance) {
self.liveCameraCellAppearence = liveCameraCellAppearence
}
}

public protocol PhotosInputViewProtocol {
var delegate: PhotosInputViewDelegate? { get set }
var presentingController: UIViewController? { get }
Expand Down Expand Up @@ -78,6 +71,7 @@ public final class PhotosInputView: UIView, PhotosInputViewProtocol {
}

public weak var delegate: PhotosInputViewDelegate?

override init(frame: CGRect) {
super.init(frame: frame)
self.commonInit()
Expand All @@ -89,27 +83,22 @@ public final class PhotosInputView: UIView, PhotosInputViewProtocol {
}

public var presentingControllerProvider: () -> UIViewController? = { nil }
public var presentingController: UIViewController? { self.presentingControllerProvider() }

public var presentingController: UIViewController? {
return self.presentingControllerProvider()
}

var appearance: PhotosInputViewAppearance?
private lazy var liveCameraCellPresenterFactory: LiveCameraCellPresenterFactoryProtocol = {
return LiveCameraCellPresenterFactory()
}()

public init(presentingControllerProvider: @escaping () -> UIViewController?,
appearance: PhotosInputViewAppearance) {
self.presentingControllerProvider = presentingControllerProvider
public init(presentingController: @escaping @autoclosure () -> UIViewController?,
customLiveCameraCellPresenterFactory: LiveCameraCellPresenterFactoryProtocol?) {
self.presentingControllerProvider = presentingController
super.init(frame: CGRect.zero)
self.appearance = appearance
if let customLiveCameraCellPresenterFactory = customLiveCameraCellPresenterFactory {
self.liveCameraCellPresenterFactory = customLiveCameraCellPresenterFactory
}
self.commonInit()
}

public convenience init(presentingController: UIViewController?,
appearance: PhotosInputViewAppearance) {
self.init(presentingControllerProvider: { [weak presentingController] in presentingController },
appearance: appearance)
}

deinit {
self.collectionView.dataSource = nil
self.collectionView.delegate = nil
Expand Down Expand Up @@ -188,8 +177,8 @@ public final class PhotosInputView: UIView, PhotosInputViewProtocol {
return PhotosInputCameraPicker(presentingControllerProvider: self.presentingControllerProvider)
}()

fileprivate lazy var liveCameraPresenter: LiveCameraCellPresenter = {
return LiveCameraCellPresenter(cellAppearance: self.appearance?.liveCameraCellAppearence ?? LiveCameraCellAppearance.createDefaultAppearance())
fileprivate lazy var liveCameraPresenter: LiveCameraCellPresenterProtocol = {
return self.liveCameraCellPresenterFactory.makeLiveCameraCellPresenter()
}()
}

Expand All @@ -200,7 +189,7 @@ extension PhotosInputView: UICollectionViewDataSource {
self.collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: self.collectionViewLayout)
self.collectionView.backgroundColor = UIColor.white
self.collectionView.translatesAutoresizingMaskIntoConstraints = false
LiveCameraCellPresenter.registerCells(collectionView: self.collectionView)
self.liveCameraPresenter.registerCells(collectionView: self.collectionView)

self.collectionView.dataSource = self
self.collectionView.delegate = self
Expand Down
12 changes: 6 additions & 6 deletions ChattoAdditions/Tests/Input/LiveCameraCellPresenterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@ class LiveCameraCellPresenterTests: XCTestCase {
var presenter: LiveCameraCellPresenter!
var cell: LiveCameraCell!
var cameraAuthorizationStatus: AVAuthorizationStatus = .notDetermined
var cameraAuthorizationStatusProvider: LiveCameraCellPresenter.AVAuthorizationStatusProvider!

override func setUp() {
super.setUp()
self.cameraAuthorizationStatusProvider = { [unowned self] in
return self.cameraAuthorizationStatus
}
self.presenter = LiveCameraCellPresenter(authorizationStatusProvider: self.cameraAuthorizationStatusProvider)
self.presenter = {
let factory = LiveCameraCellPresenterFactory(
authorizationStatusProvider: { [unowned self] in return self.cameraAuthorizationStatus }
)
return factory.makeLiveCameraCellPresenter() as? LiveCameraCellPresenter
}()
self.cell = LiveCameraCell()
}

override func tearDown() {
self.presenter = nil
self.cell = nil
self.cameraAuthorizationStatusProvider = nil
super.tearDown()
}

Expand Down
4 changes: 4 additions & 0 deletions ChattoApp/Pods/Pods.xcodeproj/project.pbxproj

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.