Преглед на файлове

feat: update messagekit to 2.0

dignifiedquire преди 6 години
родител
ревизия
c0f298fa88
променени са 56 файла, в които са добавени 1845 реда и са изтрити 619 реда
  1. 1 1
      Podfile
  2. 8 4
      Podfile.lock
  3. 8 4
      Pods/Manifest.lock
  4. 21 0
      Pods/MessageInputBar/LICENSE.md
  5. 91 0
      Pods/MessageInputBar/README.md
  6. 13 7
      Pods/MessageInputBar/Sources/Controls/InputBarButtonItem.swift
  7. 73 0
      Pods/MessageInputBar/Sources/Extensions/NSMutableAttributedString+Extensions.swift
  8. 116 0
      Pods/MessageInputBar/Sources/Extensions/UIView+Extensions.swift
  9. 132 71
      Pods/MessageInputBar/Sources/MessageInputBar.swift
  10. 81 0
      Pods/MessageInputBar/Sources/Models/NSConstraintLayoutSet.swift
  11. 44 0
      Pods/MessageInputBar/Sources/Protocols/InputItem.swift
  12. 40 0
      Pods/MessageInputBar/Sources/Protocols/InputPlugin.swift
  13. 0 0
      Pods/MessageInputBar/Sources/Protocols/MessageInputBarDelegate.swift
  14. 1 1
      Pods/MessageInputBar/Sources/Views/InputStackView.swift
  15. 44 28
      Pods/MessageInputBar/Sources/Views/InputTextView.swift
  16. 1 0
      Pods/MessageInputBar/Sources/Views/SeparatorLine.swift
  17. 4 2
      Pods/MessageKit/README.md
  18. 56 18
      Pods/MessageKit/Sources/Controllers/MessagesViewController+Keyboard.swift
  19. 1 0
      Pods/MessageKit/Sources/Controllers/MessagesViewController+Menu.swift
  20. 23 4
      Pods/MessageKit/Sources/Controllers/MessagesViewController.swift
  21. 2 0
      Pods/MessageKit/Sources/Layout/CellSizeCalculator.swift
  22. 43 15
      Pods/MessageKit/Sources/Layout/MessageSizeCalculator.swift
  23. 46 8
      Pods/MessageKit/Sources/Layout/MessagesCollectionViewFlowLayout.swift
  24. 7 0
      Pods/MessageKit/Sources/Layout/MessagesCollectionViewLayoutAttributes.swift
  25. 55 0
      Pods/MessageKit/Sources/Models/HorizontalEdgeInsets.swift
  26. 3 3
      Pods/MessageKit/Sources/Models/MessageKind.swift
  27. 3 3
      Pods/MessageKit/Sources/Models/NSConstraintLayoutSet.swift
  28. 12 0
      Pods/MessageKit/Sources/Protocols/MessageCellDelegate.swift
  29. 15 2
      Pods/MessageKit/Sources/Protocols/MessagesDataSource.swift
  30. 14 0
      Pods/MessageKit/Sources/Protocols/MessagesDisplayDelegate.swift
  31. 15 1
      Pods/MessageKit/Sources/Protocols/MessagesLayoutDelegate.swift
  32. 6 4
      Pods/MessageKit/Sources/Views/AvatarView.swift
  33. 1 1
      Pods/MessageKit/Sources/Views/Cells/MessageCollectionViewCell.swift
  34. 40 3
      Pods/MessageKit/Sources/Views/Cells/MessageContentCell.swift
  35. 1 1
      Pods/MessageKit/Sources/Views/Headers & Footers/MessageReusableView.swift
  36. 32 5
      Pods/MessageKit/Sources/Views/MessageLabel.swift
  37. 8 1
      Pods/MessageKit/Sources/Views/MessagesCollectionView.swift
  38. 13 5
      Pods/MessageKit/Sources/Views/PlayButtonView.swift
  39. 533 418
      Pods/Pods.xcodeproj/project.pbxproj
  40. 26 0
      Pods/Target Support Files/MessageInputBar/Info.plist
  41. 5 0
      Pods/Target Support Files/MessageInputBar/MessageInputBar-dummy.m
  42. 12 0
      Pods/Target Support Files/MessageInputBar/MessageInputBar-prefix.pch
  43. 16 0
      Pods/Target Support Files/MessageInputBar/MessageInputBar-umbrella.h
  44. 6 0
      Pods/Target Support Files/MessageInputBar/MessageInputBar.modulemap
  45. 10 0
      Pods/Target Support Files/MessageInputBar/MessageInputBar.xcconfig
  46. 1 1
      Pods/Target Support Files/MessageKit/Info.plist
  47. 1 0
      Pods/Target Support Files/MessageKit/MessageKit.xcconfig
  48. 1 1
      Pods/Target Support Files/MessageKit/ResourceBundle-MessageKitAssets-Info.plist
  49. 25 0
      Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-acknowledgements.markdown
  50. 31 0
      Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-acknowledgements.plist
  51. 2 0
      Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-frameworks.sh
  52. 3 3
      Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios.debug.xcconfig
  53. 3 3
      Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios.release.xcconfig
  54. 2 0
      deltachat-ios.xcodeproj/project.pbxproj
  55. 91 0
      deltachat-ios.xcodeproj/xcshareddata/xcschemes/deltachat-ios.xcscheme
  56. 3 1
      deltachat-ios/ChatViewController.swift

+ 1 - 1
Podfile

@@ -1,7 +1,7 @@
 target 'deltachat-ios' do
   use_frameworks!
   pod 'openssl-ios-bitcode', '1.0.210'
-  pod 'MessageKit', '1.0.0'
+  pod 'MessageKit', '2.0.0'
   post_install do |installer|
       installer.pods_project.targets.each do |target|
           if target.name == 'MessageKit'

+ 8 - 4
Podfile.lock

@@ -1,20 +1,24 @@
 PODS:
-  - MessageKit (1.0.0)
+  - MessageInputBar/Core (0.4.1)
+  - MessageKit (2.0.0):
+    - MessageInputBar/Core
   - openssl-ios-bitcode (1.0.210)
 
 DEPENDENCIES:
-  - MessageKit (= 1.0.0)
+  - MessageKit (= 2.0.0)
   - openssl-ios-bitcode (= 1.0.210)
 
 SPEC REPOS:
   https://github.com/cocoapods/specs.git:
+    - MessageInputBar
     - MessageKit
     - openssl-ios-bitcode
 
 SPEC CHECKSUMS:
-  MessageKit: 16160036b16476b04bd0e9f2c7ce67e662e503e4
+  MessageInputBar: e81c7535347f1f7b923de7080409a535a004b6e4
+  MessageKit: 29c1c87e5a396d2ca7a3f712e5171dc9aba42a1e
   openssl-ios-bitcode: c833701a4488bd43de0051db41cfa75f6fef8109
 
-PODFILE CHECKSUM: dea2da329ab919c5c400d1fd104627f9904b3072
+PODFILE CHECKSUM: 738743efb43b4f6b89816b656cd3f132c9e93608
 
 COCOAPODS: 1.5.3

+ 8 - 4
Pods/Manifest.lock

@@ -1,20 +1,24 @@
 PODS:
-  - MessageKit (1.0.0)
+  - MessageInputBar/Core (0.4.1)
+  - MessageKit (2.0.0):
+    - MessageInputBar/Core
   - openssl-ios-bitcode (1.0.210)
 
 DEPENDENCIES:
-  - MessageKit (= 1.0.0)
+  - MessageKit (= 2.0.0)
   - openssl-ios-bitcode (= 1.0.210)
 
 SPEC REPOS:
   https://github.com/cocoapods/specs.git:
+    - MessageInputBar
     - MessageKit
     - openssl-ios-bitcode
 
 SPEC CHECKSUMS:
-  MessageKit: 16160036b16476b04bd0e9f2c7ce67e662e503e4
+  MessageInputBar: e81c7535347f1f7b923de7080409a535a004b6e4
+  MessageKit: 29c1c87e5a396d2ca7a3f712e5171dc9aba42a1e
   openssl-ios-bitcode: c833701a4488bd43de0051db41cfa75f6fef8109
 
-PODFILE CHECKSUM: dea2da329ab919c5c400d1fd104627f9904b3072
+PODFILE CHECKSUM: 738743efb43b4f6b89816b656cd3f132c9e93608
 
 COCOAPODS: 1.5.3

+ 21 - 0
Pods/MessageInputBar/LICENSE.md

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017-2018 MessageKit
+
+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.

+ 91 - 0
Pods/MessageInputBar/README.md

@@ -0,0 +1,91 @@
+<p>
+  <img src="https://raw.githubusercontent.com/MessageKit/MessageKit/master/Assets/mklogo.png" title="MessageKit logo">
+</p>
+
+[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
+<a href="https://swift.org">
+ <img src="https://img.shields.io/badge/Swift-4-orange.svg"
+      alt="Swift" />
+</a>
+<a href="https://cocoapods.org/">
+  <img src="https://cocoapod-badges.herokuapp.com/v/MessageInputBar/badge.png"
+      alt="CocoaPods">
+</a>
+<a href="https://developer.apple.com/xcode">
+  <img src="https://img.shields.io/badge/Xcode-9-blue.svg"
+      alt="Xcode">
+</a>
+<a href="https://opensource.org/licenses/MIT">
+  <img src="https://img.shields.io/badge/License-MIT-red.svg"
+      alt="MIT">
+</a>
+<a href="https://github.com/MessageKit/MessageInputBar/issues">
+   <img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat"
+        alt="Contributions Welcome">
+</a>
+
+## Installation
+
+### [CocoaPods](https://cocoapods.org/) **Recommended**
+````ruby
+pod 'MessageInputBar'
+````
+
+### [Carthage](https://github.com/Carthage/Carthage)
+
+To integrate MessageKit using Carthage, add the following to your `Cartfile`:
+
+````
+github "MessageKit/MessageInputBar"
+````
+
+## Requirements
+
+- **iOS 9** or later
+- **Swift 4** or later
+
+> Version 0.4.0 onwards is only Swift 4.2 compatible
+
+
+## Contributing
+
+Great! Look over these things first.
+- Please read our [Code of Conduct](https://github.com/MessageKit/MessageInputBar/blob/master/Code_of_Conduct.md)
+- Check the [Contributing Guide Lines](https://github.com/MessageKit/MessageInputBar/blob/master/CONTRIBUTING.md).
+- Come join us on [Slack](https://join.slack.com/t/messagekit/shared_invite/MjI4NzIzNzMyMzU0LTE1MDMwODIzMDUtYzllYzIyNTU4MA) and 🗣 don't be a stranger. 
+- Check out the [current issues](https://github.com/MessageKit/MessageInputBar/issues) and see if you can tackle any of those. 
+- Download the project and check out the current code base. Suggest any improvements by opening a new issue. 
+- Check out the [What's Next](#whats-next) section :point_down: to see where we are headed.
+- Check [StackOverflow](https://stackoverflow.com/questions/tagged/messagekit)
+- Install [SwiftLint](https://github.com/realm/SwiftLint) too keep yourself in :neckbeard: style. 
+- Be kind and helpful.  
+
+
+## What's Next?
+
+Check out the [Releases](https://github.com/MessageKit/MessageInputBar/releases) to see what we are working on next.
+
+## Contact
+
+Have a question or an issue about MessageKit? Create an [issue](https://github.com/MessageKit/MessageInputBar/issues/new)!
+
+Interested in contributing to MessageKit? Click here to join our [Slack](https://join.slack.com/t/messagekit/shared_invite/MjI4NzIzNzMyMzU0LTE1MDMwODIzMDUtYzllYzIyNTU4MA).
+
+### Apps using this library
+
+Add your app to the list of apps using this library and make a pull request.
+
+*Please provide attribution, it is greatly appreciated.*
+
+## MessageKit Core Team
+
+- [@SD10](https://github.com/sd10), Steven Deutsch
+- [@nathantannar4](https://github.com/nathantannar4), Nathan Tannar (MessageInputBar Maintainer)
+- [@zhongwuzw](https://github.com/zhongwuzw), Wu Zhong
+
+## Thanks
+
+Many thanks to [**the contributors**](https://github.com/MessageKit/MessageInputBar/graphs/contributors) of this project.
+
+## License
+MessageInputBar is released under the [MIT License](https://github.com/MessageKit/MessageInputBar/blob/master/LICENSE.md).

+ 13 - 7
Pods/MessageKit/Sources/Views/InputBarItem.swift → Pods/MessageInputBar/Sources/Controls/InputBarButtonItem.swift

@@ -25,12 +25,12 @@
 import UIKit
 
 /**
- A InputItem that inherits from UIButton
- 
+ A subclass of UIButton that conforms to InputItem
+
  ## Important Notes ##
  1. Intended to be used in an `InputStackView`
- */
-open class InputBarButtonItem: UIButton {
+*/
+open class InputBarButtonItem: UIButton, InputItem {
     
     /// The spacing properties of the InputBarButtonItem
     ///
@@ -108,12 +108,18 @@ open class InputBarButtonItem: UIButton {
     
     /// Calls the onSelectedAction or onDeselectedAction when set
     open override var isHighlighted: Bool {
-        didSet {
-            if isHighlighted {
+        get {
+            return super.isHighlighted
+        }
+        set {
+            guard newValue != isHighlighted else { return }
+            super.isHighlighted = newValue
+            if newValue {
                 onSelectedAction?(self)
             } else {
                 onDeselectedAction?(self)
             }
+            
         }
     }
     
@@ -317,7 +323,7 @@ open class InputBarButtonItem: UIButton {
     }
     
     /// An InputBarButtonItem that's spacing property is set to be .fixed with the width arguement
-    open class func fixedSpace(_ width: CGFloat) -> InputBarButtonItem {
+    public static func fixedSpace(_ width: CGFloat) -> InputBarButtonItem {
         let item = InputBarButtonItem()
         item.setSize(.zero, animated: false)
         item.spacing = .fixed(width)

+ 73 - 0
Pods/MessageInputBar/Sources/Extensions/NSMutableAttributedString+Extensions.swift

@@ -0,0 +1,73 @@
+/*
+ MIT License
+ 
+ Copyright (c) 2017-2018 MessageKit
+ 
+ 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 UIKit
+
+extension NSMutableAttributedString {
+ 
+    @discardableResult
+    internal func bold(_ text: String, fontSize: CGFloat = UIFont.preferredFont(forTextStyle: .body).pointSize, textColor: UIColor = .black) -> NSMutableAttributedString {
+        let attrs: [NSAttributedString.Key:AnyObject] = [
+            NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: fontSize),
+            NSAttributedString.Key.foregroundColor : textColor
+        ]
+        let boldString = NSMutableAttributedString(string: text, attributes: attrs)
+        self.append(boldString)
+        return self
+    }
+    
+    @discardableResult
+    internal func normal(_ text: String, fontSize: CGFloat = UIFont.preferredFont(forTextStyle: .body).pointSize, textColor: UIColor = .black) -> NSMutableAttributedString {
+        let attrs:[NSAttributedString.Key:AnyObject] = [
+            NSAttributedString.Key.font : UIFont.systemFont(ofSize: fontSize),
+            NSAttributedString.Key.foregroundColor : textColor
+        ]
+        let normal =  NSMutableAttributedString(string: text, attributes: attrs)
+        self.append(normal)
+        return self
+    }
+
+}
+
+extension NSAttributedString {
+
+    internal func replacingCharacters(in range: NSRange, with attributedString: NSAttributedString) -> NSMutableAttributedString {
+        let ns = NSMutableAttributedString(attributedString: self)
+        ns.replaceCharacters(in: range, with: attributedString)
+        return ns
+    }
+    
+    internal static func += (lhs: inout NSAttributedString, rhs: NSAttributedString) {
+        let ns = NSMutableAttributedString(attributedString: lhs)
+        ns.append(rhs)
+        lhs = ns
+    }
+    
+    internal static func + (lhs: NSAttributedString, rhs: NSAttributedString) -> NSAttributedString {
+        let ns = NSMutableAttributedString(attributedString: lhs)
+        ns.append(rhs)
+        return NSAttributedString(attributedString: ns)
+    }
+    
+}

+ 116 - 0
Pods/MessageInputBar/Sources/Extensions/UIView+Extensions.swift

@@ -0,0 +1,116 @@
+/*
+ MIT License
+ 
+ Copyright (c) 2017-2018 MessageKit
+ 
+ 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 UIKit
+
+extension UIView {
+    
+    internal func fillSuperview() {
+        guard let superview = self.superview else {
+            return
+        }
+        translatesAutoresizingMaskIntoConstraints = false
+
+	    let constraints: [NSLayoutConstraint] = [
+    	    leftAnchor.constraint(equalTo: superview.leftAnchor),
+    	    rightAnchor.constraint(equalTo: superview.rightAnchor),
+    	    topAnchor.constraint(equalTo: superview.topAnchor),
+    	    bottomAnchor.constraint(equalTo: superview.bottomAnchor)
+    	    ]
+	    NSLayoutConstraint.activate(constraints)
+    }
+
+    internal func centerInSuperview() {
+        guard let superview = self.superview else {
+            return
+        }
+        translatesAutoresizingMaskIntoConstraints = false
+        let constraints: [NSLayoutConstraint] = [
+            centerXAnchor.constraint(equalTo: superview.centerXAnchor),
+            centerYAnchor.constraint(equalTo: superview.centerYAnchor)
+        ]
+        NSLayoutConstraint.activate(constraints)
+    }
+    
+    internal func constraint(equalTo size: CGSize) {
+        guard superview != nil else { return }
+        translatesAutoresizingMaskIntoConstraints = false
+        let constraints: [NSLayoutConstraint] = [
+            widthAnchor.constraint(equalToConstant: size.width),
+            heightAnchor.constraint(equalToConstant: size.height)
+        ]
+        NSLayoutConstraint.activate(constraints)
+        
+    }
+
+    @discardableResult
+    internal func addConstraints(_ top: NSLayoutYAxisAnchor? = nil, left: NSLayoutXAxisAnchor? = nil, bottom: NSLayoutYAxisAnchor? = nil, right: NSLayoutXAxisAnchor? = nil, topConstant: CGFloat = 0, leftConstant: CGFloat = 0, bottomConstant: CGFloat = 0, rightConstant: CGFloat = 0, widthConstant: CGFloat = 0, heightConstant: CGFloat = 0) -> [NSLayoutConstraint] {
+        
+        if self.superview == nil {
+            return []
+        }
+        translatesAutoresizingMaskIntoConstraints = false
+        
+        var constraints = [NSLayoutConstraint]()
+        
+        if let top = top {
+            let constraint = topAnchor.constraint(equalTo: top, constant: topConstant)
+            constraint.identifier = "top"
+            constraints.append(constraint)
+        }
+        
+        if let left = left {
+            let constraint = leftAnchor.constraint(equalTo: left, constant: leftConstant)
+            constraint.identifier = "left"
+            constraints.append(constraint)
+        }
+        
+        if let bottom = bottom {
+            let constraint = bottomAnchor.constraint(equalTo: bottom, constant: -bottomConstant)
+            constraint.identifier = "bottom"
+            constraints.append(constraint)
+        }
+        
+        if let right = right {
+            let constraint = rightAnchor.constraint(equalTo: right, constant: -rightConstant)
+            constraint.identifier = "right"
+            constraints.append(constraint)
+        }
+        
+        if widthConstant > 0 {
+            let constraint = widthAnchor.constraint(equalToConstant: widthConstant)
+            constraint.identifier = "width"
+            constraints.append(constraint)
+        }
+        
+        if heightConstant > 0 {
+            let constraint = heightAnchor.constraint(equalToConstant: heightConstant)
+            constraint.identifier = "height"
+            constraints.append(constraint)
+        }
+        
+        NSLayoutConstraint.activate(constraints)
+        return constraints
+    }
+}

+ 132 - 71
Pods/MessageKit/Sources/Views/MessageInputBar.swift → Pods/MessageInputBar/Sources/MessageInputBar.swift

@@ -29,7 +29,7 @@ open class MessageInputBar: UIView {
     
     // MARK: - Properties
     
-    /// A delegate to broadcast notifications from the MessageInputBar
+    /// A delegate to broadcast notifications from the `MessageInputBar`
     open weak var delegate: MessageInputBarDelegate?
     
     /// The background UIView anchored to the bottom, left, and right of the MessageInputBar
@@ -37,7 +37,7 @@ open class MessageInputBar: UIView {
     open var backgroundView: UIView = {
         let view = UIView()
         view.translatesAutoresizingMaskIntoConstraints = false
-        view.backgroundColor = .inputBarGray
+        view.backgroundColor = UIColor(red: 247/255, green: 247/255, blue: 247/255, alpha: 1.0)
         return view
     }()
     
@@ -70,7 +70,7 @@ open class MessageInputBar: UIView {
                 blurView.fillSuperview()
             }
             blurView.isHidden = !isTranslucent
-            let color: UIColor = backgroundView.backgroundColor ?? .inputBarGray
+            let color: UIColor = backgroundView.backgroundColor ?? UIColor(red: 247/255, green: 247/255, blue: 247/255, alpha: 1.0)
             backgroundView.backgroundColor = isTranslucent ? color.withAlphaComponent(0.75) : color.withAlphaComponent(1.0)
         }
     }
@@ -117,31 +117,31 @@ open class MessageInputBar: UIView {
     public let bottomStackView = InputStackView(axis: .horizontal, spacing: 15)
     
     /// The InputTextView a user can input a message in
-    open lazy var inputTextView: InputTextView = {
-        let textView = InputTextView()
-        textView.translatesAutoresizingMaskIntoConstraints = false
-        textView.messageInputBar = self
-        return textView
+    open lazy var inputTextView: InputTextView = { [weak self] in
+        let inputTextView = InputTextView()
+        inputTextView.translatesAutoresizingMaskIntoConstraints = false
+        inputTextView.messageInputBar = self
+        return inputTextView
     }()
 
     /// A InputBarButtonItem used as the send button and initially placed in the rightStackView
     open var sendButton: InputBarButtonItem = {
         return InputBarButtonItem()
             .configure {
-                $0.setSize(CGSize(width: 52, height: 28), animated: false)
+                $0.setSize(CGSize(width: 52, height: 36), animated: false)
                 $0.isEnabled = false
                 $0.title = "Send"
-                $0.titleLabel?.font = UIFont.preferredFont(forTextStyle: .headline)
+                $0.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .bold)
             }.onTouchUpInside {
                 $0.messageInputBar?.didSelectSendButton()
         }
     }()
-
-    /// A boolean that determines whether the sendButton's `isEnabled` state should be managed automatically.
-    open var shouldManageSendButtonEnabledState = true
     
     /**
-     The anchor constants that inset the contentView
+     The anchor contants used by the InputStackView's and InputTextView to create padding
+     within the MessageInputBar
+     
+     ## Important Notes ##
      
      ````
      V:|...[InputStackView.top]-(padding.top)-[contentView]-(padding.bottom)-|
@@ -160,7 +160,7 @@ open class MessageInputBar: UIView {
      The anchor constants used by the top InputStackView
      
      ## Important Notes ##
-     1. The topStackViewPadding.bottom property is not used. Use padding.top to add separation
+     1. The topStackViewPadding.bottom property is not used. Use padding.top
      
      ````
      V:|-(topStackViewPadding.top)-[InputStackView.top]-(padding.top)-[InputTextView]-...|
@@ -208,10 +208,18 @@ open class MessageInputBar: UIView {
     /// improves the performance
     public private(set) var isOverMaxTextViewHeight = false
     
-    /// A boolean that determines if the maxTextViewHeight should be auto updated on device rotation
+    /// A boolean that when set as `TRUE` will always enable the `InputTextView` to be anchored to the
+    /// height of `maxTextViewHeight`
+    /// The default value is `FALSE`
+    public private(set) var shouldForceTextViewMaxHeight = false
+    
+    /// A boolean that determines if the `maxTextViewHeight` should be maintained automatically.
+    /// To control the maximum height of the view yourself, set this to `false`.
     open var shouldAutoUpdateMaxTextViewHeight = true
     
-    /// The maximum height that the InputTextView can reach
+    /// The maximum height that the InputTextView can reach.
+    /// This is set automatically when `shouldAutoUpdateMaxTextViewHeight` is true.
+    /// To control the height yourself, make sure to set `shouldAutoUpdateMaxTextViewHeight` to false.
     open var maxTextViewHeight: CGFloat = 0 {
         didSet {
             textViewHeightAnchor?.constant = maxTextViewHeight
@@ -219,6 +227,9 @@ open class MessageInputBar: UIView {
         }
     }
     
+    /// A boolean that determines whether the sendButton's `isEnabled` state should be managed automatically.
+    open var shouldManageSendButtonEnabledState = true
+    
     /// The height that will fit the current text in the InputTextView based on its current bounds
     public var requiredInputTextViewHeight: CGFloat {
         let maxTextViewSize = CGSize(width: inputTextView.bounds.width, height: .greatestFiniteMagnitude)
@@ -239,27 +250,30 @@ open class MessageInputBar: UIView {
         }
     }
     
+    /// Holds the InputPlugin plugins that can be used to extend the functionality of the MessageInputBar
+    open var plugins = [InputPlugin]()
+    
     /// The InputBarItems held in the leftStackView
-    public private(set) var leftStackViewItems: [InputBarButtonItem] = []
+    public private(set) var leftStackViewItems: [InputItem] = []
     
     /// The InputBarItems held in the rightStackView
-    public private(set) var rightStackViewItems: [InputBarButtonItem] = []
+    public private(set) var rightStackViewItems: [InputItem] = []
     
     /// The InputBarItems held in the bottomStackView
-    public private(set) var bottomStackViewItems: [InputBarButtonItem] = []
+    public private(set) var bottomStackViewItems: [InputItem] = []
     
     /// The InputBarItems held in the topStackView
-    public private(set) var topStackViewItems: [InputBarButtonItem] = []
+    public private(set) var topStackViewItems: [InputItem] = []
     
     /// The InputBarItems held to make use of their hooks but they are not automatically added to a UIStackView
-    open var nonStackViewItems: [InputBarButtonItem] = []
+    open var nonStackViewItems: [InputItem] = []
     
     /// Returns a flatMap of all the items in each of the UIStackViews
-    public var items: [InputBarButtonItem] {
-        return [leftStackViewItems, rightStackViewItems, bottomStackViewItems, nonStackViewItems].flatMap { $0 }
+    public var items: [InputItem] {
+        return [leftStackViewItems, rightStackViewItems, bottomStackViewItems, topStackViewItems, nonStackViewItems].flatMap { $0 }
     }
     
-    // MARK: - Auto-Layout Management
+    // MARK: - Auto-Layout Constraint Sets
     
     private var textViewLayoutSet: NSLayoutConstraintSet?
     private var textViewHeightAnchor: NSLayoutConstraint?
@@ -309,15 +323,17 @@ open class MessageInputBar: UIView {
     
     /// Adds the required notification observers
     private func setupObservers() {
-        
         NotificationCenter.default.addObserver(self,
-                                               selector: #selector(MessageInputBar.textViewDidChange),
+                                               selector: #selector(MessageInputBar.orientationDidChange),
+                                               name: UIDevice.orientationDidChangeNotification, object: nil)
+        NotificationCenter.default.addObserver(self,
+                                               selector: #selector(MessageInputBar.inputTextViewDidChange),
                                                name: UITextView.textDidChangeNotification, object: inputTextView)
         NotificationCenter.default.addObserver(self,
-                                               selector: #selector(MessageInputBar.textViewDidBeginEditing),
+                                               selector: #selector(MessageInputBar.inputTextViewDidBeginEditing),
                                                name: UITextView.textDidBeginEditingNotification, object: inputTextView)
         NotificationCenter.default.addObserver(self,
-                                               selector: #selector(MessageInputBar.textViewDidEndEditing),
+                                               selector: #selector(MessageInputBar.inputTextViewDidEndEditing),
                                                name: UITextView.textDidEndEditingNotification, object: inputTextView)
     }
     
@@ -335,12 +351,11 @@ open class MessageInputBar: UIView {
         setStackViewItems([sendButton], forStack: .right, animated: false)
     }
     
-    // swiftlint:disable function_body_length colon
     /// Sets up the initial constraints of each subview
     private func setupConstraints() {
         
         // The constraints within the MessageInputBar
-        separatorLine.addConstraints(topAnchor, left: leftAnchor, right: rightAnchor)
+        separatorLine.addConstraints(topAnchor, left: leftAnchor, right: rightAnchor, heightConstant: separatorLine.height)
         backgroundViewBottomAnchor = backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor)
         backgroundViewBottomAnchor?.isActive = true
         backgroundView.addConstraints(topStackView.bottomAnchor, left: leftAnchor, right: rightAnchor)
@@ -385,7 +400,7 @@ open class MessageInputBar: UIView {
             left:   leftStackView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 0),
             width:  leftStackView.widthAnchor.constraint(equalToConstant: leftStackViewWidthConstant)
         )
-
+        
         rightStackViewLayoutSet = NSLayoutConstraintSet(
             top:    rightStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0),
             bottom: rightStackView.bottomAnchor.constraint(equalTo: inputTextView.bottomAnchor, constant: 0),
@@ -401,7 +416,6 @@ open class MessageInputBar: UIView {
         )
         activateConstraints()
     }
-    // swiftlint:enable function_body_length colon
     
     /// Respect iPhone X safeAreaInsets
     /// Adds a constraint to anchor the bottomAnchor of the contentView to the window's safeAreaLayoutGuide.bottomAnchor
@@ -459,10 +473,7 @@ open class MessageInputBar: UIView {
         }
     }
     
-    // MARK: - Layout Helper Methods
-    
-    /// Calculates the correct intrinsicContentSize of the MessageInputBar. This takes into account the various padding edge
-    /// insets, InputTextView's height and top/bottom InputStackView's heights.
+    /// Calculates the correct intrinsicContentSize of the MessageInputBar
     ///
     /// - Returns: The required intrinsicContentSize
     open func calculateIntrinsicContentSize() -> CGSize {
@@ -473,11 +484,12 @@ open class MessageInputBar: UIView {
                 textViewHeightAnchor?.isActive = true
                 inputTextView.isScrollEnabled = true
                 isOverMaxTextViewHeight = true
+                inputTextView.layoutIfNeeded()
             }
             inputTextViewHeight = maxTextViewHeight
         } else {
             if isOverMaxTextViewHeight {
-                textViewHeightAnchor?.isActive = false
+                textViewHeightAnchor?.isActive = false || shouldForceTextViewMaxHeight
                 inputTextView.isScrollEnabled = false
                 isOverMaxTextViewHeight = false
                 inputTextView.invalidateIntrinsicContentSize()
@@ -493,6 +505,7 @@ open class MessageInputBar: UIView {
         return CGSize(width: bounds.width, height: requiredHeight)
     }
     
+    
     /// Returns the max height the InputTextView can grow to based on the UIScreen
     ///
     /// - Returns: Max Height
@@ -503,13 +516,14 @@ open class MessageInputBar: UIView {
         return (UIScreen.main.bounds.height / 5).rounded(.down)
     }
     
+    // MARK: - Layout Helper Methods
+    
     /// Layout the given InputStackView's
     ///
-    /// - Parameter positions: The UIStackView's to layout
+    /// - Parameter positions: The InputStackView's to layout
     public func layoutStackViews(_ positions: [InputStackView.Position] = [.left, .right, .bottom, .top]) {
         
         guard superview != nil else { return }
-        
         for position in positions {
             switch position {
             case .left:
@@ -532,7 +546,7 @@ open class MessageInputBar: UIView {
     ///
     /// - Parameters:
     ///   - animated: If the layout should be animated
-    ///   - animations: Code
+    ///   - animations: Animation logic
     internal func performLayout(_ animated: Bool, _ animations: @escaping () -> Void) {
         deactivateConstraints()
         if animated {
@@ -565,16 +579,14 @@ open class MessageInputBar: UIView {
         topStackViewLayoutSet?.deactivate()
     }
     
-    // MARK: - UIStackView InputBarItem Methods
-    
-    // swiftlint:disable function_body_length
-    /// Removes all of the arranged subviews from the UIStackView and adds the given items. Sets the messageInputBar property of the InputBarButtonItem
+    /// Removes all of the arranged subviews from the InputStackView and adds the given items.
+    /// Sets the messageInputBar property of the InputBarButtonItem
     ///
     /// - Parameters:
-    ///   - items: New UIStackView arranged views
-    ///   - position: The targeted UIStackView
+    ///   - items: New InputStackView arranged views
+    ///   - position: The targeted InputStackView
     ///   - animated: If the layout should be animated
-    open func setStackViewItems(_ items: [InputBarButtonItem], forStack position: InputStackView.Position, animated: Bool) {
+    open func setStackViewItems(_ items: [InputItem], forStack position: InputStackView.Position, animated: Bool) {
         
         func setNewItems() {
             switch position {
@@ -584,7 +596,9 @@ open class MessageInputBar: UIView {
                 leftStackViewItems.forEach {
                     $0.messageInputBar = self
                     $0.parentStackViewPosition = position
-                    leftStackView.addArrangedSubview($0)
+                    if let view = $0 as? UIView {
+                        leftStackView.addArrangedSubview(view)
+                    }
                 }
                 guard superview != nil else { return }
                 leftStackView.layoutIfNeeded()
@@ -594,7 +608,9 @@ open class MessageInputBar: UIView {
                 rightStackViewItems.forEach {
                     $0.messageInputBar = self
                     $0.parentStackViewPosition = position
-                    rightStackView.addArrangedSubview($0)
+                    if let view = $0 as? UIView {
+                        rightStackView.addArrangedSubview(view)
+                    }
                 }
                 guard superview != nil else { return }
                 rightStackView.layoutIfNeeded()
@@ -604,7 +620,9 @@ open class MessageInputBar: UIView {
                 bottomStackViewItems.forEach {
                     $0.messageInputBar = self
                     $0.parentStackViewPosition = position
-                    bottomStackView.addArrangedSubview($0)
+                    if let view = $0 as? UIView {
+                        bottomStackView.addArrangedSubview(view)
+                    }
                 }
                 guard superview != nil else { return }
                 bottomStackView.layoutIfNeeded()
@@ -614,7 +632,9 @@ open class MessageInputBar: UIView {
                 topStackViewItems.forEach {
                     $0.messageInputBar = self
                     $0.parentStackViewPosition = position
-                    topStackView.addArrangedSubview($0)
+                    if let view = $0 as? UIView {
+                        topStackView.addArrangedSubview(view)
+                    }
                 }
                 guard superview != nil else { return }
                 topStackView.layoutIfNeeded()
@@ -626,7 +646,6 @@ open class MessageInputBar: UIView {
             setNewItems()
         }
     }
-    // swiftlint:enable function_body_length
     
     /// Sets the leftStackViewWidthConstant
     ///
@@ -637,8 +656,8 @@ open class MessageInputBar: UIView {
         performLayout(animated) {
             self.leftStackViewWidthConstant = newValue
             self.layoutStackViews([.left])
-            guard self.superview != nil else { return }
-            self.layoutIfNeeded()
+            guard self.superview?.superview != nil else { return }
+            self.superview?.superview?.layoutIfNeeded()
         }
     }
     
@@ -651,8 +670,22 @@ open class MessageInputBar: UIView {
         performLayout(animated) {
             self.rightStackViewWidthConstant = newValue
             self.layoutStackViews([.right])
-            guard self.superview != nil else { return }
-            self.layoutIfNeeded()
+            guard self.superview?.superview != nil else { return }
+            self.superview?.superview?.layoutIfNeeded()
+        }
+    }
+    
+    /// Sets the `shouldForceTextViewMaxHeight` property
+    ///
+    /// - Parameters:
+    ///   - newValue: New boolean value
+    ///   - animated: If the layout should be animated
+    open func setShouldForceMaxTextViewHeight(to newValue: Bool, animated: Bool) {
+        performLayout(animated) {
+            self.shouldForceTextViewMaxHeight = newValue
+            self.textViewHeightAnchor?.isActive = newValue
+            guard self.superview?.superview != nil else { return }
+            self.superview?.superview?.layoutIfNeeded()
         }
     }
     
@@ -664,52 +697,80 @@ open class MessageInputBar: UIView {
         if traitCollection.verticalSizeClass != previousTraitCollection?.verticalSizeClass || traitCollection.horizontalSizeClass != previousTraitCollection?.horizontalSizeClass {
             if shouldAutoUpdateMaxTextViewHeight {
                 maxTextViewHeight = calculateMaxTextViewHeight()
+            } else {
+                invalidateIntrinsicContentSize()
             }
-            invalidateIntrinsicContentSize()
         }
     }
     
+    /// Invalidates the intrinsicContentSize
+    @objc
+    open func orientationDidChange() {
+        if shouldAutoUpdateMaxTextViewHeight {
+            maxTextViewHeight = calculateMaxTextViewHeight()
+        }
+        invalidateIntrinsicContentSize()
+    }
+    
     /// Enables/Disables the sendButton based on the InputTextView's text being empty
     /// Calls each items `textViewDidChangeAction` method
     /// Calls the delegates `textViewTextDidChangeTo` method
     /// Invalidates the intrinsicContentSize
     @objc
-    open func textViewDidChange() {
+    open func inputTextViewDidChange() {
+        
         let trimmedText = inputTextView.text.trimmingCharacters(in: .whitespacesAndNewlines)
-
+        
         if shouldManageSendButtonEnabledState {
-            sendButton.isEnabled = !trimmedText.isEmpty || inputTextView.images.count > 0
+            var isEnabled = !trimmedText.isEmpty
+            if !isEnabled {
+                // The images property is more resource intensive so only use it if needed
+                isEnabled = inputTextView.images.count > 0
+            }
+            sendButton.isEnabled = isEnabled
         }
-        inputTextView.placeholderLabel.isHidden = !inputTextView.text.isEmpty
-
-        items.forEach { $0.textViewDidChangeAction(with: inputTextView) }
-
+        
+        // Capture change before iterating over the InputItem's
+        let shouldInvalidateIntrinsicContentSize = requiredInputTextViewHeight != inputTextView.bounds.height
+        
+        items.forEach { $0.textViewDidChangeAction(with: self.inputTextView) }
         delegate?.messageInputBar(self, textViewTextDidChangeTo: trimmedText)
         
-        if requiredInputTextViewHeight != inputTextView.bounds.height {
+        if shouldInvalidateIntrinsicContentSize {
             // Prevent un-needed content size invalidation
             invalidateIntrinsicContentSize()
         }
     }
     
     /// Calls each items `keyboardEditingBeginsAction` method
-    /// Invalidates the intrinsicContentSize so that the keyboard does not overlap the view
     @objc
-    open func textViewDidBeginEditing() {
+    open func inputTextViewDidBeginEditing() {
         items.forEach { $0.keyboardEditingBeginsAction() }
     }
     
     /// Calls each items `keyboardEditingEndsAction` method
     @objc
-    open func textViewDidEndEditing() {
+    open func inputTextViewDidEndEditing() {
         items.forEach { $0.keyboardEditingEndsAction() }
     }
     
-    // MARK: - User Actions
+    // MARK: - Plugins
     
+    /// Reloads each of the plugins
+    open func reloadPlugins() {
+        plugins.forEach { $0.reloadData() }
+    }
+    
+    /// Invalidates each of the plugins
+    open func invalidatePlugins() {
+        plugins.forEach { $0.invalidate() }
+    }
+    
+    // MARK: - User Actions
+
     /// Calls the delegates `didPressSendButtonWith` method
     /// Assumes that the InputTextView's text has been set to empty and calls `inputTextViewDidChange()`
-    /// Invalidates each of the inputManagers
+    /// Invalidates each of the InputPlugins
     open func didSelectSendButton() {
         delegate?.messageInputBar(self, didPressSendButtonWith: inputTextView.text)
     }

+ 81 - 0
Pods/MessageInputBar/Sources/Models/NSConstraintLayoutSet.swift

@@ -0,0 +1,81 @@
+/*
+ MIT License
+ 
+ Copyright (c) 2017-2018 MessageKit
+ 
+ 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 UIKit
+
+internal class NSLayoutConstraintSet {
+    
+    internal var top: NSLayoutConstraint?
+    internal var bottom: NSLayoutConstraint?
+    internal var left: NSLayoutConstraint?
+    internal var right: NSLayoutConstraint?
+    internal var centerX: NSLayoutConstraint?
+    internal var centerY: NSLayoutConstraint?
+    internal var width: NSLayoutConstraint?
+    internal var height: NSLayoutConstraint?
+    
+    internal init(top: NSLayoutConstraint? = nil, bottom: NSLayoutConstraint? = nil,
+                left: NSLayoutConstraint? = nil, right: NSLayoutConstraint? = nil,
+                centerX: NSLayoutConstraint? = nil, centerY: NSLayoutConstraint? = nil,
+                width: NSLayoutConstraint? = nil, height: NSLayoutConstraint? = nil) {
+        self.top = top
+        self.bottom = bottom
+        self.left = left
+        self.right = right
+        self.centerX = centerX
+        self.centerY = centerY
+        self.width = width
+        self.height = height
+    }
+
+    /// All of the currently configured constraints
+    private var availableConstraints: [NSLayoutConstraint] {
+        let constraints = [top, bottom, left, right, centerX, centerY, width, height]
+        var available: [NSLayoutConstraint] = []
+        for constraint in constraints {
+            if let value = constraint {
+                available.append(value)
+            }
+        }
+        return available
+    }
+    
+    /// Activates all of the non-nil constraints
+    ///
+    /// - Returns: Self
+    @discardableResult
+    internal func activate() -> Self {
+        NSLayoutConstraint.activate(availableConstraints)
+        return self
+    }
+    
+    /// Deactivates all of the non-nil constraints
+    ///
+    /// - Returns: Self
+    @discardableResult
+    internal func deactivate() -> Self {
+        NSLayoutConstraint.deactivate(availableConstraints)
+        return self
+    }
+}

+ 44 - 0
Pods/MessageInputBar/Sources/Protocols/InputItem.swift

@@ -0,0 +1,44 @@
+/*
+ MIT License
+ 
+ Copyright (c) 2017-2018 MessageKit
+ 
+ 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 UIKit
+
+/// InputItem is a protocol that links elements to the MessageInputBar to make them reactive
+public protocol InputItem: AnyObject {
+    
+    /// A reference to the MessageInputBar. Set automatically when inserted into an InputStackView
+    var messageInputBar: MessageInputBar? { get set }
+    
+    /// A reference to the InputStackView that the InputItem is contained in. Set when inserted into an InputStackView
+    var parentStackViewPosition: InputStackView.Position? { get set }
+    
+    /// A hook that is called when the InputTextView's text is changed
+    func textViewDidChangeAction(with textView: InputTextView)
+    
+    /// A hook that is called when the InputTextView is resigned as the first responder
+    func keyboardEditingEndsAction()
+    
+    /// A hook that is called when the InputTextView is made the first responder
+    func keyboardEditingBeginsAction()
+}

+ 40 - 0
Pods/MessageInputBar/Sources/Protocols/InputPlugin.swift

@@ -0,0 +1,40 @@
+/*
+ MIT License
+ 
+ Copyright (c) 2017-2018 MessageKit
+ 
+ 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 UIKit
+
+/// `InputPlugin` is a protocol that makes integrating plugins to the `MessageInputBar` easy.
+public protocol InputPlugin: AnyObject {
+    
+    /// Should reload the state if the `InputPlugin`
+    func reloadData()
+    
+    /// Should remove any content that the `InputPlugin` is managing
+    func invalidate()
+    
+    /// Should handle the input of data types that an `InputPlugin` manages
+    ///
+    /// - Parameter object: The object to input
+    func handleInput(of object: AnyObject) -> Bool
+}

+ 0 - 0
Pods/MessageKit/Sources/Protocols/MessageInputBarDelegate.swift → Pods/MessageInputBar/Sources/Protocols/MessageInputBarDelegate.swift


+ 1 - 1
Pods/MessageKit/Sources/Views/InputStackView.swift → Pods/MessageInputBar/Sources/Views/InputStackView.swift

@@ -25,7 +25,7 @@
 import UIKit
 
 /**
- A UIStackView that's intended for holding `InputBarButtonItem`s
+ A UIStackView that's intended for holding `InputItem`s
  
  ## Important Notes ##
  1. Default alignment is .fill

+ 44 - 28
Pods/MessageKit/Sources/Views/InputTextView.swift → Pods/MessageInputBar/Sources/Views/InputTextView.swift

@@ -25,7 +25,7 @@
 import UIKit
 
 /**
- A UITextView that has a UILabel embedded for placeholder text
+ A `UITextView` that has a `UILabel` embedded for placeholder text
  
  ## Important Notes ##
  1. Changing the font, textAlignment or textContainerInset automatically performs the same modifications to the placeholderLabel
@@ -40,18 +40,16 @@ open class InputTextView: UITextView {
     open override var text: String! {
         didSet {
             postTextViewDidChangeNotification()
-            placeholderLabel.isHidden = !text.isEmpty
         }
     }
     
     open override var attributedText: NSAttributedString! {
         didSet {
             postTextViewDidChangeNotification()
-            placeholderLabel.isHidden = !text.isEmpty
         }
     }
     
-    /// The images that are currently stored as NSTextAttachment's
+    /// The images that are currently stored as `NSTextAttachment`'s
     open var images: [UIImage] {
         return parseForAttachedImages()
     }
@@ -62,7 +60,7 @@ open class InputTextView: UITextView {
     
     open var isImagePasteEnabled: Bool = true
     
-    /// A UILabel that holds the InputTextView's placeholder text
+    /// A UILabel that holds the `InputTextView`'s placeholder text
     public let placeholderLabel: UILabel = {
         let label = UILabel()
         label.numberOfLines = 0
@@ -87,27 +85,34 @@ open class InputTextView: UITextView {
         }
     }
     
-    /// The UIEdgeInsets the placeholderLabel has within the InputTextView
-    open var placeholderLabelInsets: UIEdgeInsets = UIEdgeInsets(top: 4, left: 7, bottom: 4, right: 7) {
+    /// The `UIEdgeInsets` the placeholderLabel has within the `InputTextView`
+    open var placeholderLabelInsets: UIEdgeInsets = UIEdgeInsets(top: 8, left: 4, bottom: 8, right: 4)  {
         didSet {
             updateConstraintsForPlaceholderLabel()
         }
     }
     
-    /// The font of the InputTextView. When set the placeholderLabel's font is also updated
+    /// The font of the `InputTextView`. When set the placeholderLabel's font is also updated
     open override var font: UIFont! {
         didSet {
             placeholderLabel.font = font
         }
     }
     
-    /// The textAlignment of the InputTextView. When set the placeholderLabel's textAlignment is also updated
+    /// The `textAlignment` of the `InputTextView`. When set the placeholderLabel's `textAlignment` is also updated
     open override var textAlignment: NSTextAlignment {
         didSet {
             placeholderLabel.textAlignment = textAlignment
         }
     }
     
+    /// The textContainerInset of the `InputTextView`. When set the placeholderLabelInsets is also updated
+    open override var textContainerInset: UIEdgeInsets {
+        didSet {
+            placeholderLabelInsets = textContainerInset
+        }
+    }
+    
     open override var scrollIndicatorInsets: UIEdgeInsets {
         didSet {
             // When .zero a rendering issue can occur
@@ -120,7 +125,7 @@ open class InputTextView: UITextView {
         }
     }
     
-    /// A weak reference to the MessageInputBar that the InputTextView is contained within
+    /// A weak reference to the `MessageInputBar` that the `InputTextView` is contained within
     open weak var messageInputBar: MessageInputBar?
     
     /// The constraints of the placeholderLabel
@@ -151,25 +156,20 @@ open class InputTextView: UITextView {
     /// Sets up the default properties
     open func setup() {
         
+        backgroundColor = .clear
         font = UIFont.preferredFont(forTextStyle: .body)
-        textContainerInset = UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 4)
+        isScrollEnabled = false
         scrollIndicatorInsets = UIEdgeInsets(top: .leastNonzeroMagnitude,
                                              left: .leastNonzeroMagnitude,
                                              bottom: .leastNonzeroMagnitude,
                                              right: .leastNonzeroMagnitude)
-        isScrollEnabled = false
-        layer.cornerRadius = 5.0
-        layer.borderWidth = 1.25
-        layer.borderColor = UIColor.lightGray.cgColor
-        allowsEditingTextAttributes = false
         setupPlaceholderLabel()
         setupObservers()
     }
-    
-    // swiftlint:disable colon
+
     /// Adds the placeholderLabel to the view and sets up its initial constraints
     private func setupPlaceholderLabel() {
-        
+
         addSubview(placeholderLabel)
         placeholderLabelConstraintSet = NSLayoutConstraintSet(
             top:     placeholderLabel.topAnchor.constraint(equalTo: topAnchor, constant: placeholderLabelInsets.top),
@@ -178,12 +178,11 @@ open class InputTextView: UITextView {
             right:   placeholderLabel.rightAnchor.constraint(equalTo: rightAnchor, constant: -placeholderLabelInsets.right),
             centerX: placeholderLabel.centerXAnchor.constraint(equalTo: centerXAnchor),
             centerY: placeholderLabel.centerYAnchor.constraint(equalTo: centerYAnchor)
-            )
+        )
         placeholderLabelConstraintSet?.centerX?.priority = .defaultLow
         placeholderLabelConstraintSet?.centerY?.priority = .defaultLow
         placeholderLabelConstraintSet?.activate()
     }
-    // swiftlint:enable colon
     
     /// Adds the required notification observers
     private func setupObservers() {
@@ -191,23 +190,32 @@ open class InputTextView: UITextView {
         NotificationCenter.default.addObserver(self,
                                                selector: #selector(InputTextView.redrawTextAttachments),
                                                name: UIDevice.orientationDidChangeNotification, object: nil)
+        NotificationCenter.default.addObserver(self,
+                                               selector: #selector(InputTextView.textViewTextDidChange),
+                                               name: UITextView.textDidChangeNotification, object: nil)
     }
     
     /// Updates the placeholderLabels constraint constants to match the placeholderLabelInsets
     private func updateConstraintsForPlaceholderLabel() {
-        
+
         placeholderLabelConstraintSet?.top?.constant = placeholderLabelInsets.top
         placeholderLabelConstraintSet?.bottom?.constant = -placeholderLabelInsets.bottom
         placeholderLabelConstraintSet?.left?.constant = placeholderLabelInsets.left
         placeholderLabelConstraintSet?.right?.constant = -placeholderLabelInsets.right
     }
     
+    
     // MARK: - Notification
     
     private func postTextViewDidChangeNotification() {
         NotificationCenter.default.post(name: UITextView.textDidChangeNotification, object: self)
     }
     
+    @objc
+    private func textViewTextDidChange() {
+        placeholderLabel.isHidden = !text.isEmpty
+    }
+    
     // MARK: - Image Paste Support
     
     open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
@@ -223,14 +231,22 @@ open class InputTextView: UITextView {
         guard let image = UIPasteboard.general.image else {
             return super.paste(sender)
         }
-        pasteImageInTextContainer(with: image)
+        if isImagePasteEnabled {
+            pasteImageInTextContainer(with: image)
+        } else {
+            for plugin in messageInputBar?.plugins ?? [] {
+                if plugin.handleInput(of: image) {
+                    return
+                }
+            }
+        }
     }
     
     /// Addes a new UIImage to the NSTextContainer as an NSTextAttachment
     ///
     /// - Parameter image: The image to add
     private func pasteImageInTextContainer(with image: UIImage) {
-
+        
         // Add the new image as an NSTextAttachment
         let attributedImageString = NSAttributedString(attachment: textAttachment(using: image))
         
@@ -247,7 +263,7 @@ open class InputTextView: UITextView {
         let attributes: [NSAttributedString.Key: Any] = [
             NSAttributedString.Key.font: font ?? UIFont.preferredFont(forTextStyle: .body),
             NSAttributedString.Key.foregroundColor: textColor ?? .black
-            ]
+        ]
         newAttributedStingComponent.addAttributes(attributes, range: NSRange(location: 0, length: newAttributedStingComponent.length))
         
         textStorage.beginEditing()
@@ -258,9 +274,9 @@ open class InputTextView: UITextView {
         // Advance the range to the selected range plus the number of characters added
         let location = selectedRange.location + (isEmpty ? 2 : 3)
         selectedRange = NSRange(location: location, length: 0)
-    
+        
         // Broadcast a notification to recievers such as the MessageInputBar which will handle resizing
-        NotificationCenter.default.post(name: UITextView.textDidChangeNotification, object: self)
+        postTextViewDidChangeNotification()
     }
     
     /// Returns an NSTextAttachment the provided image that will fit inside the NSTextContainer
@@ -348,7 +364,7 @@ open class InputTextView: UITextView {
                 }
             }
         }
-
+        
         return components
     }
     

+ 1 - 0
Pods/MessageKit/Sources/Views/SeparatorLine.swift → Pods/MessageInputBar/Sources/Views/SeparatorLine.swift

@@ -39,6 +39,7 @@ open class SeparatorLine: UIView {
     /// The height of the line
     open var height: CGFloat = 1.0 {
         didSet {
+            constraints.filter { $0.identifier == "height" }.forEach { $0.constant = height } // Assumes constraint was given an identifier
             invalidateIntrinsicContentSize()
         }
     }

+ 4 - 2
Pods/MessageKit/README.md

@@ -31,7 +31,7 @@
 * [**Goal**](#goals)📈
 * [**Contributing**](#contributing)
 * [**Requirements**](#requirements)
-* [**Code of Conduct**](https://github.com/MessageKit/MessageKit/blob/master/Code_of_Conduct.md)
+* [**Code of Conduct**](https://github.com/MessageKit/MessageKit/blob/master/CODE_OF_CONDUCT.md)
 * [**What's Next**](#whats-next)
 * [**Contact**](#contact)
 * [**Apps using this library**](#apps-using-this-library)
@@ -90,7 +90,7 @@ github "MessageKit/MessageKit"
 ## Contributing
 
 Great! Look over these things first.
-- Please read our [Code of Conduct](https://github.com/MessageKit/MessageKit/blob/master/Code_of_Conduct.md)
+- Please read our [Code of Conduct](https://github.com/MessageKit/MessageKit/blob/master/CODE_OF_CONDUCT.md)
 - Check the [Contributing Guide Lines](https://github.com/MessageKit/MessageKit/blob/master/CONTRIBUTING.md).
 - Come join us on [Slack](https://join.slack.com/t/messagekit/shared_invite/MjI4NzIzNzMyMzU0LTE1MDMwODIzMDUtYzllYzIyNTU4MA) and 🗣 don't be a stranger. 
 - Check out the [current issues](https://github.com/MessageKit/MessageKit/issues) and see if you can tackle any of those. 
@@ -116,6 +116,8 @@ Interested in contributing to MessageKit? Click here to join our [Slack](https:/
 Add your app to the list of apps using this library and make a pull request.
 
 - [MediQuo](https://www.mediquo.com)
+- [RappresentaMe](https://itunes.apple.com/it/app/rappresentame/id1330914443)
+- [WiseEyes](https://itunes.apple.com/us/app/wiseeyes/id1391408511?mt=8)
 
 *Please provide attribution, it is greatly appreciated.*
 

+ 56 - 18
Pods/MessageKit/Sources/Controllers/MessagesViewController+Keyboard.swift

@@ -23,6 +23,7 @@
  */
 
 import Foundation
+import MessageInputBar
 
 extension MessagesViewController {
 
@@ -31,7 +32,7 @@ extension MessagesViewController {
     internal func addKeyboardObservers() {
         NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.handleKeyboardDidChangeState(_:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.handleTextViewDidBeginEditing(_:)), name: UITextView.textDidBeginEditingNotification, object: nil)
-        NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.adjustScrollViewInset), name: UIDevice.orientationDidChangeNotification, object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.adjustScrollViewTopInset), name: UIDevice.orientationDidChangeNotification, object: nil)
     }
 
     internal func removeKeyboardObservers() {
@@ -44,7 +45,7 @@ extension MessagesViewController {
 
     @objc
     private func handleTextViewDidBeginEditing(_ notification: Notification) {
-        if scrollsToBottomOnKeybordBeginsEditing {
+        if scrollsToBottomOnKeyboardBeginsEditing {
             guard let inputTextView = notification.object as? InputTextView, inputTextView === messageInputBar.inputTextView else { return }
             messagesCollectionView.scrollToBottom(animated: true)
         }
@@ -52,12 +53,35 @@ extension MessagesViewController {
 
     @objc
     private func handleKeyboardDidChangeState(_ notification: Notification) {
-        guard let keyboardEndFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
-        
         guard !isMessagesControllerBeingDismissed else { return }
+
+        guard let keyboardStartFrameInScreenCoords = notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? CGRect else { return }
+        guard !keyboardStartFrameInScreenCoords.isEmpty else {
+            // WORKAROUND for what seems to be a bug in iPad's keyboard handling in iOS 11: we receive an extra spurious frame change
+            // notification when undocking the keyboard, with a zero starting frame and an incorrect end frame. The workaround is to
+            // ignore this notification.
+            return
+        }
         
-        let newBottomInset = view.frame.height - keyboardEndFrame.minY - iPhoneXBottomInset
+        // Note that the check above does not exclude all notifications from an undocked keyboard, only the weird ones.
+        //
+        // We've tried following Apple's recommended approach of tracking UIKeyboardWillShow / UIKeyboardDidHide and ignoring frame
+        // change notifications while the keyboard is hidden or undocked (undocked keyboard is considered hidden by those events).
+        // Unfortunately, we do care about the difference between hidden and undocked, because we have an input bar which is at the
+        // bottom when the keyboard is hidden, and is tied to the keyboard when it's undocked.
+        //
+        // If we follow what Apple recommends and ignore notifications while the keyboard is hidden/undocked, we get an extra inset
+        // at the bottom when the undocked keyboard is visible (the inset that tries to compensate for the missing input bar).
+        // (Alternatives like setting newBottomInset to 0 or to the height of the input bar don't work either.)
+        //
+        // We could make it work by adding extra checks for the state of the keyboard and compensating accordingly, but it seems easier
+        // to simply check whether the current keyboard frame, whatever it is (even when undocked), covers the bottom of the collection
+        // view.
         
+        guard let keyboardEndFrameInScreenCoords = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
+        let keyboardEndFrame = view.convert(keyboardEndFrameInScreenCoords, from: view.window)
+        
+        let newBottomInset = requiredScrollViewBottomInset(forKeyboardFrame: keyboardEndFrame)
         let differenceOfBottomInset = newBottomInset - messageCollectionViewBottomInset
         
         if maintainPositionOnKeyboardFrameChanged && differenceOfBottomInset != 0 {
@@ -68,8 +92,10 @@ extension MessagesViewController {
         messageCollectionViewBottomInset = newBottomInset
     }
 
+    // MARK: - Inset Computation
+
     @objc
-    internal func adjustScrollViewInset() {
+    internal func adjustScrollViewTopInset() {
         if #available(iOS 11.0, *) {
             // No need to add to the top contentInset
         } else {
@@ -81,23 +107,35 @@ extension MessagesViewController {
         }
     }
 
-    // MARK: - Helpers
+    private func requiredScrollViewBottomInset(forKeyboardFrame keyboardFrame: CGRect) -> CGFloat {
+        // we only need to adjust for the part of the keyboard that covers (i.e. intersects) our collection view;
+        // see https://developer.apple.com/videos/play/wwdc2017/242/ for more details
+        let intersection = messagesCollectionView.frame.intersection(keyboardFrame)
+        
+        if intersection.isNull || intersection.maxY < messagesCollectionView.frame.maxY {
+            // The keyboard is hidden, is a hardware one, or is undocked and does not cover the bottom of the collection view.
+            // Note: intersection.maxY may be less than messagesCollectionView.frame.maxY when dealing with undocked keyboards.
+            return max(0, additionalBottomInset - automaticallyAddedBottomInset)
+        } else {
+            return max(0, intersection.height + additionalBottomInset - automaticallyAddedBottomInset)
+        }
+    }
 
-    internal var keyboardOffsetFrame: CGRect {
-        guard let inputFrame = inputAccessoryView?.frame else { return .zero }
-        return CGRect(origin: inputFrame.origin, size: CGSize(width: inputFrame.width, height: inputFrame.height - iPhoneXBottomInset))
+    internal func requiredInitialScrollViewBottomInset() -> CGFloat {
+        guard let inputAccessoryView = inputAccessoryView else { return 0 }
+        return max(0, inputAccessoryView.frame.height + additionalBottomInset - automaticallyAddedBottomInset)
     }
 
-    /// On the iPhone X the inputAccessoryView is anchored to the layoutMarginesGuide.bottom anchor
-    /// so the frame of the inputAccessoryView is larger than the required offset
-    /// for the MessagesCollectionView.
+    /// iOS 11's UIScrollView can automatically add safe area insets to its contentInset,
+    /// which needs to be accounted for when setting the contentInset based on screen coordinates.
     ///
-    /// - Returns: The safeAreaInsets.bottom if its an iPhoneX, else 0
-    private var iPhoneXBottomInset: CGFloat {
+    /// - Returns: The distance automatically added to contentInset.bottom, if any.
+    private var automaticallyAddedBottomInset: CGFloat {
         if #available(iOS 11.0, *) {
-            guard UIScreen.main.nativeBounds.height == 2436 else { return 0 }
-            return view.safeAreaInsets.bottom
+            return messagesCollectionView.adjustedContentInset.bottom - messagesCollectionView.contentInset.bottom
+        } else {
+            return 0
         }
-        return 0
     }
+
 }

+ 1 - 0
Pods/MessageKit/Sources/Controllers/MessagesViewController+Menu.swift

@@ -23,6 +23,7 @@
  */
 
 import Foundation
+import MessageInputBar
 
 extension MessagesViewController {
 

+ 23 - 4
Pods/MessageKit/Sources/Controllers/MessagesViewController.swift

@@ -23,6 +23,7 @@
  */
 
 import UIKit
+import MessageInputBar
 
 /// A subclass of `UIViewController` with a `MessagesCollectionView` object
 /// that is used to display conversation interfaces.
@@ -39,7 +40,7 @@ UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
     /// bottom whenever the `InputTextView` begins editing.
     ///
     /// The default value of this property is `false`.
-    open var scrollsToBottomOnKeybordBeginsEditing: Bool = false
+    open var scrollsToBottomOnKeyboardBeginsEditing: Bool = false
     
     /// A Boolean value that determines whether the `MessagesCollectionView`
     /// maintains it's current position when the height of the `MessageInputBar` changes.
@@ -59,6 +60,17 @@ UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
         return false
     }
 
+    /// A CGFloat value that adds to (or, if negative, subtracts from) the automatically
+    /// computed value of `messagesCollectionView.contentInset.bottom`. Meant to be used
+    /// as a measure of last resort when the built-in algorithm does not produce the right
+    /// value for your app. Please let us know when you end up having to use this property.
+    open var additionalBottomInset: CGFloat = 0 {
+        didSet {
+            let delta = additionalBottomInset - oldValue
+            messageCollectionViewBottomInset += delta
+        }
+    }
+
     private var isFirstLayout: Bool = true
     
     internal var isMessagesControllerBeingDismissed: Bool = false
@@ -94,14 +106,19 @@ UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
         isMessagesControllerBeingDismissed = true
     }
     
+    open override func viewDidDisappear(_ animated: Bool) {
+        super.viewDidDisappear(animated)
+        isMessagesControllerBeingDismissed = false
+    }
+    
     open override func viewDidLayoutSubviews() {
         // Hack to prevent animation of the contentInset after viewDidAppear
         if isFirstLayout {
             defer { isFirstLayout = false }
             addKeyboardObservers()
-            messageCollectionViewBottomInset = keyboardOffsetFrame.height
+            messageCollectionViewBottomInset = requiredInitialScrollViewBottomInset()
         }
-        adjustScrollViewInset()
+        adjustScrollViewTopInset()
     }
 
     // MARK: - Initializers
@@ -164,6 +181,8 @@ UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
         return collectionView.messagesDataSource?.numberOfItems(inSection: section, in: collectionView) ?? 0
     }
 
+    /// Note:
+    ///   If you override this method, remember to call MessagesDataSource's customCell(for:at:in:) for MessageKind.custom messages, if necessary
     open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
 
         guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
@@ -190,7 +209,7 @@ UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
             cell.configure(with: message, at: indexPath, and: messagesCollectionView)
             return cell
         case .custom:
-            fatalError(MessageKitError.customDataUnresolvedCell)
+            return messagesDataSource.customCell(for: message, at: indexPath, in: messagesCollectionView)
         }
     }
 

+ 2 - 0
Pods/MessageKit/Sources/Layout/CellSizeCalculator.swift

@@ -44,5 +44,7 @@ open class CellSizeCalculator {
     /// - indexPath: The `IndexPath` of the item to be displayed.
     /// The default return .zero
     open func sizeForItem(at indexPath: IndexPath) -> CGSize { return .zero }
+    
+    public init() {}
 
 }

+ 43 - 15
Pods/MessageKit/Sources/Layout/MessageSizeCalculator.swift

@@ -50,6 +50,12 @@ open class MessageSizeCalculator: CellSizeCalculator {
     public var incomingMessageBottomLabelAlignment = LabelAlignment(textAlignment: .left, textInsets: UIEdgeInsets(left: 42))
     public var outgoingMessageBottomLabelAlignment = LabelAlignment(textAlignment: .right, textInsets: UIEdgeInsets(right: 42))
 
+    public var incomingAccessoryViewSize = CGSize.zero
+    public var outgoingAccessoryViewSize = CGSize.zero
+
+    public var incomingAccessoryViewPadding = HorizontalEdgeInsets.zero
+    public var outgoingAccessoryViewPadding = HorizontalEdgeInsets.zero
+
     open override func configure(attributes: UICollectionViewLayoutAttributes) {
         guard let attributes = attributes as? MessagesCollectionViewLayoutAttributes else { return }
 
@@ -68,6 +74,9 @@ open class MessageSizeCalculator: CellSizeCalculator {
 
         attributes.messageBottomLabelAlignment = messageBottomLabelAlignment(for: message)
         attributes.messageBottomLabelSize = messageBottomLabelSize(for: message, at: indexPath)
+
+        attributes.accessoryViewSize = accessoryViewSize(for: message)
+        attributes.accessoryViewPadding = accessoryViewPadding(for: message)
     }
 
     open override func sizeForItem(at indexPath: IndexPath) -> CGSize {
@@ -86,41 +95,44 @@ open class MessageSizeCalculator: CellSizeCalculator {
         let messageVerticalPadding = messageContainerPadding(for: message).vertical
         let avatarHeight = avatarSize(for: message).height
         let avatarVerticalPosition = avatarPosition(for: message).vertical
+        let accessoryViewHeight = accessoryViewSize(for: message).height
 
         switch avatarVerticalPosition {
         case .messageCenter:
             let totalLabelHeight: CGFloat = cellTopLabelHeight + messageTopLabelHeight
                 + messageContainerHeight + messageVerticalPadding + messageBottomLabelHeight
-            return max(avatarHeight, totalLabelHeight)
+            let cellHeight = max(avatarHeight, totalLabelHeight)
+            return max(cellHeight, accessoryViewHeight)
         case .messageBottom:
             var cellHeight: CGFloat = 0
             cellHeight += messageBottomLabelHeight
             let labelsHeight = messageContainerHeight + messageVerticalPadding + cellTopLabelHeight + messageTopLabelHeight
             cellHeight += max(labelsHeight, avatarHeight)
-            return cellHeight
+            return max(cellHeight, accessoryViewHeight)
         case .messageTop:
             var cellHeight: CGFloat = 0
             cellHeight += cellTopLabelHeight
             cellHeight += messageTopLabelHeight
             let labelsHeight = messageContainerHeight + messageVerticalPadding + messageBottomLabelHeight
             cellHeight += max(labelsHeight, avatarHeight)
-            return cellHeight
+            return max(cellHeight, accessoryViewHeight)
         case .messageLabelTop:
             var cellHeight: CGFloat = 0
             cellHeight += cellTopLabelHeight
             let messageLabelsHeight = messageContainerHeight + messageBottomLabelHeight + messageVerticalPadding + messageTopLabelHeight
             cellHeight += max(messageLabelsHeight, avatarHeight)
-            return cellHeight
+            return max(cellHeight, accessoryViewHeight)
         case .cellTop, .cellBottom:
             let totalLabelHeight: CGFloat = cellTopLabelHeight + messageTopLabelHeight
                 + messageContainerHeight + messageVerticalPadding + messageBottomLabelHeight
-            return max(avatarHeight, totalLabelHeight)
+            let cellHeight = max(avatarHeight, totalLabelHeight)
+            return max(cellHeight, accessoryViewHeight)
         }
     }
 
     // MARK: - Avatar
 
-    public func avatarPosition(for message: MessageType) -> AvatarPosition {
+    open func avatarPosition(for message: MessageType) -> AvatarPosition {
         let dataSource = messagesLayout.messagesDataSource
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         var position = isFromCurrentSender ? outgoingAvatarPosition : incomingAvatarPosition
@@ -134,7 +146,7 @@ open class MessageSizeCalculator: CellSizeCalculator {
         return position
     }
 
-    public func avatarSize(for message: MessageType) -> CGSize {
+    open func avatarSize(for message: MessageType) -> CGSize {
         let dataSource = messagesLayout.messagesDataSource
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         return isFromCurrentSender ? outgoingAvatarSize : incomingAvatarSize
@@ -142,14 +154,14 @@ open class MessageSizeCalculator: CellSizeCalculator {
 
     // MARK: - Top cell Label
 
-    public func cellTopLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
+    open func cellTopLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
         let layoutDelegate = messagesLayout.messagesLayoutDelegate
         let collectionView = messagesLayout.messagesCollectionView
         let height = layoutDelegate.cellTopLabelHeight(for: message, at: indexPath, in: collectionView)
         return CGSize(width: messagesLayout.itemWidth, height: height)
     }
 
-    public func cellTopLabelAlignment(for message: MessageType) -> LabelAlignment {
+    open func cellTopLabelAlignment(for message: MessageType) -> LabelAlignment {
         let dataSource = messagesLayout.messagesDataSource
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         return isFromCurrentSender ? outgoingCellTopLabelAlignment : incomingCellTopLabelAlignment
@@ -157,14 +169,14 @@ open class MessageSizeCalculator: CellSizeCalculator {
     
     // MARK: - Top message Label
     
-    public func messageTopLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
+    open func messageTopLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
         let layoutDelegate = messagesLayout.messagesLayoutDelegate
         let collectionView = messagesLayout.messagesCollectionView
         let height = layoutDelegate.messageTopLabelHeight(for: message, at: indexPath, in: collectionView)
         return CGSize(width: messagesLayout.itemWidth, height: height)
     }
     
-    public func messageTopLabelAlignment(for message: MessageType) -> LabelAlignment {
+    open func messageTopLabelAlignment(for message: MessageType) -> LabelAlignment {
         let dataSource = messagesLayout.messagesDataSource
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         return isFromCurrentSender ? outgoingMessageTopLabelAlignment : incomingMessageTopLabelAlignment
@@ -172,22 +184,36 @@ open class MessageSizeCalculator: CellSizeCalculator {
 
     // MARK: - Bottom Label
 
-    public func messageBottomLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
+    open func messageBottomLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
         let layoutDelegate = messagesLayout.messagesLayoutDelegate
         let collectionView = messagesLayout.messagesCollectionView
         let height = layoutDelegate.messageBottomLabelHeight(for: message, at: indexPath, in: collectionView)
         return CGSize(width: messagesLayout.itemWidth, height: height)
     }
 
-    public func messageBottomLabelAlignment(for message: MessageType) -> LabelAlignment {
+    open func messageBottomLabelAlignment(for message: MessageType) -> LabelAlignment {
         let dataSource = messagesLayout.messagesDataSource
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         return isFromCurrentSender ? outgoingMessageBottomLabelAlignment : incomingMessageBottomLabelAlignment
     }
 
+    // MARK: - Accessory View
+
+    public func accessoryViewSize(for message: MessageType) -> CGSize {
+        let dataSource = messagesLayout.messagesDataSource
+        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
+        return isFromCurrentSender ? outgoingAccessoryViewSize : incomingAccessoryViewSize
+    }
+
+    public func accessoryViewPadding(for message: MessageType) -> HorizontalEdgeInsets {
+        let dataSource = messagesLayout.messagesDataSource
+        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
+        return isFromCurrentSender ? outgoingAccessoryViewPadding : incomingAccessoryViewPadding
+    }
+
     // MARK: - MessageContainer
 
-    public func messageContainerPadding(for message: MessageType) -> UIEdgeInsets {
+    open func messageContainerPadding(for message: MessageType) -> UIEdgeInsets {
         let dataSource = messagesLayout.messagesDataSource
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         return isFromCurrentSender ? outgoingMessagePadding : incomingMessagePadding
@@ -201,7 +227,9 @@ open class MessageSizeCalculator: CellSizeCalculator {
     open func messageContainerMaxWidth(for message: MessageType) -> CGFloat {
         let avatarWidth = avatarSize(for: message).width
         let messagePadding = messageContainerPadding(for: message)
-        return messagesLayout.itemWidth - avatarWidth - messagePadding.horizontal
+        let accessoryWidth = accessoryViewSize(for: message).width
+        let accessoryPadding = accessoryViewPadding(for: message)
+        return messagesLayout.itemWidth - avatarWidth - messagePadding.horizontal - accessoryWidth - accessoryPadding.horizontal
     }
 
     // MARK: - Helpers

+ 46 - 8
Pods/MessageKit/Sources/Layout/MessagesCollectionViewFlowLayout.swift

@@ -66,19 +66,31 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
 
     public override init() {
         super.init()
-
-        sectionInset = UIEdgeInsets(top: 4, left: 8, bottom: 4, right: 8)
-
-        NotificationCenter.default.addObserver(self, selector: #selector(MessagesCollectionViewFlowLayout.handleOrientationChange(_:)), name: UIDevice.orientationDidChangeNotification, object: nil)
+        
+        setupView()
+        setupObserver()
     }
 
     required public init?(coder aDecoder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
+        super.init(coder: aDecoder)
+        
+        setupView()
+        setupObserver()
     }
 
     deinit {
         NotificationCenter.default.removeObserver(self)
     }
+    
+    // MARK: - Methods
+    
+    private func setupView() {
+        sectionInset = UIEdgeInsets(top: 4, left: 8, bottom: 4, right: 8)
+    }
+    
+    private func setupObserver() {
+        NotificationCenter.default.addObserver(self, selector: #selector(MessagesCollectionViewFlowLayout.handleOrientationChange(_:)), name: UIDevice.orientationDidChangeNotification, object: nil)
+    }
 
     // MARK: - Attributes
 
@@ -126,11 +138,17 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
 
     lazy open var textMessageSizeCalculator = TextMessageSizeCalculator(layout: self)
     lazy open var attributedTextMessageSizeCalculator = TextMessageSizeCalculator(layout: self)
-    lazy open var emojiMessageSizeCalculator = TextMessageSizeCalculator(layout: self)
+    lazy open var emojiMessageSizeCalculator: TextMessageSizeCalculator = {
+        let sizeCalculator = TextMessageSizeCalculator(layout: self)
+        sizeCalculator.messageLabelFont = UIFont.systemFont(ofSize: sizeCalculator.messageLabelFont.pointSize * 2)
+        return sizeCalculator
+    }()
     lazy open var photoMessageSizeCalculator = MediaMessageSizeCalculator(layout: self)
     lazy open var videoMessageSizeCalculator = MediaMessageSizeCalculator(layout: self)
     lazy open var locationMessageSizeCalculator = LocationMessageSizeCalculator(layout: self)
 
+    /// - Note:
+    ///   If you override this method, remember to call MessageLayoutDelegate's customCellSizeCalculator(for:at:in:) method for MessageKind.custom messages, if necessary
     open func cellSizeCalculatorForItem(at indexPath: IndexPath) -> CellSizeCalculator {
         let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
         switch message.kind {
@@ -147,7 +165,7 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
         case .location:
             return locationMessageSizeCalculator
         case .custom:
-            fatalError("Must return a CellSizeCalculator for MessageKind.custom(Any?)")
+            return messagesLayoutDelegate.customCellSizeCalculator(for: message, at: indexPath, in: messagesCollectionView)
         }
     }
 
@@ -215,7 +233,27 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
     public func setMessageOutgoingMessageBottomLabelAlignment(_ newAlignment: LabelAlignment) {
         messageSizeCalculators().forEach { $0.outgoingMessageBottomLabelAlignment = newAlignment }
     }
-    
+
+    /// Set `incomingAccessoryViewSize` of all `MessageSizeCalculator`s
+    public func setMessageIncomingAccessoryViewSize(_ newSize: CGSize) {
+        messageSizeCalculators().forEach { $0.incomingAccessoryViewSize = newSize }
+    }
+
+    /// Set `outgoingAvatarSize` of all `MessageSizeCalculator`s
+    public func setMessageOutgoingAccessoryViewSize(_ newSize: CGSize) {
+        messageSizeCalculators().forEach { $0.outgoingAccessoryViewSize = newSize }
+    }
+
+    /// Set `incomingAccessoryViewSize` of all `MessageSizeCalculator`s
+    public func setMessageIncomingAccessoryViewPadding(_ newPadding: HorizontalEdgeInsets) {
+        messageSizeCalculators().forEach { $0.incomingAccessoryViewPadding = newPadding }
+    }
+
+    /// Set `outgoingAvatarSize` of all `MessageSizeCalculator`s
+    public func setMessageOutgoingAccessoryViewPadding(_ newPadding: HorizontalEdgeInsets) {
+        messageSizeCalculators().forEach { $0.outgoingAccessoryViewPadding = newPadding }
+    }
+
     /// Get all `MessageSizeCalculator`s
     open func messageSizeCalculators() -> [MessageSizeCalculator] {
         return [textMessageSizeCalculator, attributedTextMessageSizeCalculator, emojiMessageSizeCalculator, photoMessageSizeCalculator, videoMessageSizeCalculator, locationMessageSizeCalculator]

+ 7 - 0
Pods/MessageKit/Sources/Layout/MessagesCollectionViewLayoutAttributes.swift

@@ -46,6 +46,9 @@ open class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttribu
     public var messageBottomLabelAlignment = LabelAlignment(textAlignment: .center, textInsets: .zero)
     public var messageBottomLabelSize: CGSize = .zero
 
+    public var accessoryViewSize: CGSize = .zero
+    public var accessoryViewPadding: HorizontalEdgeInsets = .zero
+
     // MARK: - Methods
 
     open override func copy(with zone: NSZone? = nil) -> Any {
@@ -63,6 +66,8 @@ open class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttribu
         copy.messageTopLabelSize = messageTopLabelSize
         copy.messageBottomLabelAlignment = messageBottomLabelAlignment
         copy.messageBottomLabelSize = messageBottomLabelSize
+        copy.accessoryViewSize = accessoryViewSize
+        copy.accessoryViewPadding = accessoryViewPadding
         return copy
         // swiftlint:enable force_cast
     }
@@ -82,6 +87,8 @@ open class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttribu
                 && attributes.messageTopLabelSize == messageTopLabelSize
                 && attributes.messageBottomLabelAlignment == messageBottomLabelAlignment
                 && attributes.messageBottomLabelSize == messageBottomLabelSize
+                && attributes.accessoryViewSize == accessoryViewSize
+                && attributes.accessoryViewPadding == accessoryViewPadding
         } else {
             return false
         }

+ 55 - 0
Pods/MessageKit/Sources/Models/HorizontalEdgeInsets.swift

@@ -0,0 +1,55 @@
+/*
+ MIT License
+
+ Copyright (c) 2017-2018 MessageKit
+
+ 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 Foundation
+
+/// A varient of `UIEdgeInsets` that only has horizontal inset properties
+public struct HorizontalEdgeInsets {
+
+    public var left: CGFloat
+    public var right: CGFloat
+
+    public init(left: CGFloat, right: CGFloat) {
+        self.left = left
+        self.right = right
+    }
+
+    public static var zero: HorizontalEdgeInsets {
+        return HorizontalEdgeInsets(left: 0, right: 0)
+    }
+}
+
+extension HorizontalEdgeInsets: Equatable {
+
+    public static func == (lhs: HorizontalEdgeInsets, rhs: HorizontalEdgeInsets) -> Bool {
+        return lhs.left == rhs.left && lhs.right == rhs.right
+    }
+}
+
+extension HorizontalEdgeInsets {
+
+    internal var horizontal: CGFloat {
+        return left + right
+    }
+}

+ 3 - 3
Pods/MessageKit/Sources/Models/MessageKind.swift

@@ -52,9 +52,9 @@ public enum MessageKind {
     case emoji(String)
 
     /// A custom message.
-    /// - Note: Using this case requires that you override the following methods and handle this case:
-    ///   - `collectionView(_:cellForItemAt indexPath: IndexPath) -> UICollectionViewCell`
-    ///   - `cellSizeCalculatorForItem(at indexPath: IndexPath) -> CellSizeCalculator`
+    /// - Note: Using this case requires that you implement the following methods and handle this case:
+    ///   - MessagesDataSource: customCell(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UICollectionViewCell
+    ///   - MessagesLayoutDelegate: customCellSizeCalculator(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CellSizeCalculator
     case custom(Any?)
 
     // MARK: - Not supported yet

+ 3 - 3
Pods/MessageKit/Sources/Models/NSConstraintLayoutSet.swift

@@ -36,9 +36,9 @@ internal class NSLayoutConstraintSet {
     internal var height: NSLayoutConstraint?
     
     internal init(top: NSLayoutConstraint? = nil, bottom: NSLayoutConstraint? = nil,
-                left: NSLayoutConstraint? = nil, right: NSLayoutConstraint? = nil,
-                centerX: NSLayoutConstraint? = nil, centerY: NSLayoutConstraint? = nil,
-                width: NSLayoutConstraint? = nil, height: NSLayoutConstraint? = nil) {
+                  left: NSLayoutConstraint? = nil, right: NSLayoutConstraint? = nil,
+                  centerX: NSLayoutConstraint? = nil, centerY: NSLayoutConstraint? = nil,
+                  width: NSLayoutConstraint? = nil, height: NSLayoutConstraint? = nil) {
         self.top = top
         self.bottom = bottom
         self.left = left

+ 12 - 0
Pods/MessageKit/Sources/Protocols/MessageCellDelegate.swift

@@ -77,6 +77,16 @@ public protocol MessageCellDelegate: MessageLabelDelegate {
     /// `indexPath(for: cell)` method. Then using the returned `IndexPath` with the `MessagesDataSource`
     /// method `messageForItem(at:indexPath:messagesCollectionView)`.
     func didTapMessageBottomLabel(in cell: MessageCollectionViewCell)
+    
+    /// Triggered when a tap occurs in the accessoryView.
+    ///
+    /// - Parameters:
+    ///   - cell: The cell where the tap occurred.
+    ///
+    /// You can get a reference to the `MessageType` for the cell by using `UICollectionView`'s
+    /// `indexPath(for: cell)` method. Then using the returned `IndexPath` with the `MessagesDataSource`
+    /// method `messageForItem(at:indexPath:messagesCollectionView)`.
+    func didTapAccessoryView(in cell: MessageCollectionViewCell)
 
 }
 
@@ -91,4 +101,6 @@ public extension MessageCellDelegate {
     func didTapMessageTopLabel(in cell: MessageCollectionViewCell) {}
 
     func didTapMessageBottomLabel(in cell: MessageCollectionViewCell) {}
+    
+    func didTapAccessoryView(in cell: MessageCollectionViewCell) {}
 }

+ 15 - 2
Pods/MessageKit/Sources/Protocols/MessagesDataSource.swift

@@ -92,7 +92,17 @@ public protocol MessagesDataSource: AnyObject {
     ///
     /// The default value returned by this method is `nil`.
     func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString?
-
+    
+    /// Custom collectionView cell for message with `custom` message type.
+    ///
+    /// - Parameters:
+    ///   - message: The `custom` message type
+    ///   - indexPath: The `IndexPath` of the cell.
+    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
+    ///
+    /// - Note:
+    ///   This method will call fatalError() on default. You must override this method if you are using MessageType.custom messages.
+    func customCell(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UICollectionViewCell
 }
 
 public extension MessagesDataSource {
@@ -116,5 +126,8 @@ public extension MessagesDataSource {
     func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
         return nil
     }
-
+    
+    func customCell(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UICollectionViewCell {
+        fatalError(MessageKitError.customDataUnresolvedCell)
+    }
 }

+ 14 - 0
Pods/MessageKit/Sources/Protocols/MessagesDisplayDelegate.swift

@@ -84,6 +84,18 @@ public protocol MessagesDisplayDelegate: AnyObject {
     ///   The default image configured by this method is `?`.
     func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView)
 
+    /// Used to configure the `AccessoryView` in a `MessageContentCell` class.
+    ///
+    /// - Parameters:
+    ///   - accessoryView: The `AccessoryView` of the cell.
+    ///   - message: The `MessageType` that will be displayed by this cell.
+    ///   - indexPath: The `IndexPath` of the cell.
+    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
+    ///
+    /// - Note:
+    ///   The default image configured by this method is `?`.
+    func configureAccessoryView(_ accessoryView: UIView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView)
+
     // MARK: - Text Messages
 
     /// Specifies the color of the text for a `TextMessageCell`.
@@ -194,6 +206,8 @@ public extension MessagesDisplayDelegate {
         avatarView.initials = "?"
     }
 
+    func configureAccessoryView(_ accessoryView: UIView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) {}
+
     // MARK: - Text Messages Defaults
 
     func textColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor {

+ 15 - 1
Pods/MessageKit/Sources/Protocols/MessagesLayoutDelegate.swift

@@ -80,7 +80,17 @@ public protocol MessagesLayoutDelegate: AnyObject {
     /// - Note:
     ///   The default value returned by this method is zero.
     func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat
-
+    
+    /// Custom cell size calculator for messages with MessageType.custom.
+    ///
+    /// - Parameters:
+    ///   - message: The custom message
+    ///   - indexPath: The `IndexPath` of the cell.
+    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
+    ///
+    /// - Note:
+    ///   The default implementation will throw fatalError(). You must override this method if you are using messages with MessageType.custom.
+    func customCellSizeCalculator(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CellSizeCalculator
 }
 
 public extension MessagesLayoutDelegate {
@@ -104,4 +114,8 @@ public extension MessagesLayoutDelegate {
     func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
         return 0
     }
+    
+    func customCellSizeCalculator(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CellSizeCalculator {
+        fatalError("Must return a CellSizeCalculator for MessageKind.custom(Any?)")
+    }
 }

+ 6 - 4
Pods/MessageKit/Sources/Views/AvatarView.swift

@@ -74,9 +74,15 @@ open class AvatarView: UIImageView {
         super.init(frame: frame)
         prepareView()
     }
+    
+    required public init?(coder aDecoder: NSCoder) {
+        super.init(coder: aDecoder)
+        prepareView()
+    }
 
     convenience public init() {
         self.init(frame: .zero)
+        prepareView()
     }
     
     private func setImageFrom(initials: String?) {
@@ -152,10 +158,6 @@ open class AvatarView: UIImageView {
         return CGRect(startX+2, startY, w-4, h)
     }
 
-    required public init?(coder aDecoder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-
     // MARK: - Internal methods
 
     internal func prepareView() {

+ 1 - 1
Pods/MessageKit/Sources/Views/Cells/MessageCollectionViewCell.swift

@@ -34,7 +34,7 @@ open class MessageCollectionViewCell: UICollectionViewCell {
     }
 
     public required init?(coder aDecoder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
+        super.init(coder: aDecoder)
     }
 
 }

+ 40 - 3
Pods/MessageKit/Sources/Views/Cells/MessageContentCell.swift

@@ -60,6 +60,9 @@ open class MessageContentCell: MessageCollectionViewCell {
         return label
     }()
 
+    // Should only add customized subviews - don't change accessoryView itself.
+    open var accessoryView: UIView = UIView()
+
     /// The `MessageCellDelegate` for the cell.
     open weak var delegate: MessageCellDelegate?
 
@@ -70,10 +73,13 @@ open class MessageContentCell: MessageCollectionViewCell {
     }
 
     required public init?(coder aDecoder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
+        super.init(coder: aDecoder)
+        contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+        setupSubviews()
     }
 
     open func setupSubviews() {
+        contentView.addSubview(accessoryView)
         contentView.addSubview(cellTopLabel)
         contentView.addSubview(messageTopLabel)
         contentView.addSubview(messageBottomLabel)
@@ -99,6 +105,7 @@ open class MessageContentCell: MessageCollectionViewCell {
         layoutCellTopLabel(with: attributes)
         layoutMessageTopLabel(with: attributes)
         layoutAvatarView(with: attributes)
+        layoutAccessoryView(with: attributes)
     }
 
     /// Used to configure the cell.
@@ -122,6 +129,8 @@ open class MessageContentCell: MessageCollectionViewCell {
 
         displayDelegate.configureAvatarView(avatarView, for: message, at: indexPath, in: messagesCollectionView)
 
+        displayDelegate.configureAccessoryView(accessoryView, for: message, at: indexPath, in: messagesCollectionView)
+
         messageContainerView.backgroundColor = messageColor
         messageContainerView.style = messageStyle
 
@@ -149,6 +158,8 @@ open class MessageContentCell: MessageCollectionViewCell {
             delegate?.didTapMessageTopLabel(in: self)
         case messageBottomLabel.frame.contains(touchLocation):
             delegate?.didTapMessageBottomLabel(in: self)
+        case accessoryView.frame.contains(touchLocation):
+            delegate?.didTapAccessoryView(in: self)
         default:
             break
         }
@@ -216,7 +227,12 @@ open class MessageContentCell: MessageCollectionViewCell {
                 fallthrough
             }
         default:
-            origin.y = attributes.cellTopLabelSize.height + attributes.messageTopLabelSize.height + attributes.messageContainerPadding.top
+            if attributes.accessoryViewSize.height > attributes.messageContainerSize.height {
+                let messageHeight = attributes.messageContainerSize.height + attributes.messageContainerPadding.vertical
+                origin.y = (attributes.size.height / 2) - (messageHeight / 2)
+            } else {
+                origin.y = attributes.cellTopLabelSize.height + attributes.messageTopLabelSize.height + attributes.messageContainerPadding.top
+            }
         }
 
         switch attributes.avatarPosition.horizontal {
@@ -260,5 +276,26 @@ open class MessageContentCell: MessageCollectionViewCell {
 
         messageBottomLabel.frame = CGRect(origin: origin, size: attributes.messageBottomLabelSize)
     }
-    
+
+    /// Positions the cell's accessory view.
+    /// - attributes: The `MessagesCollectionViewLayoutAttributes` for the cell.
+    open func layoutAccessoryView(with attributes: MessagesCollectionViewLayoutAttributes) {
+        
+        // Accessory view aligned to the middle of the messageContainerView
+        let y = messageContainerView.frame.midY - (attributes.accessoryViewSize.height / 2)
+
+        var origin = CGPoint(x: 0, y: y)
+
+        // Accessory view is always on the opposite side of avatar
+        switch attributes.avatarPosition.horizontal {
+        case .cellLeading:
+            origin.x = messageContainerView.frame.maxX + attributes.accessoryViewPadding.left
+        case .cellTrailing:
+            origin.x = messageContainerView.frame.minX - attributes.accessoryViewPadding.right - attributes.accessoryViewSize.width
+        case .natural:
+            fatalError(MessageKitError.avatarPositionUnresolved)
+        }
+
+        accessoryView.frame = CGRect(origin: origin, size: attributes.accessoryViewSize)
+    }
 }

+ 1 - 1
Pods/MessageKit/Sources/Views/Headers & Footers/MessageReusableView.swift

@@ -33,7 +33,7 @@ open class MessageReusableView: UICollectionReusableView {
     }
 
     public required init?(coder aDecoder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
+        super.init(coder: aDecoder)
     }
 
 }

+ 32 - 5
Pods/MessageKit/Sources/Views/MessageLabel.swift

@@ -112,6 +112,13 @@ open class MessageLabel: UILabel {
             if !isConfiguring { setNeedsDisplay() }
         }
     }
+
+    open override var intrinsicContentSize: CGSize {
+        var size = super.intrinsicContentSize
+        size.width += textInsets.horizontal
+        size.height += textInsets.vertical
+        return size
+    }
     
     internal var messageLabelFont: UIFont?
 
@@ -159,12 +166,12 @@ open class MessageLabel: UILabel {
 
     public override init(frame: CGRect) {
         super.init(frame: frame)
-        self.numberOfLines = 0
-        self.lineBreakMode = .byWordWrapping
+        setupView()
     }
 
     public required init?(coder aDecoder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
+        super.init(coder: aDecoder)
+        setupView()
     }
 
     // MARK: - Open Methods
@@ -296,6 +303,11 @@ open class MessageLabel: UILabel {
             fatalError(MessageKitError.unrecognizedCheckingResult)
         }
     }
+    
+    private func setupView() {
+        numberOfLines = 0
+        lineBreakMode = .byWordWrapping
+    }
 
     // MARK: - Parsing Text
 
@@ -304,7 +316,22 @@ open class MessageLabel: UILabel {
         let checkingTypes = enabledDetectors.reduce(0) { $0 | $1.textCheckingType.rawValue }
         let detector = try? NSDataDetector(types: checkingTypes)
         let range = NSRange(location: 0, length: text.length)
-        return detector?.matches(in: text.string, options: [], range: range) ?? []
+        let matches = detector?.matches(in: text.string, options: [], range: range) ?? []
+
+        guard enabledDetectors.contains(.url) else {
+            return matches
+        }
+
+        // Enumerate NSAttributedString NSLinks and append ranges
+        var results: [NSTextCheckingResult] = matches
+
+        text.enumerateAttribute(NSAttributedString.Key.link, in: range, options: []) { value, range, _ in
+            guard let url = value as? URL else { return }
+            let result = NSTextCheckingResult.linkCheckingResult(range: range, url: url)
+            results.append(result)
+        }
+
+        return results
     }
 
     private func setRangesForDetectors(in checkingResults: [NSTextCheckingResult]) {
@@ -372,7 +399,7 @@ open class MessageLabel: UILabel {
 
     }
 
-  internal func handleGesture(_ touchLocation: CGPoint) -> Bool {
+  open func handleGesture(_ touchLocation: CGPoint) -> Bool {
 
         guard let index = stringIndex(at: touchLocation) else { return false }
 

+ 8 - 1
Pods/MessageKit/Sources/Views/MessagesCollectionView.swift

@@ -52,7 +52,7 @@ open class MessagesCollectionView: UICollectionView {
     }
     
     required public init?(coder aDecoder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
+        super.init(frame: .zero, collectionViewLayout: MessagesCollectionViewFlowLayout())
     }
 
     public convenience init() {
@@ -122,6 +122,13 @@ open class MessagesCollectionView: UICollectionView {
                  forSupplementaryViewOfKind: kind,
                  withReuseIdentifier: String(describing: T.self))
     }
+    
+    /// Registers a nib with reusable view for a specific SectionKind
+    public func register<T: UICollectionReusableView>(_ nib: UINib? = UINib(nibName: String(describing: T.self), bundle: nil), headerFooterClassOfNib headerFooterClass: T.Type, forSupplementaryViewOfKind kind: String) {
+        register(nib,
+                 forSupplementaryViewOfKind: kind,
+                 withReuseIdentifier: String(describing: T.self))        
+    }
 
     /// Generically dequeues a cell of the correct type allowing you to avoid scattering your code with guard-let-else-fatal
     public func dequeueReusableCell<T: UICollectionViewCell>(_ cellClass: T.Type, for indexPath: IndexPath) -> T {

+ 13 - 5
Pods/MessageKit/Sources/Views/PlayButtonView.swift

@@ -40,14 +40,15 @@ open class PlayButtonView: UIView {
 
         setupSubviews()
         setupConstraints()
-
-        triangleView.clipsToBounds = true
-        triangleView.backgroundColor = .black
-        backgroundColor = .playButtonLightGray
+        setupView()
     }
 
     required public init?(coder aDecoder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
+        super.init(coder: aDecoder)
+        
+        setupSubviews()
+        setupConstraints()
+        setupView()
     }
 
     // MARK: - Methods
@@ -66,6 +67,13 @@ open class PlayButtonView: UIView {
     private func setupSubviews() {
         addSubview(triangleView)
     }
+    
+    private func setupView() {
+        triangleView.clipsToBounds = true
+        triangleView.backgroundColor = .black
+        
+        backgroundColor = .playButtonLightGray
+    }
 
     private func setupConstraints() {
         triangleView.translatesAutoresizingMaskIntoConstraints = false

Файловите разлики са ограничени, защото са твърде много
+ 533 - 418
Pods/Pods.xcodeproj/project.pbxproj


+ 26 - 0
Pods/Target Support Files/MessageInputBar/Info.plist

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>en</string>
+  <key>CFBundleExecutable</key>
+  <string>${EXECUTABLE_NAME}</string>
+  <key>CFBundleIdentifier</key>
+  <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>${PRODUCT_NAME}</string>
+  <key>CFBundlePackageType</key>
+  <string>FMWK</string>
+  <key>CFBundleShortVersionString</key>
+  <string>0.4.1</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>${CURRENT_PROJECT_VERSION}</string>
+  <key>NSPrincipalClass</key>
+  <string></string>
+</dict>
+</plist>

+ 5 - 0
Pods/Target Support Files/MessageInputBar/MessageInputBar-dummy.m

@@ -0,0 +1,5 @@
+#import <Foundation/Foundation.h>
+@interface PodsDummy_MessageInputBar : NSObject
+@end
+@implementation PodsDummy_MessageInputBar
+@end

+ 12 - 0
Pods/Target Support Files/MessageInputBar/MessageInputBar-prefix.pch

@@ -0,0 +1,12 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#else
+#ifndef FOUNDATION_EXPORT
+#if defined(__cplusplus)
+#define FOUNDATION_EXPORT extern "C"
+#else
+#define FOUNDATION_EXPORT extern
+#endif
+#endif
+#endif
+

+ 16 - 0
Pods/Target Support Files/MessageInputBar/MessageInputBar-umbrella.h

@@ -0,0 +1,16 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#else
+#ifndef FOUNDATION_EXPORT
+#if defined(__cplusplus)
+#define FOUNDATION_EXPORT extern "C"
+#else
+#define FOUNDATION_EXPORT extern
+#endif
+#endif
+#endif
+
+
+FOUNDATION_EXPORT double MessageInputBarVersionNumber;
+FOUNDATION_EXPORT const unsigned char MessageInputBarVersionString[];
+

+ 6 - 0
Pods/Target Support Files/MessageInputBar/MessageInputBar.modulemap

@@ -0,0 +1,6 @@
+framework module MessageInputBar {
+  umbrella header "MessageInputBar-umbrella.h"
+
+  export *
+  module * { export * }
+}

+ 10 - 0
Pods/Target Support Files/MessageInputBar/MessageInputBar.xcconfig

@@ -0,0 +1,10 @@
+CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/MessageInputBar
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
+PODS_BUILD_DIR = ${BUILD_DIR}
+PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_ROOT = ${SRCROOT}
+PODS_TARGET_SRCROOT = ${PODS_ROOT}/MessageInputBar
+PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
+SKIP_INSTALL = YES
+SWIFT_VERSION = 4.2

+ 1 - 1
Pods/Target Support Files/MessageKit/Info.plist

@@ -15,7 +15,7 @@
   <key>CFBundlePackageType</key>
   <string>FMWK</string>
   <key>CFBundleShortVersionString</key>
-  <string>1.0.0</string>
+  <string>2.0.0</string>
   <key>CFBundleSignature</key>
   <string>????</string>
   <key>CFBundleVersion</key>

+ 1 - 0
Pods/Target Support Files/MessageKit/MessageKit.xcconfig

@@ -1,4 +1,5 @@
 CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/MessageKit
+FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MessageInputBar"
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
 OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
 PODS_BUILD_DIR = ${BUILD_DIR}

+ 1 - 1
Pods/Target Support Files/MessageKit/ResourceBundle-MessageKitAssets-Info.plist

@@ -13,7 +13,7 @@
   <key>CFBundlePackageType</key>
   <string>BNDL</string>
   <key>CFBundleShortVersionString</key>
-  <string>1.0.0</string>
+  <string>2.0.0</string>
   <key>CFBundleSignature</key>
   <string>????</string>
   <key>CFBundleVersion</key>

+ 25 - 0
Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-acknowledgements.markdown

@@ -1,6 +1,31 @@
 # Acknowledgements
 This application makes use of the following third party libraries:
 
+## MessageInputBar
+
+MIT License
+
+Copyright (c) 2017-2018 MessageKit
+
+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.
+
+
 ## MessageKit
 
 MIT License

+ 31 - 0
Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-acknowledgements.plist

@@ -28,6 +28,37 @@ 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.
+</string>
+			<key>License</key>
+			<string>MIT</string>
+			<key>Title</key>
+			<string>MessageInputBar</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
+		<dict>
+			<key>FooterText</key>
+			<string>MIT License
+
+Copyright (c) 2017-2018 MessageKit
+
+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

+ 2 - 0
Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-frameworks.sh

@@ -143,9 +143,11 @@ strip_invalid_archs() {
 
 
 if [[ "$CONFIGURATION" == "Debug" ]]; then
+  install_framework "${BUILT_PRODUCTS_DIR}/MessageInputBar/MessageInputBar.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/MessageKit/MessageKit.framework"
 fi
 if [[ "$CONFIGURATION" == "Release" ]]; then
+  install_framework "${BUILT_PRODUCTS_DIR}/MessageInputBar/MessageInputBar.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/MessageKit/MessageKit.framework"
 fi
 if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then

+ 3 - 3
Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios.debug.xcconfig

@@ -1,11 +1,11 @@
 ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
-FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MessageKit"
+FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MessageInputBar" "${PODS_CONFIGURATION_BUILD_DIR}/MessageKit"
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
 HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/openssl-ios-bitcode"
 LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
 LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/openssl-ios-bitcode/lib"
-OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MessageKit/MessageKit.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/openssl-ios-bitcode"
-OTHER_LDFLAGS = $(inherited) -ObjC -l"crypto" -l"ssl" -framework "MessageKit"
+OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MessageInputBar/MessageInputBar.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MessageKit/MessageKit.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/openssl-ios-bitcode"
+OTHER_LDFLAGS = $(inherited) -ObjC -l"crypto" -l"ssl" -framework "MessageInputBar" -framework "MessageKit"
 OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

+ 3 - 3
Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios.release.xcconfig

@@ -1,11 +1,11 @@
 ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
-FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MessageKit"
+FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MessageInputBar" "${PODS_CONFIGURATION_BUILD_DIR}/MessageKit"
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
 HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/openssl-ios-bitcode"
 LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
 LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/openssl-ios-bitcode/lib"
-OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MessageKit/MessageKit.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/openssl-ios-bitcode"
-OTHER_LDFLAGS = $(inherited) -ObjC -l"crypto" -l"ssl" -framework "MessageKit"
+OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MessageInputBar/MessageInputBar.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MessageKit/MessageKit.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/openssl-ios-bitcode"
+OTHER_LDFLAGS = $(inherited) -ObjC -l"crypto" -l"ssl" -framework "MessageInputBar" -framework "MessageKit"
 OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

+ 2 - 0
deltachat-ios.xcodeproj/project.pbxproj

@@ -585,10 +585,12 @@
 			);
 			inputPaths = (
 				"${SRCROOT}/Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-frameworks.sh",
+				"${BUILT_PRODUCTS_DIR}/MessageInputBar/MessageInputBar.framework",
 				"${BUILT_PRODUCTS_DIR}/MessageKit/MessageKit.framework",
 			);
 			name = "[CP] Embed Pods Frameworks";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MessageInputBar.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MessageKit.framework",
 			);
 			runOnlyForDeploymentPostprocessing = 0;

+ 91 - 0
deltachat-ios.xcodeproj/xcshareddata/xcschemes/deltachat-ios.xcscheme

@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1010"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "7A9FB13F1FB061E2001FEA36"
+               BuildableName = "deltachat-ios.app"
+               BlueprintName = "deltachat-ios"
+               ReferencedContainer = "container:deltachat-ios.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+      </Testables>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "7A9FB13F1FB061E2001FEA36"
+            BuildableName = "deltachat-ios.app"
+            BlueprintName = "deltachat-ios"
+            ReferencedContainer = "container:deltachat-ios.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "7A9FB13F1FB061E2001FEA36"
+            BuildableName = "deltachat-ios.app"
+            BlueprintName = "deltachat-ios"
+            ReferencedContainer = "container:deltachat-ios.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "7A9FB13F1FB061E2001FEA36"
+            BuildableName = "deltachat-ios.app"
+            BlueprintName = "deltachat-ios"
+            ReferencedContainer = "container:deltachat-ios.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 3 - 1
deltachat-ios/ChatViewController.swift

@@ -9,6 +9,7 @@
 import UIKit
 import MessageKit
 import MapKit
+import MessageInputBar
 
 class ChatViewController: MessagesViewController {
     let chatId: Int
@@ -129,10 +130,11 @@ class ChatViewController: MessagesViewController {
         messagesCollectionView.messagesLayoutDelegate = self
         messagesCollectionView.messagesDisplayDelegate = self
         messagesCollectionView.messageCellDelegate = self
+        
         messageInputBar.delegate = self
         messageInputBar.sendButton.tintColor = UIColor(red: 69/255, green: 193/255, blue: 89/255, alpha: 1)
         // scrollsToBottomOnFirstLayout = true //default false
-        scrollsToBottomOnKeybordBeginsEditing = true // default false
+        scrollsToBottomOnKeyboardBeginsEditing = true // default false
         
         /*navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "ic_keyboard"),
                                                             style: .plain,

Някои файлове не бяха показани, защото твърде много файлове са промени