Subclass InputBarView to allow picking images

This commit is contained in:
Mohannad Bakbouk
2020-12-25 10:06:52 -08:00
parent 155148dd8d
commit 413204156b
7 changed files with 312 additions and 4 deletions
@@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
032A15DD25965D9A00E00FE3 /* AlertService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 032A15DC25965D9A00E00FE3 /* AlertService.swift */; };
032A15E225965E1100E00FE3 /* CameraInputBarAccessoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 032A15E125965E1100E00FE3 /* CameraInputBarAccessoryView.swift */; };
13CCA04625793058005C19BB /* MessageKit in Frameworks */ = {isa = PBXBuildFile; productRef = 13CCA04525793058005C19BB /* MessageKit */; };
13CCA06325793E24005C19BB /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 13CCA06225793E24005C19BB /* Kingfisher */; };
1C5433DD24C389C300A5383B /* MessagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5433DC24C389C300A5383B /* MessagesView.swift */; };
@@ -62,6 +64,8 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
032A15DC25965D9A00E00FE3 /* AlertService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertService.swift; sourceTree = "<group>"; };
032A15E125965E1100E00FE3 /* CameraInputBarAccessoryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraInputBarAccessoryView.swift; sourceTree = "<group>"; };
13CCA04225793002005C19BB /* MessageKit */ = {isa = PBXFileReference; lastKnownFileType = folder; path = MessageKit; sourceTree = "<group>"; };
1C5433DC24C389C300A5383B /* MessagesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesView.swift; sourceTree = "<group>"; };
1C5433DE24C38DBF00A5383B /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
@@ -147,6 +151,7 @@
1C5433E024C3A32400A5383B /* SwiftUI */,
385C2920211FF32E0010B4BA /* CustomCell.swift */,
385C2921211FF32E0010B4BA /* TableViewCells.swift */,
032A15E125965E1100E00FE3 /* CameraInputBarAccessoryView.swift */,
);
path = Views;
sourceTree = "<group>";
@@ -175,6 +180,7 @@
385C292A211FF3450010B4BA /* Settings+UserDefaults.swift */,
385C292F211FF3630010B4BA /* UIColor+Extensions.swift */,
385C2930211FF3630010B4BA /* UIViewController+Extensions.swift */,
032A15DC25965D9A00E00FE3 /* AlertService.swift */,
);
path = Extensions;
sourceTree = "<group>";
@@ -516,6 +522,7 @@
385C2932211FF3630010B4BA /* UIViewController+Extensions.swift in Sources */,
385C292B211FF3450010B4BA /* Settings+UserDefaults.swift in Sources */,
385C2945211FF38F0010B4BA /* NavigationController.swift in Sources */,
032A15DD25965D9A00E00FE3 /* AlertService.swift in Sources */,
385C2948211FF38F0010B4BA /* ChatViewController.swift in Sources */,
385C2944211FF38F0010B4BA /* MessageContainerController.swift in Sources */,
383B9EB32172A1C4008AB91A /* MockUser.swift in Sources */,
@@ -525,6 +532,7 @@
1C5433DD24C389C300A5383B /* MessagesView.swift in Sources */,
882B5E811CF7D53600B6E160 /* AppDelegate.swift in Sources */,
385C292D211FF3520010B4BA /* CustomMessageFlowLayout.swift in Sources */,
032A15E225965E1100E00FE3 /* CameraInputBarAccessoryView.swift in Sources */,
38CCCC592258419300DD5482 /* AutocompleteExampleViewController.swift in Sources */,
63ECDAC2241889630016C349 /* MessageSubviewContainerViewController.swift in Sources */,
);
@@ -0,0 +1,52 @@
//
// AlertService.swift
// ChatExample
//
// Created by Mohannad on 12/25/20.
// Copyright © 2020 MessageKit. All rights reserved.
//
import Foundation
import UIKit
class AlertService {
static func showAlert(style: UIAlertController.Style, title: String?, message: String?, actions: [UIAlertAction] = [UIAlertAction(title: "Ok", style: .cancel, handler: nil)], completion: (() -> Swift.Void)? = nil) {
let alert = UIAlertController(title: title, message: message, preferredStyle: style)
for action in actions {
alert.addAction(action)
}
if let topVC = UIApplication.getTopMostViewController() {
alert.popoverPresentationController?.sourceView = topVC.view
alert.popoverPresentationController?.sourceRect = CGRect(x: topVC.view.bounds.midX, y: topVC.view.bounds.midY, width: 0, height: 0)
alert.popoverPresentationController?.permittedArrowDirections = []
topVC.present(alert, animated: true, completion: completion)
}
}
}
extension UIApplication {
class func getTopMostViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return getTopMostViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return getTopMostViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return getTopMostViewController(base: presented)
}
return base
}
}
@@ -1,6 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
}
@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "camera.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

@@ -105,7 +105,16 @@ final class AdvancedExampleViewController: ChatViewController {
}
override func configureMessageInputBar() {
super.configureMessageInputBar()
//super.configureMessageInputBar()
messageInputBar = CameraInputBarAccessoryView()
messageInputBar.delegate = self
messageInputBar.inputTextView.tintColor = .primaryColor
messageInputBar.sendButton.setTitleColor(.primaryColor, for: .normal)
messageInputBar.sendButton.setTitleColor(
UIColor.primaryColor.withAlphaComponent(0.3),
for: .highlighted)
messageInputBar.isTranslucent = true
messageInputBar.separatorLine.isHidden = true
@@ -439,3 +448,28 @@ extension AdvancedExampleViewController: MessagesLayoutDelegate {
}
}
extension AdvancedExampleViewController: CameraInputBarAccessoryViewDelegate {
func inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith attachments: [AttachmentManager.Attachment]) {
for item in attachments {
if case .image(let image) = item {
self.sendImageMessage(photo: image)
}
}
inputBar.invalidatePlugins()
}
func sendImageMessage( photo : UIImage) {
let photoMessage = MockMessage(image: photo, user: self.currentSender() as! MockUser, messageId: UUID().uuidString, date: Date())
self.insertMessage(photoMessage)
}
}
@@ -0,0 +1,193 @@
//
// CameraInput.swift
// ChatExample
//
// Created by Mohannad on 12/25/20.
// Copyright © 2020 MessageKit. All rights reserved.
//
import UIKit
import InputBarAccessoryView
protocol CameraInputBarAccessoryViewDelegate : InputBarAccessoryViewDelegate {
func inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith attachments: [AttachmentManager.Attachment])
}
extension CameraInputBarAccessoryViewDelegate {
func inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith attachments: [AttachmentManager.Attachment]){
}
}
class CameraInputBarAccessoryView: InputBarAccessoryView {
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var attachmentManager: AttachmentManager = { [unowned self] in
let manager = AttachmentManager()
manager.delegate = self
return manager
}()
func configure(){
let camera = makeButton(named: "camera")
camera.tintColor = .darkGray
camera.onTouchUpInside { (item) in
self.showImagePickerControllerActionSheet()
}
self.setLeftStackViewWidthConstant(to: 35, animated: true)
self.setStackViewItems([camera], forStack: .left, animated: false)
self.inputPlugins = [attachmentManager]
}
override func didSelectSendButton() {
if attachmentManager.attachments.count > 0 {
(delegate as? CameraInputBarAccessoryViewDelegate)?.inputBar(self, didPressSendButtonWith: attachmentManager.attachments)
}
else {
delegate?.inputBar(self, didPressSendButtonWith: inputTextView.text)
}
}
private func makeButton(named: String) -> InputBarButtonItem {
return InputBarButtonItem()
.configure {
$0.spacing = .fixed(10)
$0.image = UIImage(named: named)?.withRenderingMode(.alwaysTemplate)
$0.setSize(CGSize(width: 30, height: 30), animated: false)
}.onSelected {
$0.tintColor = .systemBlue
}.onDeselected {
$0.tintColor = UIColor.lightGray
}.onTouchUpInside { _ in
print("Item Tapped")
}
}
}
extension CameraInputBarAccessoryView : UIImagePickerControllerDelegate , UINavigationControllerDelegate {
@objc func showImagePickerControllerActionSheet() {
let photoLibraryAction = UIAlertAction(title: "Choose From Library", style: .default) { (action) in
self.showImagePickerController(sourceType: .photoLibrary)
}
let cameraAction = UIAlertAction(title: "Take From Camera", style: .default) { (action) in
self.showImagePickerController(sourceType: .camera)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .default , handler: nil)
AlertService.showAlert(style: .actionSheet, title: "Choose Your Image", message: nil, actions: [photoLibraryAction, cameraAction , cancelAction], completion: nil)
}
func showImagePickerController(sourceType: UIImagePickerController.SourceType){
let imgPicker = UIImagePickerController()
imgPicker.delegate = self
imgPicker.allowsEditing = true
imgPicker.sourceType = sourceType
inputAccessoryView?.isHidden = true
getRootViewController()?.present(imgPicker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let editedImage = info[ UIImagePickerController.InfoKey.editedImage] as? UIImage {
// self.sendImageMessage(photo: editedImage)
self.inputPlugins.forEach { _ = $0.handleInput(of: editedImage)}
}
else if let originImage = info[ UIImagePickerController.InfoKey.originalImage] as? UIImage {
self.inputPlugins.forEach { _ = $0.handleInput(of: originImage)}
//self.sendImageMessage(photo: originImage)
}
getRootViewController()?.dismiss(animated: true, completion: nil)
inputAccessoryView?.isHidden = false
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
getRootViewController()?.dismiss(animated: true, completion: nil)
inputAccessoryView?.isHidden = false
}
func getRootViewController() -> UIViewController? {
return (UIApplication.shared.delegate as? AppDelegate)?.window?.rootViewController
}
}
extension CameraInputBarAccessoryView: AttachmentManagerDelegate {
// MARK: - AttachmentManagerDelegate
func attachmentManager(_ manager: AttachmentManager, shouldBecomeVisible: Bool) {
setAttachmentManager(active: shouldBecomeVisible)
}
func attachmentManager(_ manager: AttachmentManager, didReloadTo attachments: [AttachmentManager.Attachment]) {
self.sendButton.isEnabled = manager.attachments.count > 0
}
func attachmentManager(_ manager: AttachmentManager, didInsert attachment: AttachmentManager.Attachment, at index: Int) {
self.sendButton.isEnabled = manager.attachments.count > 0
}
func attachmentManager(_ manager: AttachmentManager, didRemove attachment: AttachmentManager.Attachment, at index: Int) {
self.sendButton.isEnabled = manager.attachments.count > 0
}
func attachmentManager(_ manager: AttachmentManager, didSelectAddAttachmentAt index: Int) {
self.showImagePickerControllerActionSheet()
}
// MARK: - AttachmentManagerDelegate Helper
func setAttachmentManager(active: Bool) {
let topStackView = self.topStackView
if active && !topStackView.arrangedSubviews.contains(attachmentManager.attachmentView) {
topStackView.insertArrangedSubview(attachmentManager.attachmentView, at: topStackView.arrangedSubviews.count)
topStackView.layoutIfNeeded()
} else if !active && topStackView.arrangedSubviews.contains(attachmentManager.attachmentView) {
topStackView.removeArrangedSubview(attachmentManager.attachmentView)
topStackView.layoutIfNeeded()
}
}
}