Преглед изворни кода

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

+ 8 - 4
Podfile.lock

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

+ 8 - 4
Pods/Manifest.lock

@@ -1,20 +1,24 @@
 PODS:
 PODS:
-  - MessageKit (1.0.0)
+  - MessageInputBar/Core (0.4.1)
+  - MessageKit (2.0.0):
+    - MessageInputBar/Core
   - openssl-ios-bitcode (1.0.210)
   - openssl-ios-bitcode (1.0.210)
 
 
 DEPENDENCIES:
 DEPENDENCIES:
-  - MessageKit (= 1.0.0)
+  - MessageKit (= 2.0.0)
   - openssl-ios-bitcode (= 1.0.210)
   - openssl-ios-bitcode (= 1.0.210)
 
 
 SPEC REPOS:
 SPEC REPOS:
   https://github.com/cocoapods/specs.git:
   https://github.com/cocoapods/specs.git:
+    - MessageInputBar
     - MessageKit
     - MessageKit
     - openssl-ios-bitcode
     - openssl-ios-bitcode
 
 
 SPEC CHECKSUMS:
 SPEC CHECKSUMS:
-  MessageKit: 16160036b16476b04bd0e9f2c7ce67e662e503e4
+  MessageInputBar: e81c7535347f1f7b923de7080409a535a004b6e4
+  MessageKit: 29c1c87e5a396d2ca7a3f712e5171dc9aba42a1e
   openssl-ios-bitcode: c833701a4488bd43de0051db41cfa75f6fef8109
   openssl-ios-bitcode: c833701a4488bd43de0051db41cfa75f6fef8109
 
 
-PODFILE CHECKSUM: dea2da329ab919c5c400d1fd104627f9904b3072
+PODFILE CHECKSUM: 738743efb43b4f6b89816b656cd3f132c9e93608
 
 
 COCOAPODS: 1.5.3
 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
 import UIKit
 
 
 /**
 /**
- A InputItem that inherits from UIButton
- 
+ A subclass of UIButton that conforms to InputItem
+
  ## Important Notes ##
  ## Important Notes ##
  1. Intended to be used in an `InputStackView`
  1. Intended to be used in an `InputStackView`
- */
-open class InputBarButtonItem: UIButton {
+*/
+open class InputBarButtonItem: UIButton, InputItem {
     
     
     /// The spacing properties of the InputBarButtonItem
     /// The spacing properties of the InputBarButtonItem
     ///
     ///
@@ -108,12 +108,18 @@ open class InputBarButtonItem: UIButton {
     
     
     /// Calls the onSelectedAction or onDeselectedAction when set
     /// Calls the onSelectedAction or onDeselectedAction when set
     open override var isHighlighted: Bool {
     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)
                 onSelectedAction?(self)
             } else {
             } else {
                 onDeselectedAction?(self)
                 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
     /// 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()
         let item = InputBarButtonItem()
         item.setSize(.zero, animated: false)
         item.setSize(.zero, animated: false)
         item.spacing = .fixed(width)
         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
     // MARK: - Properties
     
     
-    /// A delegate to broadcast notifications from the MessageInputBar
+    /// A delegate to broadcast notifications from the `MessageInputBar`
     open weak var delegate: MessageInputBarDelegate?
     open weak var delegate: MessageInputBarDelegate?
     
     
     /// The background UIView anchored to the bottom, left, and right of the MessageInputBar
     /// 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 = {
     open var backgroundView: UIView = {
         let view = UIView()
         let view = UIView()
         view.translatesAutoresizingMaskIntoConstraints = false
         view.translatesAutoresizingMaskIntoConstraints = false
-        view.backgroundColor = .inputBarGray
+        view.backgroundColor = UIColor(red: 247/255, green: 247/255, blue: 247/255, alpha: 1.0)
         return view
         return view
     }()
     }()
     
     
@@ -70,7 +70,7 @@ open class MessageInputBar: UIView {
                 blurView.fillSuperview()
                 blurView.fillSuperview()
             }
             }
             blurView.isHidden = !isTranslucent
             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)
             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)
     public let bottomStackView = InputStackView(axis: .horizontal, spacing: 15)
     
     
     /// The InputTextView a user can input a message in
     /// 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
     /// A InputBarButtonItem used as the send button and initially placed in the rightStackView
     open var sendButton: InputBarButtonItem = {
     open var sendButton: InputBarButtonItem = {
         return InputBarButtonItem()
         return InputBarButtonItem()
             .configure {
             .configure {
-                $0.setSize(CGSize(width: 52, height: 28), animated: false)
+                $0.setSize(CGSize(width: 52, height: 36), animated: false)
                 $0.isEnabled = false
                 $0.isEnabled = false
                 $0.title = "Send"
                 $0.title = "Send"
-                $0.titleLabel?.font = UIFont.preferredFont(forTextStyle: .headline)
+                $0.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .bold)
             }.onTouchUpInside {
             }.onTouchUpInside {
                 $0.messageInputBar?.didSelectSendButton()
                 $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)-|
      V:|...[InputStackView.top]-(padding.top)-[contentView]-(padding.bottom)-|
@@ -160,7 +160,7 @@ open class MessageInputBar: UIView {
      The anchor constants used by the top InputStackView
      The anchor constants used by the top InputStackView
      
      
      ## Important Notes ##
      ## 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]-...|
      V:|-(topStackViewPadding.top)-[InputStackView.top]-(padding.top)-[InputTextView]-...|
@@ -208,10 +208,18 @@ open class MessageInputBar: UIView {
     /// improves the performance
     /// improves the performance
     public private(set) var isOverMaxTextViewHeight = false
     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
     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 {
     open var maxTextViewHeight: CGFloat = 0 {
         didSet {
         didSet {
             textViewHeightAnchor?.constant = maxTextViewHeight
             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
     /// The height that will fit the current text in the InputTextView based on its current bounds
     public var requiredInputTextViewHeight: CGFloat {
     public var requiredInputTextViewHeight: CGFloat {
         let maxTextViewSize = CGSize(width: inputTextView.bounds.width, height: .greatestFiniteMagnitude)
         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
     /// The InputBarItems held in the leftStackView
-    public private(set) var leftStackViewItems: [InputBarButtonItem] = []
+    public private(set) var leftStackViewItems: [InputItem] = []
     
     
     /// The InputBarItems held in the rightStackView
     /// The InputBarItems held in the rightStackView
-    public private(set) var rightStackViewItems: [InputBarButtonItem] = []
+    public private(set) var rightStackViewItems: [InputItem] = []
     
     
     /// The InputBarItems held in the bottomStackView
     /// The InputBarItems held in the bottomStackView
-    public private(set) var bottomStackViewItems: [InputBarButtonItem] = []
+    public private(set) var bottomStackViewItems: [InputItem] = []
     
     
     /// The InputBarItems held in the topStackView
     /// 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
     /// 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
     /// 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 textViewLayoutSet: NSLayoutConstraintSet?
     private var textViewHeightAnchor: NSLayoutConstraint?
     private var textViewHeightAnchor: NSLayoutConstraint?
@@ -309,15 +323,17 @@ open class MessageInputBar: UIView {
     
     
     /// Adds the required notification observers
     /// Adds the required notification observers
     private func setupObservers() {
     private func setupObservers() {
-        
         NotificationCenter.default.addObserver(self,
         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)
                                                name: UITextView.textDidChangeNotification, object: inputTextView)
         NotificationCenter.default.addObserver(self,
         NotificationCenter.default.addObserver(self,
-                                               selector: #selector(MessageInputBar.textViewDidBeginEditing),
+                                               selector: #selector(MessageInputBar.inputTextViewDidBeginEditing),
                                                name: UITextView.textDidBeginEditingNotification, object: inputTextView)
                                                name: UITextView.textDidBeginEditingNotification, object: inputTextView)
         NotificationCenter.default.addObserver(self,
         NotificationCenter.default.addObserver(self,
-                                               selector: #selector(MessageInputBar.textViewDidEndEditing),
+                                               selector: #selector(MessageInputBar.inputTextViewDidEndEditing),
                                                name: UITextView.textDidEndEditingNotification, object: inputTextView)
                                                name: UITextView.textDidEndEditingNotification, object: inputTextView)
     }
     }
     
     
@@ -335,12 +351,11 @@ open class MessageInputBar: UIView {
         setStackViewItems([sendButton], forStack: .right, animated: false)
         setStackViewItems([sendButton], forStack: .right, animated: false)
     }
     }
     
     
-    // swiftlint:disable function_body_length colon
     /// Sets up the initial constraints of each subview
     /// Sets up the initial constraints of each subview
     private func setupConstraints() {
     private func setupConstraints() {
         
         
         // The constraints within the MessageInputBar
         // 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 = backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor)
         backgroundViewBottomAnchor?.isActive = true
         backgroundViewBottomAnchor?.isActive = true
         backgroundView.addConstraints(topStackView.bottomAnchor, left: leftAnchor, right: rightAnchor)
         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),
             left:   leftStackView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 0),
             width:  leftStackView.widthAnchor.constraint(equalToConstant: leftStackViewWidthConstant)
             width:  leftStackView.widthAnchor.constraint(equalToConstant: leftStackViewWidthConstant)
         )
         )
-
+        
         rightStackViewLayoutSet = NSLayoutConstraintSet(
         rightStackViewLayoutSet = NSLayoutConstraintSet(
             top:    rightStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0),
             top:    rightStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0),
             bottom: rightStackView.bottomAnchor.constraint(equalTo: inputTextView.bottomAnchor, constant: 0),
             bottom: rightStackView.bottomAnchor.constraint(equalTo: inputTextView.bottomAnchor, constant: 0),
@@ -401,7 +416,6 @@ open class MessageInputBar: UIView {
         )
         )
         activateConstraints()
         activateConstraints()
     }
     }
-    // swiftlint:enable function_body_length colon
     
     
     /// Respect iPhone X safeAreaInsets
     /// Respect iPhone X safeAreaInsets
     /// Adds a constraint to anchor the bottomAnchor of the contentView to the window's safeAreaLayoutGuide.bottomAnchor
     /// 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
     /// - Returns: The required intrinsicContentSize
     open func calculateIntrinsicContentSize() -> CGSize {
     open func calculateIntrinsicContentSize() -> CGSize {
@@ -473,11 +484,12 @@ open class MessageInputBar: UIView {
                 textViewHeightAnchor?.isActive = true
                 textViewHeightAnchor?.isActive = true
                 inputTextView.isScrollEnabled = true
                 inputTextView.isScrollEnabled = true
                 isOverMaxTextViewHeight = true
                 isOverMaxTextViewHeight = true
+                inputTextView.layoutIfNeeded()
             }
             }
             inputTextViewHeight = maxTextViewHeight
             inputTextViewHeight = maxTextViewHeight
         } else {
         } else {
             if isOverMaxTextViewHeight {
             if isOverMaxTextViewHeight {
-                textViewHeightAnchor?.isActive = false
+                textViewHeightAnchor?.isActive = false || shouldForceTextViewMaxHeight
                 inputTextView.isScrollEnabled = false
                 inputTextView.isScrollEnabled = false
                 isOverMaxTextViewHeight = false
                 isOverMaxTextViewHeight = false
                 inputTextView.invalidateIntrinsicContentSize()
                 inputTextView.invalidateIntrinsicContentSize()
@@ -493,6 +505,7 @@ open class MessageInputBar: UIView {
         return CGSize(width: bounds.width, height: requiredHeight)
         return CGSize(width: bounds.width, height: requiredHeight)
     }
     }
     
     
+    
     /// Returns the max height the InputTextView can grow to based on the UIScreen
     /// Returns the max height the InputTextView can grow to based on the UIScreen
     ///
     ///
     /// - Returns: Max Height
     /// - Returns: Max Height
@@ -503,13 +516,14 @@ open class MessageInputBar: UIView {
         return (UIScreen.main.bounds.height / 5).rounded(.down)
         return (UIScreen.main.bounds.height / 5).rounded(.down)
     }
     }
     
     
+    // MARK: - Layout Helper Methods
+    
     /// Layout the given InputStackView's
     /// 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]) {
     public func layoutStackViews(_ positions: [InputStackView.Position] = [.left, .right, .bottom, .top]) {
         
         
         guard superview != nil else { return }
         guard superview != nil else { return }
-        
         for position in positions {
         for position in positions {
             switch position {
             switch position {
             case .left:
             case .left:
@@ -532,7 +546,7 @@ open class MessageInputBar: UIView {
     ///
     ///
     /// - Parameters:
     /// - Parameters:
     ///   - animated: If the layout should be animated
     ///   - animated: If the layout should be animated
-    ///   - animations: Code
+    ///   - animations: Animation logic
     internal func performLayout(_ animated: Bool, _ animations: @escaping () -> Void) {
     internal func performLayout(_ animated: Bool, _ animations: @escaping () -> Void) {
         deactivateConstraints()
         deactivateConstraints()
         if animated {
         if animated {
@@ -565,16 +579,14 @@ open class MessageInputBar: UIView {
         topStackViewLayoutSet?.deactivate()
         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:
     /// - 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
     ///   - 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() {
         func setNewItems() {
             switch position {
             switch position {
@@ -584,7 +596,9 @@ open class MessageInputBar: UIView {
                 leftStackViewItems.forEach {
                 leftStackViewItems.forEach {
                     $0.messageInputBar = self
                     $0.messageInputBar = self
                     $0.parentStackViewPosition = position
                     $0.parentStackViewPosition = position
-                    leftStackView.addArrangedSubview($0)
+                    if let view = $0 as? UIView {
+                        leftStackView.addArrangedSubview(view)
+                    }
                 }
                 }
                 guard superview != nil else { return }
                 guard superview != nil else { return }
                 leftStackView.layoutIfNeeded()
                 leftStackView.layoutIfNeeded()
@@ -594,7 +608,9 @@ open class MessageInputBar: UIView {
                 rightStackViewItems.forEach {
                 rightStackViewItems.forEach {
                     $0.messageInputBar = self
                     $0.messageInputBar = self
                     $0.parentStackViewPosition = position
                     $0.parentStackViewPosition = position
-                    rightStackView.addArrangedSubview($0)
+                    if let view = $0 as? UIView {
+                        rightStackView.addArrangedSubview(view)
+                    }
                 }
                 }
                 guard superview != nil else { return }
                 guard superview != nil else { return }
                 rightStackView.layoutIfNeeded()
                 rightStackView.layoutIfNeeded()
@@ -604,7 +620,9 @@ open class MessageInputBar: UIView {
                 bottomStackViewItems.forEach {
                 bottomStackViewItems.forEach {
                     $0.messageInputBar = self
                     $0.messageInputBar = self
                     $0.parentStackViewPosition = position
                     $0.parentStackViewPosition = position
-                    bottomStackView.addArrangedSubview($0)
+                    if let view = $0 as? UIView {
+                        bottomStackView.addArrangedSubview(view)
+                    }
                 }
                 }
                 guard superview != nil else { return }
                 guard superview != nil else { return }
                 bottomStackView.layoutIfNeeded()
                 bottomStackView.layoutIfNeeded()
@@ -614,7 +632,9 @@ open class MessageInputBar: UIView {
                 topStackViewItems.forEach {
                 topStackViewItems.forEach {
                     $0.messageInputBar = self
                     $0.messageInputBar = self
                     $0.parentStackViewPosition = position
                     $0.parentStackViewPosition = position
-                    topStackView.addArrangedSubview($0)
+                    if let view = $0 as? UIView {
+                        topStackView.addArrangedSubview(view)
+                    }
                 }
                 }
                 guard superview != nil else { return }
                 guard superview != nil else { return }
                 topStackView.layoutIfNeeded()
                 topStackView.layoutIfNeeded()
@@ -626,7 +646,6 @@ open class MessageInputBar: UIView {
             setNewItems()
             setNewItems()
         }
         }
     }
     }
-    // swiftlint:enable function_body_length
     
     
     /// Sets the leftStackViewWidthConstant
     /// Sets the leftStackViewWidthConstant
     ///
     ///
@@ -637,8 +656,8 @@ open class MessageInputBar: UIView {
         performLayout(animated) {
         performLayout(animated) {
             self.leftStackViewWidthConstant = newValue
             self.leftStackViewWidthConstant = newValue
             self.layoutStackViews([.left])
             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) {
         performLayout(animated) {
             self.rightStackViewWidthConstant = newValue
             self.rightStackViewWidthConstant = newValue
             self.layoutStackViews([.right])
             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 traitCollection.verticalSizeClass != previousTraitCollection?.verticalSizeClass || traitCollection.horizontalSizeClass != previousTraitCollection?.horizontalSizeClass {
             if shouldAutoUpdateMaxTextViewHeight {
             if shouldAutoUpdateMaxTextViewHeight {
                 maxTextViewHeight = calculateMaxTextViewHeight()
                 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
     /// Enables/Disables the sendButton based on the InputTextView's text being empty
     /// Calls each items `textViewDidChangeAction` method
     /// Calls each items `textViewDidChangeAction` method
     /// Calls the delegates `textViewTextDidChangeTo` method
     /// Calls the delegates `textViewTextDidChangeTo` method
     /// Invalidates the intrinsicContentSize
     /// Invalidates the intrinsicContentSize
     @objc
     @objc
-    open func textViewDidChange() {
+    open func inputTextViewDidChange() {
+        
         let trimmedText = inputTextView.text.trimmingCharacters(in: .whitespacesAndNewlines)
         let trimmedText = inputTextView.text.trimmingCharacters(in: .whitespacesAndNewlines)
-
+        
         if shouldManageSendButtonEnabledState {
         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)
         delegate?.messageInputBar(self, textViewTextDidChangeTo: trimmedText)
         
         
-        if requiredInputTextViewHeight != inputTextView.bounds.height {
+        if shouldInvalidateIntrinsicContentSize {
             // Prevent un-needed content size invalidation
             // Prevent un-needed content size invalidation
             invalidateIntrinsicContentSize()
             invalidateIntrinsicContentSize()
         }
         }
     }
     }
     
     
     /// Calls each items `keyboardEditingBeginsAction` method
     /// Calls each items `keyboardEditingBeginsAction` method
-    /// Invalidates the intrinsicContentSize so that the keyboard does not overlap the view
     @objc
     @objc
-    open func textViewDidBeginEditing() {
+    open func inputTextViewDidBeginEditing() {
         items.forEach { $0.keyboardEditingBeginsAction() }
         items.forEach { $0.keyboardEditingBeginsAction() }
     }
     }
     
     
     /// Calls each items `keyboardEditingEndsAction` method
     /// Calls each items `keyboardEditingEndsAction` method
     @objc
     @objc
-    open func textViewDidEndEditing() {
+    open func inputTextViewDidEndEditing() {
         items.forEach { $0.keyboardEditingEndsAction() }
         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
     /// Calls the delegates `didPressSendButtonWith` method
     /// Assumes that the InputTextView's text has been set to empty and calls `inputTextViewDidChange()`
     /// 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() {
     open func didSelectSendButton() {
         delegate?.messageInputBar(self, didPressSendButtonWith: inputTextView.text)
         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
 import UIKit
 
 
 /**
 /**
- A UIStackView that's intended for holding `InputBarButtonItem`s
+ A UIStackView that's intended for holding `InputItem`s
  
  
  ## Important Notes ##
  ## Important Notes ##
  1. Default alignment is .fill
  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
 import UIKit
 
 
 /**
 /**
- A UITextView that has a UILabel embedded for placeholder text
+ A `UITextView` that has a `UILabel` embedded for placeholder text
  
  
  ## Important Notes ##
  ## Important Notes ##
  1. Changing the font, textAlignment or textContainerInset automatically performs the same modifications to the placeholderLabel
  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! {
     open override var text: String! {
         didSet {
         didSet {
             postTextViewDidChangeNotification()
             postTextViewDidChangeNotification()
-            placeholderLabel.isHidden = !text.isEmpty
         }
         }
     }
     }
     
     
     open override var attributedText: NSAttributedString! {
     open override var attributedText: NSAttributedString! {
         didSet {
         didSet {
             postTextViewDidChangeNotification()
             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] {
     open var images: [UIImage] {
         return parseForAttachedImages()
         return parseForAttachedImages()
     }
     }
@@ -62,7 +60,7 @@ open class InputTextView: UITextView {
     
     
     open var isImagePasteEnabled: Bool = true
     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 = {
     public let placeholderLabel: UILabel = {
         let label = UILabel()
         let label = UILabel()
         label.numberOfLines = 0
         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 {
         didSet {
             updateConstraintsForPlaceholderLabel()
             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! {
     open override var font: UIFont! {
         didSet {
         didSet {
             placeholderLabel.font = font
             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 {
     open override var textAlignment: NSTextAlignment {
         didSet {
         didSet {
             placeholderLabel.textAlignment = textAlignment
             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 {
     open override var scrollIndicatorInsets: UIEdgeInsets {
         didSet {
         didSet {
             // When .zero a rendering issue can occur
             // 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?
     open weak var messageInputBar: MessageInputBar?
     
     
     /// The constraints of the placeholderLabel
     /// The constraints of the placeholderLabel
@@ -151,25 +156,20 @@ open class InputTextView: UITextView {
     /// Sets up the default properties
     /// Sets up the default properties
     open func setup() {
     open func setup() {
         
         
+        backgroundColor = .clear
         font = UIFont.preferredFont(forTextStyle: .body)
         font = UIFont.preferredFont(forTextStyle: .body)
-        textContainerInset = UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 4)
+        isScrollEnabled = false
         scrollIndicatorInsets = UIEdgeInsets(top: .leastNonzeroMagnitude,
         scrollIndicatorInsets = UIEdgeInsets(top: .leastNonzeroMagnitude,
                                              left: .leastNonzeroMagnitude,
                                              left: .leastNonzeroMagnitude,
                                              bottom: .leastNonzeroMagnitude,
                                              bottom: .leastNonzeroMagnitude,
                                              right: .leastNonzeroMagnitude)
                                              right: .leastNonzeroMagnitude)
-        isScrollEnabled = false
-        layer.cornerRadius = 5.0
-        layer.borderWidth = 1.25
-        layer.borderColor = UIColor.lightGray.cgColor
-        allowsEditingTextAttributes = false
         setupPlaceholderLabel()
         setupPlaceholderLabel()
         setupObservers()
         setupObservers()
     }
     }
-    
-    // swiftlint:disable colon
+
     /// Adds the placeholderLabel to the view and sets up its initial constraints
     /// Adds the placeholderLabel to the view and sets up its initial constraints
     private func setupPlaceholderLabel() {
     private func setupPlaceholderLabel() {
-        
+
         addSubview(placeholderLabel)
         addSubview(placeholderLabel)
         placeholderLabelConstraintSet = NSLayoutConstraintSet(
         placeholderLabelConstraintSet = NSLayoutConstraintSet(
             top:     placeholderLabel.topAnchor.constraint(equalTo: topAnchor, constant: placeholderLabelInsets.top),
             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),
             right:   placeholderLabel.rightAnchor.constraint(equalTo: rightAnchor, constant: -placeholderLabelInsets.right),
             centerX: placeholderLabel.centerXAnchor.constraint(equalTo: centerXAnchor),
             centerX: placeholderLabel.centerXAnchor.constraint(equalTo: centerXAnchor),
             centerY: placeholderLabel.centerYAnchor.constraint(equalTo: centerYAnchor)
             centerY: placeholderLabel.centerYAnchor.constraint(equalTo: centerYAnchor)
-            )
+        )
         placeholderLabelConstraintSet?.centerX?.priority = .defaultLow
         placeholderLabelConstraintSet?.centerX?.priority = .defaultLow
         placeholderLabelConstraintSet?.centerY?.priority = .defaultLow
         placeholderLabelConstraintSet?.centerY?.priority = .defaultLow
         placeholderLabelConstraintSet?.activate()
         placeholderLabelConstraintSet?.activate()
     }
     }
-    // swiftlint:enable colon
     
     
     /// Adds the required notification observers
     /// Adds the required notification observers
     private func setupObservers() {
     private func setupObservers() {
@@ -191,23 +190,32 @@ open class InputTextView: UITextView {
         NotificationCenter.default.addObserver(self,
         NotificationCenter.default.addObserver(self,
                                                selector: #selector(InputTextView.redrawTextAttachments),
                                                selector: #selector(InputTextView.redrawTextAttachments),
                                                name: UIDevice.orientationDidChangeNotification, object: nil)
                                                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
     /// Updates the placeholderLabels constraint constants to match the placeholderLabelInsets
     private func updateConstraintsForPlaceholderLabel() {
     private func updateConstraintsForPlaceholderLabel() {
-        
+
         placeholderLabelConstraintSet?.top?.constant = placeholderLabelInsets.top
         placeholderLabelConstraintSet?.top?.constant = placeholderLabelInsets.top
         placeholderLabelConstraintSet?.bottom?.constant = -placeholderLabelInsets.bottom
         placeholderLabelConstraintSet?.bottom?.constant = -placeholderLabelInsets.bottom
         placeholderLabelConstraintSet?.left?.constant = placeholderLabelInsets.left
         placeholderLabelConstraintSet?.left?.constant = placeholderLabelInsets.left
         placeholderLabelConstraintSet?.right?.constant = -placeholderLabelInsets.right
         placeholderLabelConstraintSet?.right?.constant = -placeholderLabelInsets.right
     }
     }
     
     
+    
     // MARK: - Notification
     // MARK: - Notification
     
     
     private func postTextViewDidChangeNotification() {
     private func postTextViewDidChangeNotification() {
         NotificationCenter.default.post(name: UITextView.textDidChangeNotification, object: self)
         NotificationCenter.default.post(name: UITextView.textDidChangeNotification, object: self)
     }
     }
     
     
+    @objc
+    private func textViewTextDidChange() {
+        placeholderLabel.isHidden = !text.isEmpty
+    }
+    
     // MARK: - Image Paste Support
     // MARK: - Image Paste Support
     
     
     open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
     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 {
         guard let image = UIPasteboard.general.image else {
             return super.paste(sender)
             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
     /// Addes a new UIImage to the NSTextContainer as an NSTextAttachment
     ///
     ///
     /// - Parameter image: The image to add
     /// - Parameter image: The image to add
     private func pasteImageInTextContainer(with image: UIImage) {
     private func pasteImageInTextContainer(with image: UIImage) {
-
+        
         // Add the new image as an NSTextAttachment
         // Add the new image as an NSTextAttachment
         let attributedImageString = NSAttributedString(attachment: textAttachment(using: image))
         let attributedImageString = NSAttributedString(attachment: textAttachment(using: image))
         
         
@@ -247,7 +263,7 @@ open class InputTextView: UITextView {
         let attributes: [NSAttributedString.Key: Any] = [
         let attributes: [NSAttributedString.Key: Any] = [
             NSAttributedString.Key.font: font ?? UIFont.preferredFont(forTextStyle: .body),
             NSAttributedString.Key.font: font ?? UIFont.preferredFont(forTextStyle: .body),
             NSAttributedString.Key.foregroundColor: textColor ?? .black
             NSAttributedString.Key.foregroundColor: textColor ?? .black
-            ]
+        ]
         newAttributedStingComponent.addAttributes(attributes, range: NSRange(location: 0, length: newAttributedStingComponent.length))
         newAttributedStingComponent.addAttributes(attributes, range: NSRange(location: 0, length: newAttributedStingComponent.length))
         
         
         textStorage.beginEditing()
         textStorage.beginEditing()
@@ -258,9 +274,9 @@ open class InputTextView: UITextView {
         // Advance the range to the selected range plus the number of characters added
         // Advance the range to the selected range plus the number of characters added
         let location = selectedRange.location + (isEmpty ? 2 : 3)
         let location = selectedRange.location + (isEmpty ? 2 : 3)
         selectedRange = NSRange(location: location, length: 0)
         selectedRange = NSRange(location: location, length: 0)
-    
+        
         // Broadcast a notification to recievers such as the MessageInputBar which will handle resizing
         // 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
     /// Returns an NSTextAttachment the provided image that will fit inside the NSTextContainer
@@ -348,7 +364,7 @@ open class InputTextView: UITextView {
                 }
                 }
             }
             }
         }
         }
-
+        
         return components
         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
     /// The height of the line
     open var height: CGFloat = 1.0 {
     open var height: CGFloat = 1.0 {
         didSet {
         didSet {
+            constraints.filter { $0.identifier == "height" }.forEach { $0.constant = height } // Assumes constraint was given an identifier
             invalidateIntrinsicContentSize()
             invalidateIntrinsicContentSize()
         }
         }
     }
     }

+ 4 - 2
Pods/MessageKit/README.md

@@ -31,7 +31,7 @@
 * [**Goal**](#goals)📈
 * [**Goal**](#goals)📈
 * [**Contributing**](#contributing)
 * [**Contributing**](#contributing)
 * [**Requirements**](#requirements)
 * [**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)
 * [**What's Next**](#whats-next)
 * [**Contact**](#contact)
 * [**Contact**](#contact)
 * [**Apps using this library**](#apps-using-this-library)
 * [**Apps using this library**](#apps-using-this-library)
@@ -90,7 +90,7 @@ github "MessageKit/MessageKit"
 ## Contributing
 ## Contributing
 
 
 Great! Look over these things first.
 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).
 - 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. 
 - 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. 
 - 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.
 Add your app to the list of apps using this library and make a pull request.
 
 
 - [MediQuo](https://www.mediquo.com)
 - [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.*
 *Please provide attribution, it is greatly appreciated.*
 
 

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

@@ -23,6 +23,7 @@
  */
  */
 
 
 import Foundation
 import Foundation
+import MessageInputBar
 
 
 extension MessagesViewController {
 extension MessagesViewController {
 
 
@@ -31,7 +32,7 @@ extension MessagesViewController {
     internal func addKeyboardObservers() {
     internal func addKeyboardObservers() {
         NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.handleKeyboardDidChangeState(_:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
         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.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() {
     internal func removeKeyboardObservers() {
@@ -44,7 +45,7 @@ extension MessagesViewController {
 
 
     @objc
     @objc
     private func handleTextViewDidBeginEditing(_ notification: Notification) {
     private func handleTextViewDidBeginEditing(_ notification: Notification) {
-        if scrollsToBottomOnKeybordBeginsEditing {
+        if scrollsToBottomOnKeyboardBeginsEditing {
             guard let inputTextView = notification.object as? InputTextView, inputTextView === messageInputBar.inputTextView else { return }
             guard let inputTextView = notification.object as? InputTextView, inputTextView === messageInputBar.inputTextView else { return }
             messagesCollectionView.scrollToBottom(animated: true)
             messagesCollectionView.scrollToBottom(animated: true)
         }
         }
@@ -52,12 +53,35 @@ extension MessagesViewController {
 
 
     @objc
     @objc
     private func handleKeyboardDidChangeState(_ notification: Notification) {
     private func handleKeyboardDidChangeState(_ notification: Notification) {
-        guard let keyboardEndFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
-        
         guard !isMessagesControllerBeingDismissed 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
         let differenceOfBottomInset = newBottomInset - messageCollectionViewBottomInset
         
         
         if maintainPositionOnKeyboardFrameChanged && differenceOfBottomInset != 0 {
         if maintainPositionOnKeyboardFrameChanged && differenceOfBottomInset != 0 {
@@ -68,8 +92,10 @@ extension MessagesViewController {
         messageCollectionViewBottomInset = newBottomInset
         messageCollectionViewBottomInset = newBottomInset
     }
     }
 
 
+    // MARK: - Inset Computation
+
     @objc
     @objc
-    internal func adjustScrollViewInset() {
+    internal func adjustScrollViewTopInset() {
         if #available(iOS 11.0, *) {
         if #available(iOS 11.0, *) {
             // No need to add to the top contentInset
             // No need to add to the top contentInset
         } else {
         } 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, *) {
         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 Foundation
+import MessageInputBar
 
 
 extension MessagesViewController {
 extension MessagesViewController {
 
 

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

@@ -23,6 +23,7 @@
  */
  */
 
 
 import UIKit
 import UIKit
+import MessageInputBar
 
 
 /// A subclass of `UIViewController` with a `MessagesCollectionView` object
 /// A subclass of `UIViewController` with a `MessagesCollectionView` object
 /// that is used to display conversation interfaces.
 /// that is used to display conversation interfaces.
@@ -39,7 +40,7 @@ UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
     /// bottom whenever the `InputTextView` begins editing.
     /// bottom whenever the `InputTextView` begins editing.
     ///
     ///
     /// The default value of this property is `false`.
     /// 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`
     /// A Boolean value that determines whether the `MessagesCollectionView`
     /// maintains it's current position when the height of the `MessageInputBar` changes.
     /// maintains it's current position when the height of the `MessageInputBar` changes.
@@ -59,6 +60,17 @@ UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
         return false
         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
     private var isFirstLayout: Bool = true
     
     
     internal var isMessagesControllerBeingDismissed: Bool = false
     internal var isMessagesControllerBeingDismissed: Bool = false
@@ -94,14 +106,19 @@ UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
         isMessagesControllerBeingDismissed = true
         isMessagesControllerBeingDismissed = true
     }
     }
     
     
+    open override func viewDidDisappear(_ animated: Bool) {
+        super.viewDidDisappear(animated)
+        isMessagesControllerBeingDismissed = false
+    }
+    
     open override func viewDidLayoutSubviews() {
     open override func viewDidLayoutSubviews() {
         // Hack to prevent animation of the contentInset after viewDidAppear
         // Hack to prevent animation of the contentInset after viewDidAppear
         if isFirstLayout {
         if isFirstLayout {
             defer { isFirstLayout = false }
             defer { isFirstLayout = false }
             addKeyboardObservers()
             addKeyboardObservers()
-            messageCollectionViewBottomInset = keyboardOffsetFrame.height
+            messageCollectionViewBottomInset = requiredInitialScrollViewBottomInset()
         }
         }
-        adjustScrollViewInset()
+        adjustScrollViewTopInset()
     }
     }
 
 
     // MARK: - Initializers
     // MARK: - Initializers
@@ -164,6 +181,8 @@ UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
         return collectionView.messagesDataSource?.numberOfItems(inSection: section, in: collectionView) ?? 0
         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 {
     open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
 
 
         guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
         guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
@@ -190,7 +209,7 @@ UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
             cell.configure(with: message, at: indexPath, and: messagesCollectionView)
             cell.configure(with: message, at: indexPath, and: messagesCollectionView)
             return cell
             return cell
         case .custom:
         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.
     /// - indexPath: The `IndexPath` of the item to be displayed.
     /// The default return .zero
     /// The default return .zero
     open func sizeForItem(at indexPath: IndexPath) -> CGSize { 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 incomingMessageBottomLabelAlignment = LabelAlignment(textAlignment: .left, textInsets: UIEdgeInsets(left: 42))
     public var outgoingMessageBottomLabelAlignment = LabelAlignment(textAlignment: .right, textInsets: UIEdgeInsets(right: 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) {
     open override func configure(attributes: UICollectionViewLayoutAttributes) {
         guard let attributes = attributes as? MessagesCollectionViewLayoutAttributes else { return }
         guard let attributes = attributes as? MessagesCollectionViewLayoutAttributes else { return }
 
 
@@ -68,6 +74,9 @@ open class MessageSizeCalculator: CellSizeCalculator {
 
 
         attributes.messageBottomLabelAlignment = messageBottomLabelAlignment(for: message)
         attributes.messageBottomLabelAlignment = messageBottomLabelAlignment(for: message)
         attributes.messageBottomLabelSize = messageBottomLabelSize(for: message, at: indexPath)
         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 {
     open override func sizeForItem(at indexPath: IndexPath) -> CGSize {
@@ -86,41 +95,44 @@ open class MessageSizeCalculator: CellSizeCalculator {
         let messageVerticalPadding = messageContainerPadding(for: message).vertical
         let messageVerticalPadding = messageContainerPadding(for: message).vertical
         let avatarHeight = avatarSize(for: message).height
         let avatarHeight = avatarSize(for: message).height
         let avatarVerticalPosition = avatarPosition(for: message).vertical
         let avatarVerticalPosition = avatarPosition(for: message).vertical
+        let accessoryViewHeight = accessoryViewSize(for: message).height
 
 
         switch avatarVerticalPosition {
         switch avatarVerticalPosition {
         case .messageCenter:
         case .messageCenter:
             let totalLabelHeight: CGFloat = cellTopLabelHeight + messageTopLabelHeight
             let totalLabelHeight: CGFloat = cellTopLabelHeight + messageTopLabelHeight
                 + messageContainerHeight + messageVerticalPadding + messageBottomLabelHeight
                 + messageContainerHeight + messageVerticalPadding + messageBottomLabelHeight
-            return max(avatarHeight, totalLabelHeight)
+            let cellHeight = max(avatarHeight, totalLabelHeight)
+            return max(cellHeight, accessoryViewHeight)
         case .messageBottom:
         case .messageBottom:
             var cellHeight: CGFloat = 0
             var cellHeight: CGFloat = 0
             cellHeight += messageBottomLabelHeight
             cellHeight += messageBottomLabelHeight
             let labelsHeight = messageContainerHeight + messageVerticalPadding + cellTopLabelHeight + messageTopLabelHeight
             let labelsHeight = messageContainerHeight + messageVerticalPadding + cellTopLabelHeight + messageTopLabelHeight
             cellHeight += max(labelsHeight, avatarHeight)
             cellHeight += max(labelsHeight, avatarHeight)
-            return cellHeight
+            return max(cellHeight, accessoryViewHeight)
         case .messageTop:
         case .messageTop:
             var cellHeight: CGFloat = 0
             var cellHeight: CGFloat = 0
             cellHeight += cellTopLabelHeight
             cellHeight += cellTopLabelHeight
             cellHeight += messageTopLabelHeight
             cellHeight += messageTopLabelHeight
             let labelsHeight = messageContainerHeight + messageVerticalPadding + messageBottomLabelHeight
             let labelsHeight = messageContainerHeight + messageVerticalPadding + messageBottomLabelHeight
             cellHeight += max(labelsHeight, avatarHeight)
             cellHeight += max(labelsHeight, avatarHeight)
-            return cellHeight
+            return max(cellHeight, accessoryViewHeight)
         case .messageLabelTop:
         case .messageLabelTop:
             var cellHeight: CGFloat = 0
             var cellHeight: CGFloat = 0
             cellHeight += cellTopLabelHeight
             cellHeight += cellTopLabelHeight
             let messageLabelsHeight = messageContainerHeight + messageBottomLabelHeight + messageVerticalPadding + messageTopLabelHeight
             let messageLabelsHeight = messageContainerHeight + messageBottomLabelHeight + messageVerticalPadding + messageTopLabelHeight
             cellHeight += max(messageLabelsHeight, avatarHeight)
             cellHeight += max(messageLabelsHeight, avatarHeight)
-            return cellHeight
+            return max(cellHeight, accessoryViewHeight)
         case .cellTop, .cellBottom:
         case .cellTop, .cellBottom:
             let totalLabelHeight: CGFloat = cellTopLabelHeight + messageTopLabelHeight
             let totalLabelHeight: CGFloat = cellTopLabelHeight + messageTopLabelHeight
                 + messageContainerHeight + messageVerticalPadding + messageBottomLabelHeight
                 + messageContainerHeight + messageVerticalPadding + messageBottomLabelHeight
-            return max(avatarHeight, totalLabelHeight)
+            let cellHeight = max(avatarHeight, totalLabelHeight)
+            return max(cellHeight, accessoryViewHeight)
         }
         }
     }
     }
 
 
     // MARK: - Avatar
     // MARK: - Avatar
 
 
-    public func avatarPosition(for message: MessageType) -> AvatarPosition {
+    open func avatarPosition(for message: MessageType) -> AvatarPosition {
         let dataSource = messagesLayout.messagesDataSource
         let dataSource = messagesLayout.messagesDataSource
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         var position = isFromCurrentSender ? outgoingAvatarPosition : incomingAvatarPosition
         var position = isFromCurrentSender ? outgoingAvatarPosition : incomingAvatarPosition
@@ -134,7 +146,7 @@ open class MessageSizeCalculator: CellSizeCalculator {
         return position
         return position
     }
     }
 
 
-    public func avatarSize(for message: MessageType) -> CGSize {
+    open func avatarSize(for message: MessageType) -> CGSize {
         let dataSource = messagesLayout.messagesDataSource
         let dataSource = messagesLayout.messagesDataSource
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         return isFromCurrentSender ? outgoingAvatarSize : incomingAvatarSize
         return isFromCurrentSender ? outgoingAvatarSize : incomingAvatarSize
@@ -142,14 +154,14 @@ open class MessageSizeCalculator: CellSizeCalculator {
 
 
     // MARK: - Top cell Label
     // 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 layoutDelegate = messagesLayout.messagesLayoutDelegate
         let collectionView = messagesLayout.messagesCollectionView
         let collectionView = messagesLayout.messagesCollectionView
         let height = layoutDelegate.cellTopLabelHeight(for: message, at: indexPath, in: collectionView)
         let height = layoutDelegate.cellTopLabelHeight(for: message, at: indexPath, in: collectionView)
         return CGSize(width: messagesLayout.itemWidth, height: height)
         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 dataSource = messagesLayout.messagesDataSource
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         return isFromCurrentSender ? outgoingCellTopLabelAlignment : incomingCellTopLabelAlignment
         return isFromCurrentSender ? outgoingCellTopLabelAlignment : incomingCellTopLabelAlignment
@@ -157,14 +169,14 @@ open class MessageSizeCalculator: CellSizeCalculator {
     
     
     // MARK: - Top message Label
     // 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 layoutDelegate = messagesLayout.messagesLayoutDelegate
         let collectionView = messagesLayout.messagesCollectionView
         let collectionView = messagesLayout.messagesCollectionView
         let height = layoutDelegate.messageTopLabelHeight(for: message, at: indexPath, in: collectionView)
         let height = layoutDelegate.messageTopLabelHeight(for: message, at: indexPath, in: collectionView)
         return CGSize(width: messagesLayout.itemWidth, height: height)
         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 dataSource = messagesLayout.messagesDataSource
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         return isFromCurrentSender ? outgoingMessageTopLabelAlignment : incomingMessageTopLabelAlignment
         return isFromCurrentSender ? outgoingMessageTopLabelAlignment : incomingMessageTopLabelAlignment
@@ -172,22 +184,36 @@ open class MessageSizeCalculator: CellSizeCalculator {
 
 
     // MARK: - Bottom Label
     // 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 layoutDelegate = messagesLayout.messagesLayoutDelegate
         let collectionView = messagesLayout.messagesCollectionView
         let collectionView = messagesLayout.messagesCollectionView
         let height = layoutDelegate.messageBottomLabelHeight(for: message, at: indexPath, in: collectionView)
         let height = layoutDelegate.messageBottomLabelHeight(for: message, at: indexPath, in: collectionView)
         return CGSize(width: messagesLayout.itemWidth, height: height)
         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 dataSource = messagesLayout.messagesDataSource
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         return isFromCurrentSender ? outgoingMessageBottomLabelAlignment : incomingMessageBottomLabelAlignment
         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
     // MARK: - MessageContainer
 
 
-    public func messageContainerPadding(for message: MessageType) -> UIEdgeInsets {
+    open func messageContainerPadding(for message: MessageType) -> UIEdgeInsets {
         let dataSource = messagesLayout.messagesDataSource
         let dataSource = messagesLayout.messagesDataSource
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
         return isFromCurrentSender ? outgoingMessagePadding : incomingMessagePadding
         return isFromCurrentSender ? outgoingMessagePadding : incomingMessagePadding
@@ -201,7 +227,9 @@ open class MessageSizeCalculator: CellSizeCalculator {
     open func messageContainerMaxWidth(for message: MessageType) -> CGFloat {
     open func messageContainerMaxWidth(for message: MessageType) -> CGFloat {
         let avatarWidth = avatarSize(for: message).width
         let avatarWidth = avatarSize(for: message).width
         let messagePadding = messageContainerPadding(for: message)
         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
     // MARK: - Helpers

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

@@ -66,19 +66,31 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
 
 
     public override init() {
     public override init() {
         super.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) {
     required public init?(coder aDecoder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
+        super.init(coder: aDecoder)
+        
+        setupView()
+        setupObserver()
     }
     }
 
 
     deinit {
     deinit {
         NotificationCenter.default.removeObserver(self)
         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
     // MARK: - Attributes
 
 
@@ -126,11 +138,17 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
 
 
     lazy open var textMessageSizeCalculator = TextMessageSizeCalculator(layout: self)
     lazy open var textMessageSizeCalculator = TextMessageSizeCalculator(layout: self)
     lazy open var attributedTextMessageSizeCalculator = 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 photoMessageSizeCalculator = MediaMessageSizeCalculator(layout: self)
     lazy open var videoMessageSizeCalculator = MediaMessageSizeCalculator(layout: self)
     lazy open var videoMessageSizeCalculator = MediaMessageSizeCalculator(layout: self)
     lazy open var locationMessageSizeCalculator = LocationMessageSizeCalculator(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 {
     open func cellSizeCalculatorForItem(at indexPath: IndexPath) -> CellSizeCalculator {
         let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
         let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
         switch message.kind {
         switch message.kind {
@@ -147,7 +165,7 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
         case .location:
         case .location:
             return locationMessageSizeCalculator
             return locationMessageSizeCalculator
         case .custom:
         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) {
     public func setMessageOutgoingMessageBottomLabelAlignment(_ newAlignment: LabelAlignment) {
         messageSizeCalculators().forEach { $0.outgoingMessageBottomLabelAlignment = newAlignment }
         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
     /// Get all `MessageSizeCalculator`s
     open func messageSizeCalculators() -> [MessageSizeCalculator] {
     open func messageSizeCalculators() -> [MessageSizeCalculator] {
         return [textMessageSizeCalculator, attributedTextMessageSizeCalculator, emojiMessageSizeCalculator, photoMessageSizeCalculator, videoMessageSizeCalculator, locationMessageSizeCalculator]
         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 messageBottomLabelAlignment = LabelAlignment(textAlignment: .center, textInsets: .zero)
     public var messageBottomLabelSize: CGSize = .zero
     public var messageBottomLabelSize: CGSize = .zero
 
 
+    public var accessoryViewSize: CGSize = .zero
+    public var accessoryViewPadding: HorizontalEdgeInsets = .zero
+
     // MARK: - Methods
     // MARK: - Methods
 
 
     open override func copy(with zone: NSZone? = nil) -> Any {
     open override func copy(with zone: NSZone? = nil) -> Any {
@@ -63,6 +66,8 @@ open class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttribu
         copy.messageTopLabelSize = messageTopLabelSize
         copy.messageTopLabelSize = messageTopLabelSize
         copy.messageBottomLabelAlignment = messageBottomLabelAlignment
         copy.messageBottomLabelAlignment = messageBottomLabelAlignment
         copy.messageBottomLabelSize = messageBottomLabelSize
         copy.messageBottomLabelSize = messageBottomLabelSize
+        copy.accessoryViewSize = accessoryViewSize
+        copy.accessoryViewPadding = accessoryViewPadding
         return copy
         return copy
         // swiftlint:enable force_cast
         // swiftlint:enable force_cast
     }
     }
@@ -82,6 +87,8 @@ open class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttribu
                 && attributes.messageTopLabelSize == messageTopLabelSize
                 && attributes.messageTopLabelSize == messageTopLabelSize
                 && attributes.messageBottomLabelAlignment == messageBottomLabelAlignment
                 && attributes.messageBottomLabelAlignment == messageBottomLabelAlignment
                 && attributes.messageBottomLabelSize == messageBottomLabelSize
                 && attributes.messageBottomLabelSize == messageBottomLabelSize
+                && attributes.accessoryViewSize == accessoryViewSize
+                && attributes.accessoryViewPadding == accessoryViewPadding
         } else {
         } else {
             return false
             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)
     case emoji(String)
 
 
     /// A custom message.
     /// 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?)
     case custom(Any?)
 
 
     // MARK: - Not supported yet
     // MARK: - Not supported yet

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

@@ -36,9 +36,9 @@ internal class NSLayoutConstraintSet {
     internal var height: NSLayoutConstraint?
     internal var height: NSLayoutConstraint?
     
     
     internal init(top: NSLayoutConstraint? = nil, bottom: NSLayoutConstraint? = nil,
     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.top = top
         self.bottom = bottom
         self.bottom = bottom
         self.left = left
         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`
     /// `indexPath(for: cell)` method. Then using the returned `IndexPath` with the `MessagesDataSource`
     /// method `messageForItem(at:indexPath:messagesCollectionView)`.
     /// method `messageForItem(at:indexPath:messagesCollectionView)`.
     func didTapMessageBottomLabel(in cell: MessageCollectionViewCell)
     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 didTapMessageTopLabel(in cell: MessageCollectionViewCell) {}
 
 
     func didTapMessageBottomLabel(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`.
     /// The default value returned by this method is `nil`.
     func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString?
     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 {
 public extension MessagesDataSource {
@@ -116,5 +126,8 @@ public extension MessagesDataSource {
     func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
     func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
         return nil
         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 `?`.
     ///   The default image configured by this method is `?`.
     func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView)
     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
     // MARK: - Text Messages
 
 
     /// Specifies the color of the text for a `TextMessageCell`.
     /// Specifies the color of the text for a `TextMessageCell`.
@@ -194,6 +206,8 @@ public extension MessagesDisplayDelegate {
         avatarView.initials = "?"
         avatarView.initials = "?"
     }
     }
 
 
+    func configureAccessoryView(_ accessoryView: UIView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) {}
+
     // MARK: - Text Messages Defaults
     // MARK: - Text Messages Defaults
 
 
     func textColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor {
     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:
     /// - Note:
     ///   The default value returned by this method is zero.
     ///   The default value returned by this method is zero.
     func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat
     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 {
 public extension MessagesLayoutDelegate {
@@ -104,4 +114,8 @@ public extension MessagesLayoutDelegate {
     func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
     func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
         return 0
         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)
         super.init(frame: frame)
         prepareView()
         prepareView()
     }
     }
+    
+    required public init?(coder aDecoder: NSCoder) {
+        super.init(coder: aDecoder)
+        prepareView()
+    }
 
 
     convenience public init() {
     convenience public init() {
         self.init(frame: .zero)
         self.init(frame: .zero)
+        prepareView()
     }
     }
     
     
     private func setImageFrom(initials: String?) {
     private func setImageFrom(initials: String?) {
@@ -152,10 +158,6 @@ open class AvatarView: UIImageView {
         return CGRect(startX+2, startY, w-4, h)
         return CGRect(startX+2, startY, w-4, h)
     }
     }
 
 
-    required public init?(coder aDecoder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-
     // MARK: - Internal methods
     // MARK: - Internal methods
 
 
     internal func prepareView() {
     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) {
     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
         return label
     }()
     }()
 
 
+    // Should only add customized subviews - don't change accessoryView itself.
+    open var accessoryView: UIView = UIView()
+
     /// The `MessageCellDelegate` for the cell.
     /// The `MessageCellDelegate` for the cell.
     open weak var delegate: MessageCellDelegate?
     open weak var delegate: MessageCellDelegate?
 
 
@@ -70,10 +73,13 @@ open class MessageContentCell: MessageCollectionViewCell {
     }
     }
 
 
     required public init?(coder aDecoder: NSCoder) {
     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() {
     open func setupSubviews() {
+        contentView.addSubview(accessoryView)
         contentView.addSubview(cellTopLabel)
         contentView.addSubview(cellTopLabel)
         contentView.addSubview(messageTopLabel)
         contentView.addSubview(messageTopLabel)
         contentView.addSubview(messageBottomLabel)
         contentView.addSubview(messageBottomLabel)
@@ -99,6 +105,7 @@ open class MessageContentCell: MessageCollectionViewCell {
         layoutCellTopLabel(with: attributes)
         layoutCellTopLabel(with: attributes)
         layoutMessageTopLabel(with: attributes)
         layoutMessageTopLabel(with: attributes)
         layoutAvatarView(with: attributes)
         layoutAvatarView(with: attributes)
+        layoutAccessoryView(with: attributes)
     }
     }
 
 
     /// Used to configure the cell.
     /// Used to configure the cell.
@@ -122,6 +129,8 @@ open class MessageContentCell: MessageCollectionViewCell {
 
 
         displayDelegate.configureAvatarView(avatarView, for: message, at: indexPath, in: messagesCollectionView)
         displayDelegate.configureAvatarView(avatarView, for: message, at: indexPath, in: messagesCollectionView)
 
 
+        displayDelegate.configureAccessoryView(accessoryView, for: message, at: indexPath, in: messagesCollectionView)
+
         messageContainerView.backgroundColor = messageColor
         messageContainerView.backgroundColor = messageColor
         messageContainerView.style = messageStyle
         messageContainerView.style = messageStyle
 
 
@@ -149,6 +158,8 @@ open class MessageContentCell: MessageCollectionViewCell {
             delegate?.didTapMessageTopLabel(in: self)
             delegate?.didTapMessageTopLabel(in: self)
         case messageBottomLabel.frame.contains(touchLocation):
         case messageBottomLabel.frame.contains(touchLocation):
             delegate?.didTapMessageBottomLabel(in: self)
             delegate?.didTapMessageBottomLabel(in: self)
+        case accessoryView.frame.contains(touchLocation):
+            delegate?.didTapAccessoryView(in: self)
         default:
         default:
             break
             break
         }
         }
@@ -216,7 +227,12 @@ open class MessageContentCell: MessageCollectionViewCell {
                 fallthrough
                 fallthrough
             }
             }
         default:
         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 {
         switch attributes.avatarPosition.horizontal {
@@ -260,5 +276,26 @@ open class MessageContentCell: MessageCollectionViewCell {
 
 
         messageBottomLabel.frame = CGRect(origin: origin, size: attributes.messageBottomLabelSize)
         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) {
     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() }
             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?
     internal var messageLabelFont: UIFont?
 
 
@@ -159,12 +166,12 @@ open class MessageLabel: UILabel {
 
 
     public override init(frame: CGRect) {
     public override init(frame: CGRect) {
         super.init(frame: frame)
         super.init(frame: frame)
-        self.numberOfLines = 0
-        self.lineBreakMode = .byWordWrapping
+        setupView()
     }
     }
 
 
     public required init?(coder aDecoder: NSCoder) {
     public required init?(coder aDecoder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
+        super.init(coder: aDecoder)
+        setupView()
     }
     }
 
 
     // MARK: - Open Methods
     // MARK: - Open Methods
@@ -296,6 +303,11 @@ open class MessageLabel: UILabel {
             fatalError(MessageKitError.unrecognizedCheckingResult)
             fatalError(MessageKitError.unrecognizedCheckingResult)
         }
         }
     }
     }
+    
+    private func setupView() {
+        numberOfLines = 0
+        lineBreakMode = .byWordWrapping
+    }
 
 
     // MARK: - Parsing Text
     // MARK: - Parsing Text
 
 
@@ -304,7 +316,22 @@ open class MessageLabel: UILabel {
         let checkingTypes = enabledDetectors.reduce(0) { $0 | $1.textCheckingType.rawValue }
         let checkingTypes = enabledDetectors.reduce(0) { $0 | $1.textCheckingType.rawValue }
         let detector = try? NSDataDetector(types: checkingTypes)
         let detector = try? NSDataDetector(types: checkingTypes)
         let range = NSRange(location: 0, length: text.length)
         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]) {
     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 }
         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) {
     required public init?(coder aDecoder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
+        super.init(frame: .zero, collectionViewLayout: MessagesCollectionViewFlowLayout())
     }
     }
 
 
     public convenience init() {
     public convenience init() {
@@ -122,6 +122,13 @@ open class MessagesCollectionView: UICollectionView {
                  forSupplementaryViewOfKind: kind,
                  forSupplementaryViewOfKind: kind,
                  withReuseIdentifier: String(describing: T.self))
                  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
     /// 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 {
     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()
         setupSubviews()
         setupConstraints()
         setupConstraints()
-
-        triangleView.clipsToBounds = true
-        triangleView.backgroundColor = .black
-        backgroundColor = .playButtonLightGray
+        setupView()
     }
     }
 
 
     required public init?(coder aDecoder: NSCoder) {
     required public init?(coder aDecoder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
+        super.init(coder: aDecoder)
+        
+        setupSubviews()
+        setupConstraints()
+        setupView()
     }
     }
 
 
     // MARK: - Methods
     // MARK: - Methods
@@ -66,6 +67,13 @@ open class PlayButtonView: UIView {
     private func setupSubviews() {
     private func setupSubviews() {
         addSubview(triangleView)
         addSubview(triangleView)
     }
     }
+    
+    private func setupView() {
+        triangleView.clipsToBounds = true
+        triangleView.backgroundColor = .black
+        
+        backgroundColor = .playButtonLightGray
+    }
 
 
     private func setupConstraints() {
     private func setupConstraints() {
         triangleView.translatesAutoresizingMaskIntoConstraints = false
         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>
   <key>CFBundlePackageType</key>
   <string>FMWK</string>
   <string>FMWK</string>
   <key>CFBundleShortVersionString</key>
   <key>CFBundleShortVersionString</key>
-  <string>1.0.0</string>
+  <string>2.0.0</string>
   <key>CFBundleSignature</key>
   <key>CFBundleSignature</key>
   <string>????</string>
   <string>????</string>
   <key>CFBundleVersion</key>
   <key>CFBundleVersion</key>

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

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

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

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

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

@@ -1,6 +1,31 @@
 # Acknowledgements
 # Acknowledgements
 This application makes use of the following third party libraries:
 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
 ## MessageKit
 
 
 MIT License
 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
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 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
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 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
 if [[ "$CONFIGURATION" == "Debug" ]]; then
+  install_framework "${BUILT_PRODUCTS_DIR}/MessageInputBar/MessageInputBar.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/MessageKit/MessageKit.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/MessageKit/MessageKit.framework"
 fi
 fi
 if [[ "$CONFIGURATION" == "Release" ]]; then
 if [[ "$CONFIGURATION" == "Release" ]]; then
+  install_framework "${BUILT_PRODUCTS_DIR}/MessageInputBar/MessageInputBar.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/MessageKit/MessageKit.framework"
   install_framework "${BUILT_PRODUCTS_DIR}/MessageKit/MessageKit.framework"
 fi
 fi
 if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
 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
 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
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
 HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/openssl-ios-bitcode"
 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'
 LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
 LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/openssl-ios-bitcode/lib"
 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"
 OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
 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
 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
 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
 HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/openssl-ios-bitcode"
 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'
 LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
 LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/openssl-ios-bitcode/lib"
 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"
 OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_BUILD_DIR = ${BUILD_DIR}
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

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

@@ -585,10 +585,12 @@
 			);
 			);
 			inputPaths = (
 			inputPaths = (
 				"${SRCROOT}/Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-frameworks.sh",
 				"${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",
 				"${BUILT_PRODUCTS_DIR}/MessageKit/MessageKit.framework",
 			);
 			);
 			name = "[CP] Embed Pods Frameworks";
 			name = "[CP] Embed Pods Frameworks";
 			outputPaths = (
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MessageInputBar.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MessageKit.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MessageKit.framework",
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			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 UIKit
 import MessageKit
 import MessageKit
 import MapKit
 import MapKit
+import MessageInputBar
 
 
 class ChatViewController: MessagesViewController {
 class ChatViewController: MessagesViewController {
     let chatId: Int
     let chatId: Int
@@ -129,10 +130,11 @@ class ChatViewController: MessagesViewController {
         messagesCollectionView.messagesLayoutDelegate = self
         messagesCollectionView.messagesLayoutDelegate = self
         messagesCollectionView.messagesDisplayDelegate = self
         messagesCollectionView.messagesDisplayDelegate = self
         messagesCollectionView.messageCellDelegate = self
         messagesCollectionView.messageCellDelegate = self
+        
         messageInputBar.delegate = self
         messageInputBar.delegate = self
         messageInputBar.sendButton.tintColor = UIColor(red: 69/255, green: 193/255, blue: 89/255, alpha: 1)
         messageInputBar.sendButton.tintColor = UIColor(red: 69/255, green: 193/255, blue: 89/255, alpha: 1)
         // scrollsToBottomOnFirstLayout = true //default false
         // scrollsToBottomOnFirstLayout = true //default false
-        scrollsToBottomOnKeybordBeginsEditing = true // default false
+        scrollsToBottomOnKeyboardBeginsEditing = true // default false
         
         
         /*navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "ic_keyboard"),
         /*navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "ic_keyboard"),
                                                             style: .plain,
                                                             style: .plain,

Неке датотеке нису приказане због велике количине промена