Procházet zdrojové kódy

Updated MessageKit and added SnapKit

humanlikedisaster před 6 roky
rodič
revize
6524ebe154
100 změnil soubory, kde provedl 5470 přidání a 2160 odebrání
  1. 12 2
      Podfile
  2. 9 5
      Podfile.lock
  3. 9 5
      Pods/Manifest.lock
  4. 5 3
      Pods/MessageKit/README.md
  5. 0 99
      Pods/MessageKit/Sources/Controllers/MessagesViewController+DataSource.swift
  6. 0 102
      Pods/MessageKit/Sources/Controllers/MessagesViewController+Delegate.swift
  7. 16 19
      Pods/MessageKit/Sources/Controllers/MessagesViewController+Keyboard.swift
  8. 3 5
      Pods/MessageKit/Sources/Controllers/MessagesViewController+Menu.swift
  9. 150 23
      Pods/MessageKit/Sources/Controllers/MessagesViewController.swift
  10. 1 1
      Pods/MessageKit/Sources/Extensions/Bundle+Extensions.swift
  11. 1 1
      Pods/MessageKit/Sources/Extensions/CGRect+Extensions.swift
  12. 2 10
      Pods/MessageKit/Sources/Extensions/NSAttributedString+Extensions.swift
  13. 0 70
      Pods/MessageKit/Sources/Extensions/UICollectionView+Extensions.swift
  14. 5 5
      Pods/MessageKit/Sources/Extensions/UIColor+Extensions.swift
  15. 7 19
      Pods/MessageKit/Sources/Extensions/UIEdgeInsets+Extensions.swift
  16. 4 4
      Pods/MessageKit/Sources/Extensions/UIView+Extensions.swift
  17. 48 0
      Pods/MessageKit/Sources/Layout/CellSizeCalculator.swift
  18. 19 20
      Pods/MessageKit/Sources/Layout/LocationMessageSizeCalculator.swift
  19. 48 0
      Pods/MessageKit/Sources/Layout/MediaMessageSizeCalculator.swift
  20. 0 214
      Pods/MessageKit/Sources/Layout/MessageIntermediateLayoutAttributes.swift
  21. 228 0
      Pods/MessageKit/Sources/Layout/MessageSizeCalculator.swift
  22. 102 515
      Pods/MessageKit/Sources/Layout/MessagesCollectionViewFlowLayout.swift
  23. 40 18
      Pods/MessageKit/Sources/Layout/MessagesCollectionViewLayoutAttributes.swift
  24. 90 0
      Pods/MessageKit/Sources/Layout/TextMessageSizeCalculator.swift
  25. 18 4
      Pods/MessageKit/Sources/Models/AvatarPosition.swift
  26. 3 1
      Pods/MessageKit/Sources/Models/DetectorType.swift
  27. 16 30
      Pods/MessageKit/Sources/Models/LabelAlignment.swift
  28. 13 10
      Pods/MessageKit/Sources/Models/MessageKind.swift
  29. 13 11
      Pods/MessageKit/Sources/Models/MessageKitError.swift
  30. 2 2
      Pods/MessageKit/Sources/Models/MessageStyle.swift
  31. 20 14
      Pods/MessageKit/Sources/Models/NSConstraintLayoutSet.swift
  32. 36 0
      Pods/MessageKit/Sources/Protocols/LocationItem.swift
  33. 42 0
      Pods/MessageKit/Sources/Protocols/MediaItem.swift
  34. 25 13
      Pods/MessageKit/Sources/Protocols/MessageCellDelegate.swift
  35. 11 10
      Pods/MessageKit/Sources/Protocols/MessageInputBarDelegate.swift
  36. 25 0
      Pods/MessageKit/Sources/Protocols/MessageLabelDelegate.swift
  37. 4 7
      Pods/MessageKit/Sources/Protocols/MessageType.swift
  38. 38 8
      Pods/MessageKit/Sources/Protocols/MessagesDataSource.swift
  39. 61 72
      Pods/MessageKit/Sources/Protocols/MessagesDisplayDelegate.swift
  40. 36 206
      Pods/MessageKit/Sources/Protocols/MessagesLayoutDelegate.swift
  41. 30 79
      Pods/MessageKit/Sources/Supporting/MessageKit+Availability.swift
  42. 4 2
      Pods/MessageKit/Sources/Views/AvatarView.swift
  43. 8 8
      Pods/MessageKit/Sources/Views/Cells/LocationMessageCell.swift
  44. 22 11
      Pods/MessageKit/Sources/Views/Cells/MediaMessageCell.swift
  45. 4 111
      Pods/MessageKit/Sources/Views/Cells/MessageCollectionViewCell.swift
  46. 264 0
      Pods/MessageKit/Sources/Views/Cells/MessageContentCell.swift
  47. 10 8
      Pods/MessageKit/Sources/Views/Cells/TextMessageCell.swift
  48. 6 7
      Pods/MessageKit/Sources/Views/Headers & Footers/MessageReusableView.swift
  49. 1 1
      Pods/MessageKit/Sources/Views/InputStackView.swift
  50. 2 0
      Pods/MessageKit/Sources/Views/InputTextView.swift
  51. 10 12
      Pods/MessageKit/Sources/Views/InsetLabel.swift
  52. 3 5
      Pods/MessageKit/Sources/Views/MessageContainerView.swift
  53. 5 1
      Pods/MessageKit/Sources/Views/MessageInputBar.swift
  54. 29 4
      Pods/MessageKit/Sources/Views/MessageLabel.swift
  55. 49 6
      Pods/MessageKit/Sources/Views/MessagesCollectionView.swift
  56. 532 369
      Pods/Pods.xcodeproj/project.pbxproj
  57. 19 0
      Pods/SnapKit/LICENSE
  58. 129 0
      Pods/SnapKit/README.md
  59. 306 0
      Pods/SnapKit/Source/Constraint.swift
  60. 195 0
      Pods/SnapKit/Source/ConstraintAttributes.swift
  61. 37 0
      Pods/SnapKit/Source/ConstraintConfig.swift
  62. 147 0
      Pods/SnapKit/Source/ConstraintConstantTarget.swift
  63. 185 0
      Pods/SnapKit/Source/ConstraintDSL.swift
  64. 69 0
      Pods/SnapKit/Source/ConstraintDescription.swift
  65. 72 0
      Pods/SnapKit/Source/ConstraintInsetTarget.swift
  66. 35 0
      Pods/SnapKit/Source/ConstraintInsets.swift
  67. 61 0
      Pods/SnapKit/Source/ConstraintItem.swift
  68. 36 0
      Pods/SnapKit/Source/ConstraintLayoutGuide+Extensions.swift
  69. 37 0
      Pods/SnapKit/Source/ConstraintLayoutGuide.swift
  70. 66 0
      Pods/SnapKit/Source/ConstraintLayoutGuideDSL.swift
  71. 36 0
      Pods/SnapKit/Source/ConstraintLayoutSupport.swift
  72. 56 0
      Pods/SnapKit/Source/ConstraintLayoutSupportDSL.swift
  73. 204 0
      Pods/SnapKit/Source/ConstraintMaker.swift
  74. 56 0
      Pods/SnapKit/Source/ConstraintMakerEditable.swift
  75. 169 0
      Pods/SnapKit/Source/ConstraintMakerExtendable.swift
  76. 49 0
      Pods/SnapKit/Source/ConstraintMakerFinalizable.swift
  77. 68 0
      Pods/SnapKit/Source/ConstraintMakerPriortizable.swift
  78. 113 0
      Pods/SnapKit/Source/ConstraintMakerRelatable.swift
  79. 75 0
      Pods/SnapKit/Source/ConstraintMultiplierTarget.swift
  80. 69 0
      Pods/SnapKit/Source/ConstraintOffsetTarget.swift
  81. 77 0
      Pods/SnapKit/Source/ConstraintPriority.swift
  82. 85 0
      Pods/SnapKit/Source/ConstraintPriorityTarget.swift
  83. 66 0
      Pods/SnapKit/Source/ConstraintRelatableTarget.swift
  84. 48 0
      Pods/SnapKit/Source/ConstraintRelation.swift
  85. 152 0
      Pods/SnapKit/Source/ConstraintView+Extensions.swift
  86. 35 0
      Pods/SnapKit/Source/ConstraintView.swift
  87. 101 0
      Pods/SnapKit/Source/ConstraintViewDSL.swift
  88. 160 0
      Pods/SnapKit/Source/Debugging.swift
  89. 57 0
      Pods/SnapKit/Source/LayoutConstraint.swift
  90. 93 0
      Pods/SnapKit/Source/LayoutConstraintItem.swift
  91. 42 0
      Pods/SnapKit/Source/Typealiases.swift
  92. 36 0
      Pods/SnapKit/Source/UILayoutSupport+Extensions.swift
  93. 1 1
      Pods/Target Support Files/MessageKit/Info.plist
  94. 1 1
      Pods/Target Support Files/MessageKit/ResourceBundle-MessageKitAssets-Info.plist
  95. 23 0
      Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-acknowledgements.markdown
  96. 29 0
      Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-acknowledgements.plist
  97. 2 0
      Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios-frameworks.sh
  98. 3 3
      Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios.debug.xcconfig
  99. 3 3
      Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios.release.xcconfig
  100. 26 0
      Pods/Target Support Files/SnapKit/Info.plist

+ 12 - 2
Podfile

@@ -1,5 +1,15 @@
 target 'deltachat-ios' do
   use_frameworks!
-  pod 'openssl-ios-bitcode'
-  pod 'MessageKit'
+  pod 'openssl-ios-bitcode', '1.0.210'
+  pod 'MessageKit', '1.0.0'
+  pod 'SnapKit', '~> 4.0.0'
+  post_install do |installer|
+      installer.pods_project.targets.each do |target|
+          if target.name == 'MessageKit'
+              target.build_configurations.each do |config|
+                  config.build_settings['SWIFT_VERSION'] = '4.0'
+              end
+          end
+      end
+  end
 end

+ 9 - 5
Podfile.lock

@@ -1,20 +1,24 @@
 PODS:
-  - MessageKit (0.13.3)
+  - MessageKit (1.0.0)
   - openssl-ios-bitcode (1.0.210)
+  - SnapKit (4.0.1)
 
 DEPENDENCIES:
-  - MessageKit
-  - openssl-ios-bitcode
+  - MessageKit (= 1.0.0)
+  - openssl-ios-bitcode (= 1.0.210)
+  - SnapKit (~> 4.0.0)
 
 SPEC REPOS:
   https://github.com/cocoapods/specs.git:
     - MessageKit
     - openssl-ios-bitcode
+    - SnapKit
 
 SPEC CHECKSUMS:
-  MessageKit: 63c5811bdf1087384c76732fa4b5479b2ed11568
+  MessageKit: 16160036b16476b04bd0e9f2c7ce67e662e503e4
   openssl-ios-bitcode: c833701a4488bd43de0051db41cfa75f6fef8109
+  SnapKit: 0de968a9fec17499afa29683b05d0c775b6d1c29
 
-PODFILE CHECKSUM: c057d65ca0f57313f89f48ea66fc7773d4a562aa
+PODFILE CHECKSUM: b18882081bc3e0790641d9587f94f63500487061
 
 COCOAPODS: 1.5.3

+ 9 - 5
Pods/Manifest.lock

@@ -1,20 +1,24 @@
 PODS:
-  - MessageKit (0.13.3)
+  - MessageKit (1.0.0)
   - openssl-ios-bitcode (1.0.210)
+  - SnapKit (4.0.1)
 
 DEPENDENCIES:
-  - MessageKit
-  - openssl-ios-bitcode
+  - MessageKit (= 1.0.0)
+  - openssl-ios-bitcode (= 1.0.210)
+  - SnapKit (~> 4.0.0)
 
 SPEC REPOS:
   https://github.com/cocoapods/specs.git:
     - MessageKit
     - openssl-ios-bitcode
+    - SnapKit
 
 SPEC CHECKSUMS:
-  MessageKit: 63c5811bdf1087384c76732fa4b5479b2ed11568
+  MessageKit: 16160036b16476b04bd0e9f2c7ce67e662e503e4
   openssl-ios-bitcode: c833701a4488bd43de0051db41cfa75f6fef8109
+  SnapKit: 0de968a9fec17499afa29683b05d0c775b6d1c29
 
-PODFILE CHECKSUM: c057d65ca0f57313f89f48ea66fc7773d4a562aa
+PODFILE CHECKSUM: b18882081bc3e0790641d9587f94f63500487061
 
 COCOAPODS: 1.5.3

+ 5 - 3
Pods/MessageKit/README.md

@@ -56,9 +56,9 @@ See [VISION.md](https://github.com/MessageKit/MessageKit/blob/master/VISION.md)
 pod 'MessageKit'
 ````
 
-If your project is still using Swift 3. Add the following code in your Podfile.
+If your project is still using Swift 3, you can add the following code to your Podfile:
 
-````
+````ruby
 target 'TARGET_NAME' do
     pod 'MessageKit'
     ...
@@ -78,7 +78,7 @@ end
 
 To integrate MessageKit using Carthage, add the following to your `Cartfile`:
 
-````ruby
+````
 github "MessageKit/MessageKit"
 ````
 
@@ -115,6 +115,8 @@ Interested in contributing to MessageKit? Click here to join our [Slack](https:/
 
 Add your app to the list of apps using this library and make a pull request.
 
+- [MediQuo](https://www.mediquo.com)
+
 *Please provide attribution, it is greatly appreciated.*
 
 ## Core Team

+ 0 - 99
Pods/MessageKit/Sources/Controllers/MessagesViewController+DataSource.swift

@@ -1,99 +0,0 @@
-/*
- 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 MessagesViewController: UICollectionViewDataSource {
-
-    open func numberOfSections(in collectionView: UICollectionView) -> Int {
-        guard let collectionView = collectionView as? MessagesCollectionView else {
-            fatalError(MessageKitError.notMessagesCollectionView)
-        }
-        // Each message is its own section
-        return collectionView.messagesDataSource?.numberOfMessages(in: collectionView) ?? 0
-    }
-
-    open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
-        guard let collectionView = collectionView as? MessagesCollectionView else {
-            fatalError(MessageKitError.notMessagesCollectionView)
-        }
-        let messageCount = collectionView.messagesDataSource?.numberOfMessages(in: collectionView) ?? 0
-        // There will only ever be 1 message per section
-        return messageCount > 0 ? 1 : 0
-    }
-
-    open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
-
-        guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
-            fatalError(MessageKitError.notMessagesCollectionView)
-        }
-
-        guard let messagesDataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-
-        let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
-
-        switch message.data {
-        case .text, .attributedText, .emoji:
-            let cell = messagesCollectionView.dequeueReusableCell(TextMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .photo, .video:
-            let cell = messagesCollectionView.dequeueReusableCell(MediaMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .location:
-            let cell = messagesCollectionView.dequeueReusableCell(LocationMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        }
-    }
-
-    open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
-
-        guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
-            fatalError(MessageKitError.notMessagesCollectionView)
-        }
-
-        guard let dataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-
-        guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
-            fatalError(MessageKitError.nilMessagesDisplayDelegate)
-        }
-
-        let message = dataSource.messageForItem(at: indexPath, in: messagesCollectionView)
-
-        switch kind {
-        case UICollectionElementKindSectionHeader:
-            return displayDelegate.messageHeaderView(for: message, at: indexPath, in: messagesCollectionView)
-        case UICollectionElementKindSectionFooter:
-            return displayDelegate.messageFooterView(for: message, at: indexPath, in: messagesCollectionView)
-        default:
-            fatalError(MessageKitError.unrecognizedSectionKind)
-        }
-    }
-}

+ 0 - 102
Pods/MessageKit/Sources/Controllers/MessagesViewController+Delegate.swift

@@ -1,102 +0,0 @@
-/*
- 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 MessagesViewController: UICollectionViewDelegateFlowLayout {
-
-    open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
-        guard let messagesFlowLayout = collectionViewLayout as? MessagesCollectionViewFlowLayout else { return .zero }
-        return messagesFlowLayout.sizeForItem(at: indexPath)
-    }
-
-    open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
-
-        guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
-            fatalError(MessageKitError.notMessagesCollectionView)
-        }
-        guard let dataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-        guard let layoutDelegate = messagesCollectionView.messagesLayoutDelegate else {
-            fatalError(MessageKitError.nilMessagesLayoutDeleagte)
-        }
-        // Could pose a problem if subclass behaviors allows more than one item per section
-        let indexPath = IndexPath(item: 0, section: section)
-        let message = dataSource.messageForItem(at: indexPath, in: messagesCollectionView)
-        return layoutDelegate.headerViewSize(for: message, at: indexPath, in: messagesCollectionView)
-    }
-
-    open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
-        guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
-            fatalError(MessageKitError.notMessagesCollectionView)
-        }
-        guard let dataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-        guard let layoutDelegate = messagesCollectionView.messagesLayoutDelegate else {
-            fatalError(MessageKitError.nilMessagesLayoutDeleagte)
-        }
-        // Could pose a problem if subclass behaviors allows more than one item per section
-        let indexPath = IndexPath(item: 0, section: section)
-        let message = dataSource.messageForItem(at: indexPath, in: messagesCollectionView)
-        return layoutDelegate.footerViewSize(for: message, at: indexPath, in: messagesCollectionView)
-    }
-
-    open func collectionView(_ collectionView: UICollectionView, shouldShowMenuForItemAt indexPath: IndexPath) -> Bool {
-        guard let messagesDataSource = messagesCollectionView.messagesDataSource else { return false }
-        let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
-
-        switch message.data {
-        case .text, .attributedText, .emoji, .photo:
-            selectedIndexPathForMenu = indexPath
-            return true
-        default:
-            return false
-        }
-    }
-
-    open func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
-        return (action == NSSelectorFromString("copy:"))
-    }
-
-    open func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {
-        guard let messagesDataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-        let pasteBoard = UIPasteboard.general
-        let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
-
-        switch message.data {
-        case .text(let text), .emoji(let text):
-            pasteBoard.string = text
-        case .attributedText(let attributedText):
-            pasteBoard.string = attributedText.string
-        case .photo(let image):
-            pasteBoard.image = image
-        default:
-            break
-        }
-    }
-}

+ 16 - 19
Pods/MessageKit/Sources/Controllers/MessagesViewController+Keyboard.swift

@@ -28,13 +28,13 @@ extension MessagesViewController {
 
     // MARK: - Register / Unregister Observers
 
-    func addKeyboardObservers() {
+    internal func addKeyboardObservers() {
         NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.handleKeyboardDidChangeState(_:)), name: .UIKeyboardWillChangeFrame, object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.handleTextViewDidBeginEditing(_:)), name: .UITextViewTextDidBeginEditing, object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.adjustScrollViewInset), name: .UIDeviceOrientationDidChange, object: nil)
     }
 
-    func removeKeyboardObservers() {
+    internal func removeKeyboardObservers() {
         NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillChangeFrame, object: nil)
         NotificationCenter.default.removeObserver(self, name: .UITextViewTextDidBeginEditing, object: nil)
         NotificationCenter.default.removeObserver(self, name: .UIDeviceOrientationDidChange, object: nil)
@@ -53,26 +53,23 @@ extension MessagesViewController {
     @objc
     private func handleKeyboardDidChangeState(_ notification: Notification) {
         guard let keyboardEndFrame = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? CGRect else { return }
-
-        if (keyboardEndFrame.origin.y + keyboardEndFrame.size.height) > UIScreen.main.bounds.height {
-            // Hardware keyboard is found
-            messageCollectionViewBottomInset = view.frame.size.height - keyboardEndFrame.origin.y - iPhoneXBottomInset
-        } else {
-            //Software keyboard is found
-            let afterBottomInset = keyboardEndFrame.height > keyboardOffsetFrame.height ? (keyboardEndFrame.height - iPhoneXBottomInset) : keyboardOffsetFrame.height
-            let differenceOfBottomInset = afterBottomInset - messageCollectionViewBottomInset
-
-            if maintainPositionOnKeyboardFrameChanged && differenceOfBottomInset != 0 {
-                let contentOffset = CGPoint(x: messagesCollectionView.contentOffset.x, y: messagesCollectionView.contentOffset.y + differenceOfBottomInset)
-                messagesCollectionView.setContentOffset(contentOffset, animated: false)
-            }
-
-            messageCollectionViewBottomInset = afterBottomInset
+        
+        guard !isMessagesControllerBeingDismissed else { return }
+        
+        let newBottomInset = view.frame.height - keyboardEndFrame.minY - iPhoneXBottomInset
+        
+        let differenceOfBottomInset = newBottomInset - messageCollectionViewBottomInset
+        
+        if maintainPositionOnKeyboardFrameChanged && differenceOfBottomInset != 0 {
+            let contentOffset = CGPoint(x: messagesCollectionView.contentOffset.x, y: messagesCollectionView.contentOffset.y + differenceOfBottomInset)
+            messagesCollectionView.setContentOffset(contentOffset, animated: false)
         }
+        
+        messageCollectionViewBottomInset = newBottomInset
     }
 
     @objc
-    func adjustScrollViewInset() {
+    internal func adjustScrollViewInset() {
         if #available(iOS 11.0, *) {
             // No need to add to the top contentInset
         } else {
@@ -86,7 +83,7 @@ extension MessagesViewController {
 
     // MARK: - Helpers
 
-    var keyboardOffsetFrame: CGRect {
+    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))
     }

+ 3 - 5
Pods/MessageKit/Sources/Controllers/MessagesViewController+Menu.swift

@@ -28,13 +28,11 @@ extension MessagesViewController {
 
     // MARK: - Register / Unregister Observers
 
-    /// Add observer for `UIMenuControllerWillShowMenu` notification
-    func addMenuControllerObservers() {
+    internal func addMenuControllerObservers() {
         NotificationCenter.default.addObserver(self, selector: #selector(MessagesViewController.menuControllerWillShow(_:)), name: .UIMenuControllerWillShowMenu, object: nil)
     }
 
-    /// Remove observer for `UIMenuControllerWillShowMenu` notification
-    func removeMenuControllerObservers() {
+    internal func removeMenuControllerObservers() {
         NotificationCenter.default.removeObserver(self, name: .UIMenuControllerWillShowMenu, object: nil)
     }
 
@@ -57,7 +55,7 @@ extension MessagesViewController {
 
         currentMenuController.setMenuVisible(false, animated: false)
 
-        guard let selectedCell = messagesCollectionView.cellForItem(at: selectedIndexPath) as? MessageCollectionViewCell else { return }
+        guard let selectedCell = messagesCollectionView.cellForItem(at: selectedIndexPath) as? MessageContentCell else { return }
         let selectedCellMessageBubbleFrame = selectedCell.convert(selectedCell.messageContainerView.frame, to: view)
 
         var messageInputBarFrame: CGRect = .zero

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

@@ -24,9 +24,10 @@
 
 import UIKit
 
-open class MessagesViewController: UIViewController {
-    
-    // MARK: - Properties [Public]
+/// A subclass of `UIViewController` with a `MessagesCollectionView` object
+/// that is used to display conversation interfaces.
+open class MessagesViewController: UIViewController,
+UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
 
     /// The `MessagesCollectionView` managed by the messages view controller object.
     open var messagesCollectionView = MessagesCollectionView()
@@ -58,13 +59,13 @@ open class MessagesViewController: UIViewController {
         return false
     }
 
-    /// A Boolean value used to determine if `viewDidLayoutSubviews()` has been called.
     private var isFirstLayout: Bool = true
     
-    /// Indicated selected indexPath when handle menu action
-    var selectedIndexPathForMenu: IndexPath?
+    internal var isMessagesControllerBeingDismissed: Bool = false
+
+    internal var selectedIndexPathForMenu: IndexPath?
 
-    var messageCollectionViewBottomInset: CGFloat = 0 {
+    internal var messageCollectionViewBottomInset: CGFloat = 0 {
         didSet {
             messagesCollectionView.contentInset.bottom = messageCollectionViewBottomInset
             messagesCollectionView.scrollIndicatorInsets.bottom = messageCollectionViewBottomInset
@@ -78,12 +79,21 @@ open class MessagesViewController: UIViewController {
         setupDefaults()
         setupSubviews()
         setupConstraints()
-        registerReusableViews()
         setupDelegates()
         addMenuControllerObservers()
         addObservers()
     }
     
+    open override func viewDidAppear(_ animated: Bool) {
+        super.viewDidAppear(animated)
+        isMessagesControllerBeingDismissed = false
+    }
+    
+    open override func viewWillDisappear(_ animated: Bool) {
+        super.viewWillDisappear(animated)
+        isMessagesControllerBeingDismissed = true
+    }
+    
     open override func viewDidLayoutSubviews() {
         // Hack to prevent animation of the contentInset after viewDidAppear
         if isFirstLayout {
@@ -105,7 +115,6 @@ open class MessagesViewController: UIViewController {
 
     // MARK: - Methods [Private]
 
-    /// Sets the default values for the MessagesViewController
     private func setupDefaults() {
         extendedLayoutIncludesOpaqueBars = true
         automaticallyAdjustsScrollViewInsets = false
@@ -114,29 +123,15 @@ open class MessagesViewController: UIViewController {
         messagesCollectionView.alwaysBounceVertical = true
     }
 
-    /// Sets the delegate and dataSource of the messagesCollectionView property.
     private func setupDelegates() {
         messagesCollectionView.delegate = self
         messagesCollectionView.dataSource = self
     }
 
-    /// Adds the messagesCollectionView to the controllers root view.
     private func setupSubviews() {
         view.addSubview(messagesCollectionView)
     }
 
-    /// Registers all cells and supplementary views of the messagesCollectionView property.
-    private func registerReusableViews() {
-        messagesCollectionView.register(TextMessageCell.self)
-        messagesCollectionView.register(MediaMessageCell.self)
-        messagesCollectionView.register(LocationMessageCell.self)
-
-        messagesCollectionView.register(MessageFooterView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter)
-        messagesCollectionView.register(MessageHeaderView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader)
-        messagesCollectionView.register(MessageDateHeaderView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader)
-    }
-
-    /// Sets the constraints of the `MessagesCollectionView`.
     private func setupConstraints() {
         messagesCollectionView.translatesAutoresizingMaskIntoConstraints = false
         
@@ -152,6 +147,138 @@ open class MessagesViewController: UIViewController {
             NSLayoutConstraint.activate([top, bottom, trailing, leading])
         }
     }
+
+    // MARK: - UICollectionViewDataSource
+
+    open func numberOfSections(in collectionView: UICollectionView) -> Int {
+        guard let collectionView = collectionView as? MessagesCollectionView else {
+            fatalError(MessageKitError.notMessagesCollectionView)
+        }
+        return collectionView.messagesDataSource?.numberOfSections(in: collectionView) ?? 0
+    }
+
+    open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+        guard let collectionView = collectionView as? MessagesCollectionView else {
+            fatalError(MessageKitError.notMessagesCollectionView)
+        }
+        return collectionView.messagesDataSource?.numberOfItems(inSection: section, in: collectionView) ?? 0
+    }
+
+    open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+
+        guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
+            fatalError(MessageKitError.notMessagesCollectionView)
+        }
+
+        guard let messagesDataSource = messagesCollectionView.messagesDataSource else {
+            fatalError(MessageKitError.nilMessagesDataSource)
+        }
+
+        let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
+
+        switch message.kind {
+        case .text, .attributedText, .emoji:
+            let cell = messagesCollectionView.dequeueReusableCell(TextMessageCell.self, for: indexPath)
+            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
+            return cell
+        case .photo, .video:
+            let cell = messagesCollectionView.dequeueReusableCell(MediaMessageCell.self, for: indexPath)
+            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
+            return cell
+        case .location:
+            let cell = messagesCollectionView.dequeueReusableCell(LocationMessageCell.self, for: indexPath)
+            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
+            return cell
+        case .custom:
+            fatalError(MessageKitError.customDataUnresolvedCell)
+        }
+    }
+
+    open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
+
+        guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
+            fatalError(MessageKitError.notMessagesCollectionView)
+        }
+
+        guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
+            fatalError(MessageKitError.nilMessagesDisplayDelegate)
+        }
+
+        switch kind {
+        case UICollectionElementKindSectionHeader:
+            return displayDelegate.messageHeaderView(for: indexPath, in: messagesCollectionView)
+        case UICollectionElementKindSectionFooter:
+            return displayDelegate.messageFooterView(for: indexPath, in: messagesCollectionView)
+        default:
+            fatalError(MessageKitError.unrecognizedSectionKind)
+        }
+    }
+
+    // MARK: - UICollectionViewDelegateFlowLayout
+
+    open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
+        guard let messagesFlowLayout = collectionViewLayout as? MessagesCollectionViewFlowLayout else { return .zero }
+        return messagesFlowLayout.sizeForItem(at: indexPath)
+    }
+
+    open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
+
+        guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
+            fatalError(MessageKitError.notMessagesCollectionView)
+        }
+        guard let layoutDelegate = messagesCollectionView.messagesLayoutDelegate else {
+            fatalError(MessageKitError.nilMessagesLayoutDelegate)
+        }
+        return layoutDelegate.headerViewSize(for: section, in: messagesCollectionView)
+    }
+
+    open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
+        guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
+            fatalError(MessageKitError.notMessagesCollectionView)
+        }
+        guard let layoutDelegate = messagesCollectionView.messagesLayoutDelegate else {
+            fatalError(MessageKitError.nilMessagesLayoutDelegate)
+        }
+        return layoutDelegate.footerViewSize(for: section, in: messagesCollectionView)
+    }
+
+    open func collectionView(_ collectionView: UICollectionView, shouldShowMenuForItemAt indexPath: IndexPath) -> Bool {
+        guard let messagesDataSource = messagesCollectionView.messagesDataSource else { return false }
+        let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
+
+        switch message.kind {
+        case .text, .attributedText, .emoji, .photo:
+            selectedIndexPathForMenu = indexPath
+            return true
+        default:
+            return false
+        }
+    }
+
+    open func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
+        return (action == NSSelectorFromString("copy:"))
+    }
+
+    open func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {
+        guard let messagesDataSource = messagesCollectionView.messagesDataSource else {
+            fatalError(MessageKitError.nilMessagesDataSource)
+        }
+        let pasteBoard = UIPasteboard.general
+        let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
+
+        switch message.kind {
+        case .text(let text), .emoji(let text):
+            pasteBoard.string = text
+        case .attributedText(let attributedText):
+            pasteBoard.string = attributedText.string
+        case .photo(let mediaItem):
+            pasteBoard.image = mediaItem.image ?? mediaItem.placeholderImage
+        default:
+            break
+        }
+    }
+
+    // MARK: - Helpers
     
     private func addObservers() {
         NotificationCenter.default.addObserver(

+ 1 - 1
Pods/MessageKit/Sources/Extensions/Bundle+Extensions.swift

@@ -26,7 +26,7 @@ import Foundation
 
 extension Bundle {
 
-    static func messageKitAssetBundle() -> Bundle {
+    internal static func messageKitAssetBundle() -> Bundle {
         let podBundle = Bundle(for: MessagesViewController.self)
         
         guard let resourceBundleUrl = podBundle.url(forResource: "MessageKitAssets", withExtension: "bundle") else {

+ 1 - 1
Pods/MessageKit/Sources/Extensions/CGRect+Extensions.swift

@@ -26,7 +26,7 @@ import Foundation
 
 extension CGRect {
     
-    init(_ x: CGFloat, _ y: CGFloat, _ w: CGFloat, _ h: CGFloat) {
+    internal init(_ x: CGFloat, _ y: CGFloat, _ w: CGFloat, _ h: CGFloat) {
         self.init(x: x, y: y, width: w, height: h)
     }
 

+ 2 - 10
Pods/MessageKit/Sources/Extensions/NSAttributedString+Extensions.swift

@@ -26,18 +26,10 @@ import Foundation
 
 extension NSAttributedString {
 
-    func height(considering width: CGFloat) -> CGFloat {
-
-        let constraintBox = CGSize(width: width, height: .greatestFiniteMagnitude)
-        let rect = self.boundingRect(with: constraintBox, options: .usesLineFragmentOrigin, context: nil)
-        return rect.height
-
-    }
-
-    func width(considering height: CGFloat) -> CGFloat {
+    internal func width(considering height: CGFloat) -> CGFloat {
 
         let constraintBox = CGSize(width: .greatestFiniteMagnitude, height: height)
-        let rect = self.boundingRect(with: constraintBox, options: .usesLineFragmentOrigin, context: nil)
+        let rect = self.boundingRect(with: constraintBox, options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)
         return rect.width
         
     }

+ 0 - 70
Pods/MessageKit/Sources/Extensions/UICollectionView+Extensions.swift

@@ -1,70 +0,0 @@
-/*
- 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
-
-/// Optional Cell Protocol to Simplify registration/cell type loading in a generic way
-public protocol CollectionViewReusable: AnyObject {
-    static func reuseIdentifier() -> String
-}
-
-public extension MessagesCollectionView {
-    /// Registers a particular cell using its reuse-identifier
-    func register<CellType: UICollectionViewCell & CollectionViewReusable>(_ cellClass: CellType.Type) {
-	    register(cellClass, forCellWithReuseIdentifier: CellType.reuseIdentifier())
-    }
-
-    /// Registers a reusable view for a specific SectionKind
-    func register<ViewType: UICollectionReusableView & CollectionViewReusable>(_ headerFooterClass: ViewType.Type, forSupplementaryViewOfKind kind: String) {
-	    register(headerFooterClass,
-	             forSupplementaryViewOfKind: kind,
-	             withReuseIdentifier: ViewType.reuseIdentifier())
-    }
-
-    /// Generically dequeues a cell of the correct type allowing you to avoid scattering your code with guard-let-else-fatal
-    func dequeueReusableCell<CellType: UICollectionViewCell & CollectionViewReusable>(_ cellClass: CellType.Type, for indexPath: IndexPath) -> CellType {
-	    guard let cell = dequeueReusableCell(withReuseIdentifier: cellClass.reuseIdentifier(), for: indexPath) as? CellType else {
-    	    fatalError("Unable to dequeue \(String(describing: cellClass)) with reuseId of \(cellClass.reuseIdentifier())")
-	    }
-	    return cell
-    }
-
-    /// Generically dequeues a header of the correct type allowing you to avoid scattering your code with guard-let-else-fatal
-    func dequeueReusableHeaderView<ViewType: UICollectionReusableView & CollectionViewReusable>(_ viewClass: ViewType.Type, for indexPath: IndexPath) -> ViewType {
-        let view = dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: viewClass.reuseIdentifier(), for: indexPath)
-        guard let viewType = view as? ViewType else {
-            fatalError("Unable to dequeue \(String(describing: viewClass)) with reuseId of \(viewClass.reuseIdentifier())")
-        }
-        return viewType
-    }
-
-    /// Generically dequeues a footer of the correct type allowing you to avoid scattering your code with guard-let-else-fatal
-    func dequeueReusableFooterView<ViewType: UICollectionReusableView & CollectionViewReusable>(_ viewClass: ViewType.Type, for indexPath: IndexPath) -> ViewType {
-        let view = dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionFooter, withReuseIdentifier: viewClass.reuseIdentifier(), for: indexPath)
-        guard let viewType = view as? ViewType else {
-            fatalError("Unable to dequeue \(String(describing: viewClass)) with reuseId of \(viewClass.reuseIdentifier())")
-        }
-        return viewType
-    }
-}

+ 5 - 5
Pods/MessageKit/Sources/Extensions/UIColor+Extensions.swift

@@ -26,14 +26,14 @@ import Foundation
 
 extension UIColor {
 
-    static let incomingGray = UIColor(red: 230/255, green: 230/255, blue: 235/255, alpha: 1.0)
+    internal static let incomingGray = UIColor(red: 230/255, green: 230/255, blue: 235/255, alpha: 1.0)
 
-    static let outgoingGreen = UIColor(red: 69/255, green: 214/255, blue: 93/255, alpha: 1.0)
+    internal static let outgoingGreen = UIColor(red: 69/255, green: 214/255, blue: 93/255, alpha: 1.0)
 
-    static let inputBarGray = UIColor(red: 247/255, green: 247/255, blue: 247/255, alpha: 1.0)
+    internal static let inputBarGray = UIColor(red: 247/255, green: 247/255, blue: 247/255, alpha: 1.0)
 
-    static let playButtonLightGray = UIColor(red: 230/255, green: 230/255, blue: 230/255, alpha: 1.0)
+    internal static let playButtonLightGray = UIColor(red: 230/255, green: 230/255, blue: 230/255, alpha: 1.0)
 
-    static let sendButtonBlue = UIColor(red: 15/255, green: 135/255, blue: 255/255, alpha: 1.0)
+    internal static let sendButtonBlue = UIColor(red: 15/255, green: 135/255, blue: 255/255, alpha: 1.0)
 
 }

+ 7 - 19
Pods/MessageKit/Sources/Views/Headers & Footers/MessageDateHeaderView.swift → Pods/MessageKit/Sources/Extensions/UIEdgeInsets+Extensions.swift

@@ -22,28 +22,16 @@
  SOFTWARE.
  */
 
-import UIKit
+import Foundation
 
-open class MessageDateHeaderView: MessageHeaderView {
-    open override class func reuseIdentifier() -> String { return "messagekit.header.date" }
+extension UIEdgeInsets {
 
-    // MARK: - Properties
-
-    open let dateLabel = UILabel()
-
-    // MARK: - Initializers
-
-    public override init(frame: CGRect) {
-        super.init(frame: frame)
-        addSubview(dateLabel)
-        dateLabel.fillSuperview()
-        dateLabel.textAlignment = .center
-        dateLabel.font = .boldSystemFont(ofSize: 10)
-        dateLabel.textColor = .darkGray
+    internal var vertical: CGFloat {
+        return top + bottom
     }
-    
-    public required init?(coder aDecoder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
+
+    internal var horizontal: CGFloat {
+        return left + right
     }
 
 }

+ 4 - 4
Pods/MessageKit/Sources/Extensions/UIView+Extensions.swift

@@ -26,7 +26,7 @@ import UIKit
 
 extension UIView {
     
-    func fillSuperview() {
+    internal func fillSuperview() {
         guard let superview = self.superview else {
             return
         }
@@ -41,7 +41,7 @@ extension UIView {
 	    NSLayoutConstraint.activate(constraints)
     }
 
-    func centerInSuperview() {
+    internal func centerInSuperview() {
         guard let superview = self.superview else {
             return
         }
@@ -53,7 +53,7 @@ extension UIView {
         NSLayoutConstraint.activate(constraints)
     }
     
-    func constraint(equalTo size: CGSize) {
+    internal func constraint(equalTo size: CGSize) {
         guard superview != nil else { return }
         translatesAutoresizingMaskIntoConstraints = false
         let constraints: [NSLayoutConstraint] = [
@@ -65,7 +65,7 @@ extension UIView {
     }
 
     @discardableResult
-    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] {
+    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 []

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

@@ -0,0 +1,48 @@
+/*
+ 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
+
+/// An object is responsible for
+/// sizing and configuring cells for given `IndexPath`s.
+open class CellSizeCalculator {
+
+    /// The layout object for which the cell size calculator is used.
+    public weak var layout: UICollectionViewFlowLayout?
+
+    /// Used to configure the layout attributes for a given cell.
+    ///
+    /// - Parameters:
+    /// - attributes: The attributes of the cell.
+    /// The default does nothing
+    open func configure(attributes: UICollectionViewLayoutAttributes) {}
+
+    /// Used to size an item at a given `IndexPath`.
+    ///
+    /// - Parameters:
+    /// - indexPath: The `IndexPath` of the item to be displayed.
+    /// The default return .zero
+    open func sizeForItem(at indexPath: IndexPath) -> CGSize { return .zero }
+
+}

+ 19 - 20
Pods/MessageKit/Sources/Extensions/String+Extensions.swift → Pods/MessageKit/Sources/Layout/LocationMessageSizeCalculator.swift

@@ -1,18 +1,18 @@
 /*
  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
@@ -24,21 +24,20 @@
 
 import Foundation
 
-extension String {
-
-    func height(considering width: CGFloat, and font: UIFont) -> CGFloat {
-
-        let constraintBox = CGSize(width: width, height: .greatestFiniteMagnitude)
-      let rect = self.boundingRect(with: constraintBox, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil)
-        return rect.height
-
-    }
-
-    func width(considering height: CGFloat, and font: UIFont) -> CGFloat {
-
-        let constraintBox = CGSize(width: .greatestFiniteMagnitude, height: height)
-      let rect = self.boundingRect(with: constraintBox, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil)
-        return rect.width
-
+open class LocationMessageSizeCalculator: MessageSizeCalculator {
+
+    open override func messageContainerSize(for message: MessageType) -> CGSize {
+        switch message.kind {
+        case .location(let item):
+            let maxWidth = messageContainerMaxWidth(for: message)
+            if maxWidth < item.size.width {
+                // Maintain the ratio if width is too great
+                let height = maxWidth * item.size.height / item.size.width
+                return CGSize(width: maxWidth, height: height)
+            }
+            return item.size
+        default:
+            fatalError("messageContainerSize received unhandled MessageDataType: \(message.kind)")
+        }
     }
 }

+ 48 - 0
Pods/MessageKit/Sources/Layout/MediaMessageSizeCalculator.swift

@@ -0,0 +1,48 @@
+/*
+ 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
+
+open class MediaMessageSizeCalculator: MessageSizeCalculator {
+
+    open override func messageContainerSize(for message: MessageType) -> CGSize {
+        let maxWidth = messageContainerMaxWidth(for: message)
+        let sizeForMediaItem = { (maxWidth: CGFloat, item: MediaItem) -> CGSize in
+            if maxWidth < item.size.width {
+                // Maintain the ratio if width is too great
+                let height = maxWidth * item.size.height / item.size.width
+                return CGSize(width: maxWidth, height: height)
+            }
+            return item.size
+        }
+        switch message.kind {
+        case .photo(let item):
+            return sizeForMediaItem(maxWidth, item)
+        case .video(let item):
+            return sizeForMediaItem(maxWidth, item)
+        default:
+            fatalError("messageContainerSize received unhandled MessageDataType: \(message.kind)")
+        }
+    }
+}

+ 0 - 214
Pods/MessageKit/Sources/Layout/MessageIntermediateLayoutAttributes.swift

@@ -1,214 +0,0 @@
-/*
- 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 intermediate context used to store recently calculated values used by
-/// the `MessagesCollectionViewFlowLayout` object to reduce redundant calculations.
-final class MessageIntermediateLayoutAttributes {
-
-    // Message
-    var message: MessageType
-    var indexPath: IndexPath
-    
-    // Cell
-    var itemHeight: CGFloat = 0
-    var cellFrame: CGRect = .zero
-
-    // AvatarView
-    var avatarPosition = AvatarPosition(horizontal: .cellLeading, vertical: .cellBottom)
-    var avatarSize: CGSize = .zero
-    
-    lazy var avatarFrame: CGRect = {
-        
-        guard avatarSize != .zero else { return .zero }
-        
-        var origin = CGPoint.zero
-        
-        switch avatarPosition.horizontal {
-        case .cellLeading:
-            break
-        case .cellTrailing:
-            origin.x = cellFrame.width - avatarSize.width
-        case .natural:
-            fatalError(MessageKitError.avatarPositionUnresolved)
-        }
-        
-        switch avatarPosition.vertical {
-        case .cellTop:
-            break
-        case .cellBottom:
-            origin.y = cellFrame.height - avatarSize.height
-        case .messageTop:
-            origin.y = messageContainerFrame.minY
-        case .messageBottom:
-            origin.y = messageContainerFrame.maxY - avatarSize.height
-        case .messageCenter:
-            origin.y = messageContainerFrame.midY - (avatarSize.height/2)
-        }
-        
-        return CGRect(origin: origin, size: avatarSize)
-        
-    }()
-
-    // MessageContainerView
-    var messageContainerSize: CGSize = .zero
-    var messageContainerMaxWidth: CGFloat = 0
-    var messageContainerPadding: UIEdgeInsets = .zero
-    var messageLabelInsets: UIEdgeInsets = .zero
-    
-    lazy var messageContainerFrame: CGRect = {
-        
-        guard messageContainerSize != .zero else { return .zero }
-        
-        var origin: CGPoint = .zero
-        origin.y = topLabelSize.height + messageContainerPadding.top + topLabelVerticalPadding
-        
-        switch avatarPosition.horizontal {
-        case .cellLeading:
-            origin.x = avatarSize.width + messageContainerPadding.left
-        case .cellTrailing:
-            origin.x = cellFrame.width - avatarSize.width - messageContainerSize.width - messageContainerPadding.right
-        case .natural:
-            fatalError(MessageKitError.avatarPositionUnresolved)
-        }
-        
-        return CGRect(origin: origin, size: messageContainerSize)
-        
-    }()
-    
-    // Cell Top Label
-    var topLabelAlignment: LabelAlignment = .cellLeading(.zero)
-    var topLabelSize: CGSize = .zero
-    var topLabelMaxWidth: CGFloat = 0
-    
-    lazy var topLabelFrame: CGRect = {
-        
-        guard topLabelSize != .zero else { return .zero }
-        
-        var origin = CGPoint.zero
-        
-        origin.y = topLabelPadding.top
-        
-        switch topLabelAlignment {
-        case .cellLeading:
-            origin.x = topLabelPadding.left
-        case .cellCenter:
-            origin.x = (cellFrame.width/2) + topLabelPadding.left - topLabelPadding.right
-        case .cellTrailing:
-            origin.x = cellFrame.width - topLabelSize.width - topLabelPadding.right
-        case .messageLeading:
-            origin.x = messageContainerFrame.minX + topLabelPadding.left
-        case .messageTrailing:
-            origin.x = messageContainerFrame.maxX - topLabelSize.width - topLabelPadding.right
-        }
-        
-        return CGRect(origin: origin, size: topLabelSize)
-        
-    }()
-
-    // Cell Bottom Label
-    var bottomLabelAlignment: LabelAlignment = .cellTrailing(.zero)
-    var bottomLabelSize: CGSize = .zero
-    var bottomLabelMaxWidth: CGFloat = 0
-    
-    lazy var bottomLabelFrame: CGRect = {
-        
-        guard bottomLabelSize != .zero else { return .zero }
-        
-        var origin: CGPoint = .zero
-        
-        origin.y = messageContainerFrame.maxY + messageContainerPadding.bottom + bottomLabelPadding.top
-        
-        switch bottomLabelAlignment {
-        case .cellLeading:
-            origin.x = bottomLabelPadding.left
-        case .cellCenter:
-            origin.x = (cellFrame.width/2) + bottomLabelPadding.left - bottomLabelPadding.right
-        case .cellTrailing:
-            origin.x = cellFrame.width - bottomLabelSize.width - bottomLabelPadding.right
-        case .messageLeading:
-            origin.x = messageContainerFrame.minX + bottomLabelPadding.left
-        case .messageTrailing:
-            origin.x = messageContainerFrame.maxX - bottomLabelSize.width - bottomLabelPadding.right
-        }
-        
-        return CGRect(origin: origin, size: bottomLabelSize)
-
-    }()
-    
-    // MARK: - Initializer
-    
-    init(message: MessageType, indexPath: IndexPath) {
-        self.message = message
-        self.indexPath = indexPath
-    }
-
-}
-
-// MARK: - Helpers
-
-extension MessageIntermediateLayoutAttributes {
-    
-    var bottomLabelPadding: UIEdgeInsets {
-        return bottomLabelAlignment.insets
-    }
-    
-    var bottomLabelVerticalPadding: CGFloat {
-        return bottomLabelPadding.top + bottomLabelPadding.bottom
-    }
-    
-    var bottomLabelHorizontalPadding: CGFloat {
-        return bottomLabelPadding.left + bottomLabelPadding.right
-    }
-    
-    var topLabelPadding: UIEdgeInsets {
-        return topLabelAlignment.insets
-    }
-    
-    var topLabelVerticalPadding: CGFloat {
-        return topLabelPadding.top + topLabelPadding.bottom
-    }
-    
-    var topLabelHorizontalPadding: CGFloat {
-        return topLabelPadding.left + topLabelPadding.right
-    }
-    
-    var messageLabelVerticalInsets: CGFloat {
-        return messageLabelInsets.top + messageLabelInsets.bottom
-    }
-    
-    var messageLabelHorizontalInsets: CGFloat {
-        return messageLabelInsets.left + messageLabelInsets.right
-    }
-    
-    var messageVerticalPadding: CGFloat {
-        return messageContainerPadding.top + messageContainerPadding.bottom
-    }
-    
-    var messageHorizontalPadding: CGFloat {
-        return messageContainerPadding.left + messageContainerPadding.right
-    }
-
-}

+ 228 - 0
Pods/MessageKit/Sources/Layout/MessageSizeCalculator.swift

@@ -0,0 +1,228 @@
+/*
+ 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
+
+open class MessageSizeCalculator: CellSizeCalculator {
+
+    public init(layout: MessagesCollectionViewFlowLayout? = nil) {
+        super.init()
+        
+        self.layout = layout
+    }
+
+    public var incomingAvatarSize = CGSize(width: 30, height: 30)
+    public var outgoingAvatarSize = CGSize(width: 30, height: 30)
+
+    public var incomingAvatarPosition = AvatarPosition(vertical: .cellBottom)
+    public var outgoingAvatarPosition = AvatarPosition(vertical: .cellBottom)
+
+    public var incomingMessagePadding = UIEdgeInsets(top: 0, left: 4, bottom: 0, right: 30)
+    public var outgoingMessagePadding = UIEdgeInsets(top: 0, left: 30, bottom: 0, right: 4)
+
+    public var incomingCellTopLabelAlignment = LabelAlignment(textAlignment: .center, textInsets: .zero)
+    public var outgoingCellTopLabelAlignment = LabelAlignment(textAlignment: .center, textInsets: .zero)
+
+    public var incomingMessageTopLabelAlignment = LabelAlignment(textAlignment: .left, textInsets: UIEdgeInsets(left: 42))
+    public var outgoingMessageTopLabelAlignment = LabelAlignment(textAlignment: .right, textInsets: UIEdgeInsets(right: 42))
+
+    public var incomingMessageBottomLabelAlignment = LabelAlignment(textAlignment: .left, textInsets: UIEdgeInsets(left: 42))
+    public var outgoingMessageBottomLabelAlignment = LabelAlignment(textAlignment: .right, textInsets: UIEdgeInsets(right: 42))
+
+    open override func configure(attributes: UICollectionViewLayoutAttributes) {
+        guard let attributes = attributes as? MessagesCollectionViewLayoutAttributes else { return }
+
+        let dataSource = messagesLayout.messagesDataSource
+        let indexPath = attributes.indexPath
+        let message = dataSource.messageForItem(at: indexPath, in: messagesLayout.messagesCollectionView)
+
+        attributes.avatarSize = avatarSize(for: message)
+        attributes.avatarPosition = avatarPosition(for: message)
+
+        attributes.messageContainerPadding = messageContainerPadding(for: message)
+        attributes.messageContainerSize = messageContainerSize(for: message)
+        attributes.cellTopLabelSize = cellTopLabelSize(for: message, at: indexPath)
+        attributes.messageTopLabelSize = messageTopLabelSize(for: message, at: indexPath)
+        attributes.messageTopLabelAlignment = messageTopLabelAlignment(for: message)
+
+        attributes.messageBottomLabelAlignment = messageBottomLabelAlignment(for: message)
+        attributes.messageBottomLabelSize = messageBottomLabelSize(for: message, at: indexPath)
+    }
+
+    open override func sizeForItem(at indexPath: IndexPath) -> CGSize {
+        let dataSource = messagesLayout.messagesDataSource
+        let message = dataSource.messageForItem(at: indexPath, in: messagesLayout.messagesCollectionView)
+        let itemHeight = cellContentHeight(for: message, at: indexPath)
+        return CGSize(width: messagesLayout.itemWidth, height: itemHeight)
+    }
+
+    open func cellContentHeight(for message: MessageType, at indexPath: IndexPath) -> CGFloat {
+
+        let messageContainerHeight = messageContainerSize(for: message).height
+        let messageBottomLabelHeight = messageBottomLabelSize(for: message, at: indexPath).height
+        let cellTopLabelHeight = cellTopLabelSize(for: message, at: indexPath).height
+        let messageTopLabelHeight = messageTopLabelSize(for: message, at: indexPath).height
+        let messageVerticalPadding = messageContainerPadding(for: message).vertical
+        let avatarHeight = avatarSize(for: message).height
+        let avatarVerticalPosition = avatarPosition(for: message).vertical
+
+        switch avatarVerticalPosition {
+        case .messageCenter:
+            let totalLabelHeight: CGFloat = cellTopLabelHeight + messageTopLabelHeight
+                + messageContainerHeight + messageVerticalPadding + messageBottomLabelHeight
+            return max(avatarHeight, totalLabelHeight)
+        case .messageBottom:
+            var cellHeight: CGFloat = 0
+            cellHeight += messageBottomLabelHeight
+            let labelsHeight = messageContainerHeight + messageVerticalPadding + cellTopLabelHeight + messageTopLabelHeight
+            cellHeight += max(labelsHeight, avatarHeight)
+            return cellHeight
+        case .messageTop:
+            var cellHeight: CGFloat = 0
+            cellHeight += cellTopLabelHeight
+            cellHeight += messageTopLabelHeight
+            let labelsHeight = messageContainerHeight + messageVerticalPadding + messageBottomLabelHeight
+            cellHeight += max(labelsHeight, avatarHeight)
+            return cellHeight
+        case .messageLabelTop:
+            var cellHeight: CGFloat = 0
+            cellHeight += cellTopLabelHeight
+            let messageLabelsHeight = messageContainerHeight + messageBottomLabelHeight + messageVerticalPadding + messageTopLabelHeight
+            cellHeight += max(messageLabelsHeight, avatarHeight)
+            return cellHeight
+        case .cellTop, .cellBottom:
+            let totalLabelHeight: CGFloat = cellTopLabelHeight + messageTopLabelHeight
+                + messageContainerHeight + messageVerticalPadding + messageBottomLabelHeight
+            return max(avatarHeight, totalLabelHeight)
+        }
+    }
+
+    // MARK: - Avatar
+
+    public func avatarPosition(for message: MessageType) -> AvatarPosition {
+        let dataSource = messagesLayout.messagesDataSource
+        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
+        var position = isFromCurrentSender ? outgoingAvatarPosition : incomingAvatarPosition
+
+        switch position.horizontal {
+        case .cellTrailing, .cellLeading:
+            break
+        case .natural:
+            position.horizontal = isFromCurrentSender ? .cellTrailing : .cellLeading
+        }
+        return position
+    }
+
+    public func avatarSize(for message: MessageType) -> CGSize {
+        let dataSource = messagesLayout.messagesDataSource
+        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
+        return isFromCurrentSender ? outgoingAvatarSize : incomingAvatarSize
+    }
+
+    // MARK: - Top cell Label
+
+    public func cellTopLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
+        let layoutDelegate = messagesLayout.messagesLayoutDelegate
+        let collectionView = messagesLayout.messagesCollectionView
+        let height = layoutDelegate.cellTopLabelHeight(for: message, at: indexPath, in: collectionView)
+        return CGSize(width: messagesLayout.itemWidth, height: height)
+    }
+
+    public func cellTopLabelAlignment(for message: MessageType) -> LabelAlignment {
+        let dataSource = messagesLayout.messagesDataSource
+        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
+        return isFromCurrentSender ? outgoingCellTopLabelAlignment : incomingCellTopLabelAlignment
+    }
+    
+    // MARK: - Top message Label
+    
+    public func messageTopLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
+        let layoutDelegate = messagesLayout.messagesLayoutDelegate
+        let collectionView = messagesLayout.messagesCollectionView
+        let height = layoutDelegate.messageTopLabelHeight(for: message, at: indexPath, in: collectionView)
+        return CGSize(width: messagesLayout.itemWidth, height: height)
+    }
+    
+    public func messageTopLabelAlignment(for message: MessageType) -> LabelAlignment {
+        let dataSource = messagesLayout.messagesDataSource
+        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
+        return isFromCurrentSender ? outgoingMessageTopLabelAlignment : incomingMessageTopLabelAlignment
+    }
+
+    // MARK: - Bottom Label
+
+    public func messageBottomLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
+        let layoutDelegate = messagesLayout.messagesLayoutDelegate
+        let collectionView = messagesLayout.messagesCollectionView
+        let height = layoutDelegate.messageBottomLabelHeight(for: message, at: indexPath, in: collectionView)
+        return CGSize(width: messagesLayout.itemWidth, height: height)
+    }
+
+    public func messageBottomLabelAlignment(for message: MessageType) -> LabelAlignment {
+        let dataSource = messagesLayout.messagesDataSource
+        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
+        return isFromCurrentSender ? outgoingMessageBottomLabelAlignment : incomingMessageBottomLabelAlignment
+    }
+
+    // MARK: - MessageContainer
+
+    public func messageContainerPadding(for message: MessageType) -> UIEdgeInsets {
+        let dataSource = messagesLayout.messagesDataSource
+        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
+        return isFromCurrentSender ? outgoingMessagePadding : incomingMessagePadding
+    }
+
+    open func messageContainerSize(for message: MessageType) -> CGSize {
+        // Returns .zero by default
+        return .zero
+    }
+
+    open func messageContainerMaxWidth(for message: MessageType) -> CGFloat {
+        let avatarWidth = avatarSize(for: message).width
+        let messagePadding = messageContainerPadding(for: message)
+        return messagesLayout.itemWidth - avatarWidth - messagePadding.horizontal
+    }
+
+    // MARK: - Helpers
+
+    public var messagesLayout: MessagesCollectionViewFlowLayout {
+        guard let layout = layout as? MessagesCollectionViewFlowLayout else {
+            fatalError("Layout object is missing or is not a MessagesCollectionViewFlowLayout")
+        }
+        return layout
+    }
+
+    internal func labelSize(for attributedText: NSAttributedString, considering maxWidth: CGFloat) -> CGSize {
+        let constraintBox = CGSize(width: maxWidth, height: .greatestFiniteMagnitude)
+        let rect = attributedText.boundingRect(with: constraintBox, options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil).integral
+
+        return rect.size
+    }
+}
+
+fileprivate extension UIEdgeInsets {
+    init(top: CGFloat = 0, bottom: CGFloat = 0, left: CGFloat = 0, right: CGFloat = 0) {
+        self.init(top: top, left: left, bottom: bottom, right: right)
+    }
+}

+ 102 - 515
Pods/MessageKit/Sources/Layout/MessagesCollectionViewFlowLayout.swift

@@ -29,77 +29,42 @@ import AVFoundation
 /// framework provided `MessageCollectionViewCell` subclasses.
 open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
 
-    // MARK: - Properties [Public]
-
-    /// Font to be used by `TextMessageCell` for `MessageData.text(String)` case.
-    ///
-    /// The default value of this property is `UIFont.preferredFont(forTextStyle: .body)`
-    open var messageLabelFont: UIFont {
-        didSet {
-            emojiLabelFont = messageLabelFont.withSize(2 * messageLabelFont.pointSize)
-        }
-    }
-
-    /// Determines the maximum number of `MessageCollectionViewCell` attributes to cache.
-    ///
-    /// The default value of this property is 500.
-    open var attributesCacheMaxSize: Int = 500
-    
-    /// A type property representing the `MessagesCollectionViewLayoutAttributes` to be used.
     open override class var layoutAttributesClass: AnyClass {
         return MessagesCollectionViewLayoutAttributes.self
     }
     
-    // MARK: - Properties [Private]
-    
-    /// Font to be used by `TextMessageCell` for `MessageData.emoji(String)` case.
-    ///
-    /// The default value of this property is 2x the `messageLabelFont`.
-    private var emojiLabelFont: UIFont
-
-    typealias MessageID = String
-    
-    /// The cache for `MessageIntermediateLayoutAttributes`.
-    /// The key is the `messageId` of the `MessageType`.
-    fileprivate var intermediateAttributesCache: [MessageID: MessageIntermediateLayoutAttributes] = [:]
-    
-    /// Convenience property for accessing the layout object's `MessagesCollectionView`.
-    fileprivate var messagesCollectionView: MessagesCollectionView {
+    /// The `MessagesCollectionView` that owns this layout object.
+    public var messagesCollectionView: MessagesCollectionView {
         guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
             fatalError(MessageKitError.layoutUsedOnForeignType)
         }
         return messagesCollectionView
     }
-
-    /// Convenience property for unwrapping the `MessagesCollectionView`'s `MessagesDataSource`.
-    fileprivate var messagesDataSource: MessagesDataSource {
+    
+    /// The `MessagesDataSource` for the layout's collection view.
+    public var messagesDataSource: MessagesDataSource {
         guard let messagesDataSource = messagesCollectionView.messagesDataSource else {
             fatalError(MessageKitError.nilMessagesDataSource)
         }
         return messagesDataSource
     }
-
-    /// Convenience property for unwrapping the `MessagesCollectionView`'s `MessagesLayoutDelegate`.
-    fileprivate var messagesLayoutDelegate: MessagesLayoutDelegate {
+    
+    /// The `MessagesLayoutDelegate` for the layout's collection view.
+    public var messagesLayoutDelegate: MessagesLayoutDelegate {
         guard let messagesLayoutDelegate = messagesCollectionView.messagesLayoutDelegate else {
-            fatalError(MessageKitError.nilMessagesLayoutDeleagte)
+            fatalError(MessageKitError.nilMessagesLayoutDelegate)
         }
         return messagesLayoutDelegate
     }
 
-    /// The width of an item in the `MessageCollectionViewCell`.
-    fileprivate var itemWidth: CGFloat {
+    public var itemWidth: CGFloat {
         guard let collectionView = collectionView else { return 0 }
         return collectionView.frame.width - sectionInset.left - sectionInset.right
     }
 
-    // MARK: - Initializers [Public]
+    // MARK: - Initializers
 
     public override init() {
-
-        messageLabelFont = UIFont.preferredFont(forTextStyle: .body)
-        emojiLabelFont = messageLabelFont.withSize(2 * messageLabelFont.pointSize)
-
         super.init()
 
         sectionInset = UIEdgeInsets(top: 4, left: 8, bottom: 4, right: 8)
@@ -115,523 +80,145 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
         NotificationCenter.default.removeObserver(self)
     }
 
-    /// Invalidates the layout and removes all cached attributes on device orientation change
-    @objc
-    private func handleOrientationChange(_ notification: Notification) {
-        removeAllCachedAttributes()
-        invalidateLayout()
-    }
-
-    // MARK: - Methods [Public]
-    
-    /// Removes the cached layout information for a given `MessageType` using the `messageId`.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` whose cached layout information is to be removed.
-    public func removeCachedAttributes(for message: MessageType) {
-        removeCachedAttributes(for: message.messageId)
-    }
-    
-    /// Removes the cached layout information for a `MessageType` given its `messageId`.
-    ///
-    /// - Parameters:
-    ///   - messageId: The `messageId` for the `MessageType` whose cached layout information is to be removed.
-    public func removeCachedAttributes(for messageId: String) {
-        intermediateAttributesCache.removeValue(forKey: messageId)
-    }
-    
-    /// Removes the cached layout information for all `MessageType`s.
-    public func removeAllCachedAttributes() {
-        intermediateAttributesCache.removeAll()
-    }
-    
-    open override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
-        if collectionView?.bounds.width != newBounds.width {
-            removeAllCachedAttributes()
-            return true
-        } else {
-            return false
-        }
-    }
-    
-    open override func invalidationContext(forBoundsChange newBounds: CGRect) -> UICollectionViewLayoutInvalidationContext {
-        let context = super.invalidationContext(forBoundsChange: newBounds)
-        guard let flowLayoutContext = context as? UICollectionViewFlowLayoutInvalidationContext else { return context }
-        flowLayoutContext.invalidateFlowLayoutDelegateMetrics = shouldInvalidateLayout(forBoundsChange: newBounds)
-        return flowLayoutContext
-    }
+    // MARK: - Attributes
 
     open override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
-
-        guard let attributesArray = super.layoutAttributesForElements(in: rect) as? [MessagesCollectionViewLayoutAttributes] else { return nil }
-
-        attributesArray.forEach { attributes in
-            if attributes.representedElementCategory == UICollectionElementCategory.cell {
-                configure(attributes: attributes)
-            }
+        guard let attributesArray = super.layoutAttributesForElements(in: rect) as? [MessagesCollectionViewLayoutAttributes] else {
+            return nil
+        }
+        for attributes in attributesArray where attributes.representedElementCategory == .cell {
+            let cellSizeCalculator = cellSizeCalculatorForItem(at: attributes.indexPath)
+            cellSizeCalculator.configure(attributes: attributes)
         }
-
         return attributesArray
     }
 
     open override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
-
-        guard let attributes = super.layoutAttributesForItem(at: indexPath) as? MessagesCollectionViewLayoutAttributes else { return nil }
-
-        if attributes.representedElementCategory == UICollectionElementCategory.cell {
-            configure(attributes: attributes)
+        guard let attributes = super.layoutAttributesForItem(at: indexPath) as? MessagesCollectionViewLayoutAttributes else {
+            return nil
+        }
+        if attributes.representedElementCategory == .cell {
+            let cellSizeCalculator = cellSizeCalculatorForItem(at: attributes.indexPath)
+            cellSizeCalculator.configure(attributes: attributes)
         }
-
         return attributes
-
-    }
-    
-    /// The size for the `MessageCollectionViewCell` considering all of the cell's contents.
-    ///
-    /// - Parameters:
-    ///   - indexPath: The `IndexPath` of the cell.
-    open func sizeForItem(at indexPath: IndexPath) -> CGSize {
-        let attributes = messageIntermediateLayoutAttributes(for: indexPath)
-        return CGSize(width: itemWidth, height: attributes.itemHeight)
     }
 
-}
-
-// MARK: - Calculating MessageIntermediateLayoutAttributes
+    // MARK: - Layout Invalidation
 
-fileprivate extension MessagesCollectionViewFlowLayout {
-    
-    /// Returns the cached `MessageIntermediateLayoutAttributes` for a given `IndexPath` (if any).
-    /// If no cached attributes exist, new attributes will be created.
-    /// - Parameters:
-    ///   - indexPath: The `IndexPath` used to retrieve the `MessageType`.
-    func messageIntermediateLayoutAttributes(for indexPath: IndexPath) -> MessageIntermediateLayoutAttributes {
-        
-        let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
-        
-        if let intermediateAttributes = intermediateAttributesCache[message.messageId] {
-            return intermediateAttributes
-        } else {
-            let newAttributes = createMessageIntermediateLayoutAttributes(for: message, at: indexPath)
-
-            let shouldCache = messagesLayoutDelegate.shouldCacheLayoutAttributes(for: message) && intermediateAttributesCache.count < attributesCacheMaxSize
-            
-            if shouldCache {
-                intermediateAttributesCache[message.messageId] = newAttributes
-            }
-            return newAttributes
-        }
-        
+    open override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
+        return collectionView?.bounds.width != newBounds.width
     }
-    
-    /// Returns newly created `MessageIntermediateAttributes` for a given `MessageType` and `IndexPath`.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` representing the attributes.
-    ///   - indexPath: The current `IndexPath` of the `MessageCollectionViewCell`.
-    func createMessageIntermediateLayoutAttributes(for message: MessageType, at indexPath: IndexPath) -> MessageIntermediateLayoutAttributes {
-        
-        let attributes = MessageIntermediateLayoutAttributes(message: message, indexPath: indexPath)
-        
-        // None of these are dependent on other attributes
-        attributes.avatarPosition = avatarPosition(for: attributes)
-        attributes.avatarSize = avatarSize(for: attributes)
-        attributes.messageContainerPadding = messageContainerPadding(for: attributes)
-        attributes.messageLabelInsets = messageLabelInsets(for: attributes)
-        
-        // MessageContainerView
-        attributes.messageContainerMaxWidth = messageContainerMaxWidth(for: attributes)
-        attributes.messageContainerSize = messageContainerSize(for: attributes)
-        
-        // Cell Bottom Label
-        attributes.bottomLabelAlignment = cellBottomLabelAlignment(for: attributes)
-        attributes.bottomLabelMaxWidth = cellBottomLabelMaxWidth(for: attributes)
-        attributes.bottomLabelSize = cellBottomLabelSize(for: attributes)
-        
-        // Cell Top Label
-        attributes.topLabelAlignment = cellTopLabelAlignment(for: attributes)
-        attributes.topLabelMaxWidth = cellTopLabelMaxWidth(for: attributes)
-        attributes.topLabelSize = cellTopLabelSize(for: attributes)
-        
-        // Cell Height
-        attributes.itemHeight = cellHeight(for: attributes)
-        
-        return attributes
+
+    open override func invalidationContext(forBoundsChange newBounds: CGRect) -> UICollectionViewLayoutInvalidationContext {
+        let context = super.invalidationContext(forBoundsChange: newBounds)
+        guard let flowLayoutContext = context as? UICollectionViewFlowLayoutInvalidationContext else { return context }
+        flowLayoutContext.invalidateFlowLayoutDelegateMetrics = shouldInvalidateLayout(forBoundsChange: newBounds)
+        return flowLayoutContext
     }
-    
-    /// Configures the `MessagesCollectionViewLayoutAttributes` by applying the layout information
-    /// from `MessageIntermediateLayoutAttributes` and calculating the origins of the cell's contents.
-    ///
-    /// - Parameters:
-    ///   - attributes: The `MessageCollectionViewLayoutAttributes` to apply the layout information to.
-    private func configure(attributes: MessagesCollectionViewLayoutAttributes) {
-        
-        let intermediateAttributes = messageIntermediateLayoutAttributes(for: attributes.indexPath)
-        
-        intermediateAttributes.cellFrame = attributes.frame
-        
-        attributes.messageContainerFrame = intermediateAttributes.messageContainerFrame
-        attributes.topLabelFrame = intermediateAttributes.topLabelFrame
-        attributes.bottomLabelFrame = intermediateAttributes.bottomLabelFrame
-        attributes.avatarFrame = intermediateAttributes.avatarFrame
-        attributes.messageLabelInsets = intermediateAttributes.messageLabelInsets
-        
-        switch intermediateAttributes.message.data {
-        case .emoji:
-            attributes.messageLabelFont = emojiLabelFont
-        case .text:
-            attributes.messageLabelFont = messageLabelFont
-        case .attributedText(let text):
-            guard !text.string.isEmpty else { return }
-            guard let font = text.attribute(.font, at: 0, effectiveRange: nil) as? UIFont else { return }
-            attributes.messageLabelFont = font
-        default:
-            break
-        }
 
+    @objc
+    private func handleOrientationChange(_ notification: Notification) {
+        invalidateLayout()
     }
 
-}
+    // MARK: - Cell Sizing
 
-// MARK: - Avatar Calculations [ A - C ]
+    lazy open var textMessageSizeCalculator = TextMessageSizeCalculator(layout: self)
+    lazy open var attributedTextMessageSizeCalculator = TextMessageSizeCalculator(layout: self)
+    lazy open var emojiMessageSizeCalculator = TextMessageSizeCalculator(layout: self)
+    lazy open var photoMessageSizeCalculator = MediaMessageSizeCalculator(layout: self)
+    lazy open var videoMessageSizeCalculator = MediaMessageSizeCalculator(layout: self)
+    lazy open var locationMessageSizeCalculator = LocationMessageSizeCalculator(layout: self)
 
-fileprivate extension MessagesCollectionViewFlowLayout {
-    
-    // A
-    
-    /// Returns the `AvatarPosition` for a given `MessageType`.
-    ///
-    /// - Parameters:
-    ///   - attributes: The `MessageIntermediateLayoutAttributes` containing the `MessageType` object.
-    func avatarPosition(for attributes: MessageIntermediateLayoutAttributes) -> AvatarPosition {
-        var position = messagesLayoutDelegate.avatarPosition(for: attributes.message, at: attributes.indexPath, in: messagesCollectionView)
-        
-        switch position.horizontal {
-        case .cellTrailing, .cellLeading:
-            break
-        case .natural:
-            position.horizontal = messagesDataSource.isFromCurrentSender(message: attributes.message) ? .cellTrailing : .cellLeading
+    open func cellSizeCalculatorForItem(at indexPath: IndexPath) -> CellSizeCalculator {
+        let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
+        switch message.kind {
+        case .text:
+            return textMessageSizeCalculator
+        case .attributedText:
+            return attributedTextMessageSizeCalculator
+        case .emoji:
+            return emojiMessageSizeCalculator
+        case .photo:
+            return photoMessageSizeCalculator
+        case .video:
+            return videoMessageSizeCalculator
+        case .location:
+            return locationMessageSizeCalculator
+        case .custom:
+            fatalError("Must return a CellSizeCalculator for MessageKind.custom(Any?)")
         }
-
-        return position
     }
 
-    // B
-    
-    /// Returns the size of the `AvatarView` for a given `MessageType`.
-    ///
-    /// - Parameters:
-    ///   - attributes: The `MessageIntermediateLayoutAttributes` containing the `MessageType` object.
-    func avatarSize(for attributes: MessageIntermediateLayoutAttributes) -> CGSize {
-        return messagesLayoutDelegate.avatarSize(for: attributes.message, at: attributes.indexPath, in: messagesCollectionView)
+    open func sizeForItem(at indexPath: IndexPath) -> CGSize {
+        let calculator = cellSizeCalculatorForItem(at: indexPath)
+        return calculator.sizeForItem(at: indexPath)
     }
     
-}
-
-// MARK: - General Label Size Calculations
-
-private extension MessagesCollectionViewFlowLayout {
-    
-    /// Returns the size required fit a NSAttributedString considering a constrained max width.
-    ///
-    /// - Parameters:
-    ///   - attributedText: The `NSAttributedString` used to calculate a size that fits.
-    ///   - maxWidth: The max width available for the label.
-    func labelSize(for attributedText: NSAttributedString, considering maxWidth: CGFloat) -> CGSize {
-        
-        let estimatedHeight = attributedText.height(considering: maxWidth)
-        let estimatedWidth = attributedText.width(considering: estimatedHeight)
-        
-        let finalHeight = estimatedHeight.rounded(.up)
-        let finalWidth = estimatedWidth > maxWidth ? maxWidth : estimatedWidth.rounded(.up)
-        
-        return CGSize(width: finalWidth, height: finalHeight)
+    /// Set `incomingAvatarSize` of all `MessageSizeCalculator`s
+    public func setMessageIncomingAvatarSize(_ newSize: CGSize) {
+        messageSizeCalculators().forEach { $0.incomingAvatarSize = newSize }
     }
     
-    /// Returns the size required to fit a String considering a constrained max width.
-    ///
-    /// - Parameters:
-    ///   - text: The `String` used to calculate a size that fits.
-    ///   - maxWidth: The max width available for the label.
-    func labelSize(for text: String, considering maxWidth: CGFloat, and font: UIFont) -> CGSize {
-        
-        let estimatedHeight = text.height(considering: maxWidth, and: font)
-        let estimatedWidth = text.width(considering: estimatedHeight, and: font)
-        
-        let finalHeight = estimatedHeight.rounded(.up)
-        let finalWidth = estimatedWidth > maxWidth ? maxWidth : estimatedWidth.rounded(.up)
-        
-        return CGSize(width: finalWidth, height: finalHeight)
+    /// Set `outgoingAvatarSize` of all `MessageSizeCalculator`s
+    public func setMessageOutgoingAvatarSize(_ newSize: CGSize) {
+        messageSizeCalculators().forEach { $0.outgoingAvatarSize = newSize }
     }
     
-}
-
-// MARK: - MessageContainerView Calculations [ D - G ]
-
-private extension MessagesCollectionViewFlowLayout {
-    
-    // D
-    
-    /// Returns the padding to be used around the `MessageContainerView` for a given `MessageType`.
-    ///
-    /// - Parameters:
-    ///   - attributes: The `MessageIntermediateLayoutAttributes` containing the `MessageType` object.
-    func messageContainerPadding(for attributes: MessageIntermediateLayoutAttributes) -> UIEdgeInsets {
-        return messagesLayoutDelegate.messagePadding(for: attributes.message, at: attributes.indexPath, in: messagesCollectionView)
+    /// Set `incomingAvatarPosition` of all `MessageSizeCalculator`s
+    public func setMessageIncomingAvatarPosition(_ newPosition: AvatarPosition) {
+        messageSizeCalculators().forEach { $0.incomingAvatarPosition = newPosition }
     }
     
-    // E
-    
-    /// Returns the insets for the text of a `MessageLabel` in ` TextMessageCell`.
-    ///
-    /// - Parameters:
-    ///   - attributes: The `MessageIntermediateLayoutAttributes` containing the `MessageType` object.
-    func messageLabelInsets(for attributes: MessageIntermediateLayoutAttributes) -> UIEdgeInsets {
-        // Maybe check the message type here since insets only apply to text messages
-        return messagesLayoutDelegate.messageLabelInset(for: attributes.message, at: attributes.indexPath, in: messagesCollectionView)
+    /// Set `outgoingAvatarPosition` of all `MessageSizeCalculator`s
+    public func setMessageOutgoingAvatarPosition(_ newPosition: AvatarPosition) {
+        messageSizeCalculators().forEach { $0.outgoingAvatarPosition = newPosition }
     }
     
-    // F
-    
-    /// Returns the max available width for the `MessageContainerView`.
-    ///
-    /// - Parameters:
-    ///   - attributes: The `MessageIntermediateLayoutAttributes` to consider when calculating the max width.
-    func messageContainerMaxWidth(for attributes: MessageIntermediateLayoutAttributes) -> CGFloat {
-        
-        switch attributes.message.data {
-        case .text, .attributedText:
-            return itemWidth - attributes.avatarSize.width - attributes.messageHorizontalPadding - attributes.messageLabelHorizontalInsets
-        default:
-            return itemWidth - attributes.avatarSize.width - attributes.messageHorizontalPadding
-        }
-        
+    /// Set `incomingMessagePadding` of all `MessageSizeCalculator`s
+    public func setMessageIncomingMessagePadding(_ newPadding: UIEdgeInsets) {
+        messageSizeCalculators().forEach { $0.incomingMessagePadding = newPadding }
     }
     
-    // G
-    
-    /// Returns the size of the `MessageContainerView`
-    ///
-    /// - Parameters:
-    ///   - attributes: The `MessageIntermediateLayoutAttributes` to consider when calculating the `MessageContainerView` size.
-    func messageContainerSize(for attributes: MessageIntermediateLayoutAttributes) -> CGSize {
-        
-        let message = attributes.message
-        let indexPath = attributes.indexPath
-        let maxWidth = attributes.messageContainerMaxWidth
-        
-        var messageContainerSize: CGSize = .zero
-        
-        switch attributes.message.data {
-        case .text(let text):
-            messageContainerSize = labelSize(for: text, considering: maxWidth, and: messageLabelFont)
-            messageContainerSize.width += attributes.messageLabelHorizontalInsets
-            messageContainerSize.height += attributes.messageLabelVerticalInsets
-        case .attributedText(let text):
-            messageContainerSize = labelSize(for: text, considering: maxWidth)
-            messageContainerSize.width += attributes.messageLabelHorizontalInsets
-            messageContainerSize.height += attributes.messageLabelVerticalInsets
-        case .emoji(let text):
-            messageContainerSize = labelSize(for: text, considering: maxWidth, and: emojiLabelFont)
-            messageContainerSize.width += attributes.messageLabelHorizontalInsets
-            messageContainerSize.height += attributes.messageLabelVerticalInsets
-        case .photo, .video:
-            let width = messagesLayoutDelegate.widthForMedia(message: message, at: indexPath, with: maxWidth, in: messagesCollectionView)
-            let height = messagesLayoutDelegate.heightForMedia(message: message, at: indexPath, with: maxWidth, in: messagesCollectionView)
-            messageContainerSize = CGSize(width: width, height: height)
-        case .location:
-            let width = messagesLayoutDelegate.widthForLocation(message: message, at: indexPath, with: maxWidth, in: messagesCollectionView)
-            let height = messagesLayoutDelegate.heightForLocation(message: message, at: indexPath, with: maxWidth, in: messagesCollectionView)
-            messageContainerSize = CGSize(width: width, height: height)
-        }
-        
-        return messageContainerSize
-        
+    /// Set `outgoingMessagePadding` of all `MessageSizeCalculator`s
+    public func setMessageOutgoingMessagePadding(_ newPadding: UIEdgeInsets) {
+        messageSizeCalculators().forEach { $0.outgoingMessagePadding = newPadding }
     }
     
-}
-
-// MARK: - Cell Bottom Label Calculations  [ I - K ]
-
-private extension MessagesCollectionViewFlowLayout {
-    
-    // I
-    
-    /// Returns the alignment of the cell's bottom label.
-    ///
-    /// - Parameters:
-    ///   - attributes: The `MessageIntermediateLayoutAttributes` containing the `MessageType` object.
-    func cellBottomLabelAlignment(for attributes: MessageIntermediateLayoutAttributes) -> LabelAlignment {
-        return messagesLayoutDelegate.cellBottomLabelAlignment(for: attributes.message, at: attributes.indexPath, in: messagesCollectionView)
+    /// Set `incomingCellTopLabelAlignment` of all `MessageSizeCalculator`s
+    public func setMessageIncomingCellTopLabelAlignment(_ newAlignment: LabelAlignment) {
+        messageSizeCalculators().forEach { $0.incomingCellTopLabelAlignment = newAlignment }
     }
     
-    // J
-    
-    /// Returns the max available width for the cell's bottom label considering the specified layout information.
-    ///
-    /// - Parameters:
-    ///   - attributes: The `MessageIntermediateLayoutAttributes` to consider when calculating the max width.
-    func cellBottomLabelMaxWidth(for attributes: MessageIntermediateLayoutAttributes) -> CGFloat {
-        
-        let labelHorizontal = attributes.bottomLabelAlignment
-        let avatarHorizontal = attributes.avatarPosition.horizontal
-        let avatarVertical = attributes.avatarPosition.vertical
-        let avatarWidth = attributes.avatarSize.width
-
-        switch (labelHorizontal, avatarHorizontal) {
-
-        case (.cellLeading, _), (.cellTrailing, _):
-            let width = itemWidth - attributes.bottomLabelHorizontalPadding
-            return avatarVertical != .cellBottom ? width : width - avatarWidth
-
-        case (.cellCenter, _):
-            let width = itemWidth - attributes.bottomLabelHorizontalPadding
-            return avatarVertical != .cellBottom ? width : width - (avatarWidth * 2)
-
-        case (.messageTrailing, .cellLeading):
-            let width = attributes.messageContainerSize.width + attributes.messageContainerPadding.left - attributes.bottomLabelHorizontalPadding
-            return avatarVertical == .cellBottom ? width : width + avatarWidth
-
-        case (.messageLeading, .cellTrailing):
-            let width = attributes.messageContainerSize.width + attributes.messageContainerPadding.right - attributes.bottomLabelHorizontalPadding
-            return avatarVertical == .cellBottom ? width : width + avatarWidth
-
-        case (.messageLeading, .cellLeading):
-            return itemWidth - avatarWidth - attributes.messageContainerPadding.left - attributes.bottomLabelHorizontalPadding
-
-        case (.messageTrailing, .cellTrailing):
-            return itemWidth - avatarWidth - attributes.messageContainerPadding.right - attributes.bottomLabelHorizontalPadding
-
-        case (_, .natural):
-            fatalError(MessageKitError.avatarPositionUnresolved)
-        }
-        
+    /// Set `outgoingCellTopLabelAlignment` of all `MessageSizeCalculator`s
+    public func setMessageOutgoingCellTopLabelAlignment(_ newAlignment: LabelAlignment) {
+        messageSizeCalculators().forEach { $0.outgoingCellTopLabelAlignment = newAlignment }
     }
     
-    // K
-    
-    /// Returns the size of the cell's bottom label considering the specified layout information.
-    ///
-    /// - Parameters:
-    ///   - attributes: The `MessageIntermediateLayoutAttributes` to consider when calculating label's size.
-    func cellBottomLabelSize(for attributes: MessageIntermediateLayoutAttributes) -> CGSize {
-        
-        let text = messagesDataSource.cellBottomLabelAttributedText(for: attributes.message, at: attributes.indexPath)
-        
-        guard let bottomLabelText = text else { return .zero }
-        return labelSize(for: bottomLabelText, considering: attributes.bottomLabelMaxWidth)
+    /// Set `incomingMessageTopLabelAlignment` of all `MessageSizeCalculator`s
+    public func setMessageIncomingMessageTopLabelAlignment(_ newAlignment: LabelAlignment) {
+        messageSizeCalculators().forEach { $0.incomingMessageTopLabelAlignment = newAlignment }
     }
-
-}
-
-// MARK: - Cell Top Label Size Calculations [ L - N ]
-
-private extension MessagesCollectionViewFlowLayout {
-    
-    // L
     
-    /// Returns the alignment of the cell's top label.
-    ///
-    /// - Parameters:
-    ///   - attributes: The `MessageIntermediateLayoutAttributes` containing the `MessageType` object.
-    func cellTopLabelAlignment(for attributes: MessageIntermediateLayoutAttributes) -> LabelAlignment {
-        return messagesLayoutDelegate.cellTopLabelAlignment(for: attributes.message, at: attributes.indexPath, in: messagesCollectionView)
+    /// Set `outgoingMessageTopLabelAlignment` of all `MessageSizeCalculator`s
+    public func setMessageOutgoingMessageTopLabelAlignment(_ newAlignment: LabelAlignment) {
+        messageSizeCalculators().forEach { $0.outgoingMessageTopLabelAlignment = newAlignment }
     }
     
-    // M
-    
-    /// Returns the max available width for the cell's top label considering the specified layout information.
-    ///
-    /// - Parameters:
-    ///   - attributes: The `MessageIntermediateLayoutAttributes` to consider when calculating the max width.
-    func cellTopLabelMaxWidth(for attributes: MessageIntermediateLayoutAttributes) -> CGFloat {
-        
-        let labelHorizontal = attributes.topLabelAlignment
-        let avatarHorizontal = attributes.avatarPosition.horizontal
-        let avatarVertical = attributes.avatarPosition.vertical
-        let avatarWidth = attributes.avatarSize.width
-        
-        switch (labelHorizontal, avatarHorizontal) {
-
-        case (.cellLeading, _), (.cellTrailing, _):
-            let width = itemWidth - attributes.topLabelHorizontalPadding
-            return avatarVertical != .cellTop ? width : width - avatarWidth
-
-        case (.cellCenter, _):
-            let width = itemWidth - attributes.topLabelHorizontalPadding
-            return avatarVertical != .cellTop ? width : width - (avatarWidth * 2)
-
-        case (.messageTrailing, .cellLeading):
-            let width = attributes.messageContainerSize.width + attributes.messageContainerPadding.left - attributes.topLabelHorizontalPadding
-            return avatarVertical == .cellTop ? width : width + avatarWidth
-
-        case (.messageLeading, .cellTrailing):
-            let width = attributes.messageContainerSize.width + attributes.messageContainerPadding.right - attributes.topLabelHorizontalPadding
-            return avatarVertical == .cellTop ? width : width + avatarWidth
-
-        case (.messageLeading, .cellLeading):
-            return itemWidth - avatarWidth - attributes.messageContainerPadding.left - attributes.topLabelHorizontalPadding
-
-        case (.messageTrailing, .cellTrailing):
-            return itemWidth - avatarWidth - attributes.messageContainerPadding.right - attributes.topLabelHorizontalPadding
-
-        case (_, .natural):
-            fatalError(MessageKitError.avatarPositionUnresolved)
-        }
-        
+    /// Set `incomingMessageBottomLabelAlignment` of all `MessageSizeCalculator`s
+    public func setMessageIncomingMessageBottomLabelAlignment(_ newAlignment: LabelAlignment) {
+        messageSizeCalculators().forEach { $0.incomingMessageBottomLabelAlignment = newAlignment }
     }
     
-    // N
-    
-    /// Returns the size of the cell's top label considering the specified layout information.
-    ///
-    /// - Parameters:
-    ///   - attributes: The `MessageIntermediateLayoutAttributes` to consider when calculating label's size.
-    func cellTopLabelSize(for attributes: MessageIntermediateLayoutAttributes) -> CGSize {
-        
-        let text = messagesDataSource.cellTopLabelAttributedText(for: attributes.message, at: attributes.indexPath)
-        
-        guard let topLabelText = text else { return .zero }
-
-        return labelSize(for: topLabelText, considering: attributes.topLabelMaxWidth)
-
+    /// Set `outgoingMessageBottomLabelAlignment` of all `MessageSizeCalculator`s
+    public func setMessageOutgoingMessageBottomLabelAlignment(_ newAlignment: LabelAlignment) {
+        messageSizeCalculators().forEach { $0.outgoingMessageBottomLabelAlignment = newAlignment }
     }
     
-}
-
-// MARK: - Cell Sizing
-
-private extension MessagesCollectionViewFlowLayout {
-    
-    // P
-    
-    /// The height of a `MessageCollectionViewCell`.
-    ///
-    /// - Parameters:
-    ///   - attributes: The `MessageIntermediateLayoutAttributes` to use to determine the height of the cell.
-    private func cellHeight(for attributes: MessageIntermediateLayoutAttributes) -> CGFloat {
-        
-        var cellHeight: CGFloat = 0
-        
-        switch attributes.avatarPosition.vertical {
-        case .cellTop:
-            cellHeight += max(attributes.avatarSize.height, attributes.topLabelSize.height)
-            cellHeight += attributes.bottomLabelSize.height
-            cellHeight += attributes.messageContainerSize.height
-            cellHeight += attributes.messageVerticalPadding
-        case .cellBottom:
-            cellHeight += max(attributes.avatarSize.height, attributes.bottomLabelSize.height)
-            cellHeight += attributes.topLabelSize.height
-            cellHeight += attributes.messageContainerSize.height
-            cellHeight += attributes.messageVerticalPadding
-        case .messageTop, .messageCenter, .messageBottom:
-            cellHeight += max(attributes.avatarSize.height, attributes.messageContainerSize.height)
-            cellHeight += attributes.messageVerticalPadding
-            cellHeight += attributes.topLabelSize.height
-            cellHeight += attributes.bottomLabelSize.height
-        }
-        
-        return cellHeight
+    /// Get all `MessageSizeCalculator`s
+    open func messageSizeCalculators() -> [MessageSizeCalculator] {
+        return [textMessageSizeCalculator, attributedTextMessageSizeCalculator, emojiMessageSizeCalculator, photoMessageSizeCalculator, videoMessageSizeCalculator, locationMessageSizeCalculator]
     }
     
 }

+ 40 - 18
Pods/MessageKit/Sources/Layout/MessagesCollectionViewLayoutAttributes.swift

@@ -25,43 +25,65 @@
 import UIKit
 
 /// The layout attributes used by a `MessageCollectionViewCell` to layout its subviews.
-final class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttributes {
+open class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttributes {
 
     // MARK: - Properties
 
-    var avatarFrame: CGRect = .zero
+    public var avatarSize: CGSize = .zero
+    public var avatarPosition = AvatarPosition(vertical: .cellBottom)
 
-    var messageLabelFont: UIFont = UIFont.preferredFont(forTextStyle: .body)
-    var messageContainerFrame: CGRect = .zero
-    var messageLabelInsets: UIEdgeInsets = .zero
+    public var messageContainerSize: CGSize = .zero
+    public var messageContainerPadding: UIEdgeInsets = .zero
+    public var messageLabelFont: UIFont = UIFont.preferredFont(forTextStyle: .body)
+    public var messageLabelInsets: UIEdgeInsets = .zero
 
-    var topLabelFrame: CGRect = .zero
-    var bottomLabelFrame: CGRect = .zero
+    public var cellTopLabelAlignment = LabelAlignment(textAlignment: .center, textInsets: .zero)
+    public var cellTopLabelSize: CGSize = .zero
+    
+    public var messageTopLabelAlignment = LabelAlignment(textAlignment: .center, textInsets: .zero)
+    public var messageTopLabelSize: CGSize = .zero
+
+    public var messageBottomLabelAlignment = LabelAlignment(textAlignment: .center, textInsets: .zero)
+    public var messageBottomLabelSize: CGSize = .zero
 
     // MARK: - Methods
 
-    override func copy(with zone: NSZone? = nil) -> Any {
+    open override func copy(with zone: NSZone? = nil) -> Any {
         // swiftlint:disable force_cast
         let copy = super.copy(with: zone) as! MessagesCollectionViewLayoutAttributes
-        copy.avatarFrame = avatarFrame
-        copy.messageContainerFrame = messageContainerFrame
+        copy.avatarSize = avatarSize
+        copy.avatarPosition = avatarPosition
+        copy.messageContainerSize = messageContainerSize
+        copy.messageContainerPadding = messageContainerPadding
         copy.messageLabelFont = messageLabelFont
         copy.messageLabelInsets = messageLabelInsets
-        copy.topLabelFrame = topLabelFrame
-        copy.bottomLabelFrame = bottomLabelFrame
+        copy.cellTopLabelAlignment = cellTopLabelAlignment
+        copy.cellTopLabelSize = cellTopLabelSize
+        copy.messageTopLabelAlignment = messageTopLabelAlignment
+        copy.messageTopLabelSize = messageTopLabelSize
+        copy.messageBottomLabelAlignment = messageBottomLabelAlignment
+        copy.messageBottomLabelSize = messageBottomLabelSize
         return copy
         // swiftlint:enable force_cast
     }
 
-    override func isEqual(_ object: Any?) -> Bool {
-
+    open override func isEqual(_ object: Any?) -> Bool {
         // MARK: - LEAVE this as is
-        // swiftlint:disable unused_optional_binding
-        if let _ = object as? MessagesCollectionViewLayoutAttributes {
-            return super.isEqual(object)
+        if let attributes = object as? MessagesCollectionViewLayoutAttributes {
+            return super.isEqual(object) && attributes.avatarSize == avatarSize
+                && attributes.avatarPosition == attributes.avatarPosition
+                && attributes.messageContainerSize == messageContainerSize
+                && attributes.messageContainerPadding == messageContainerPadding
+                && attributes.messageLabelFont == messageLabelFont
+                && attributes.messageLabelInsets == messageLabelInsets
+                && attributes.cellTopLabelAlignment == cellTopLabelAlignment
+                && attributes.cellTopLabelSize == cellTopLabelSize
+                && attributes.messageTopLabelAlignment == messageTopLabelAlignment
+                && attributes.messageTopLabelSize == messageTopLabelSize
+                && attributes.messageBottomLabelAlignment == messageBottomLabelAlignment
+                && attributes.messageBottomLabelSize == messageBottomLabelSize
         } else {
             return false
         }
-        // swiftlint:enable unused_optional_binding
     }
 }

+ 90 - 0
Pods/MessageKit/Sources/Layout/TextMessageSizeCalculator.swift

@@ -0,0 +1,90 @@
+/*
+ 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
+
+open class TextMessageSizeCalculator: MessageSizeCalculator {
+
+    public var incomingMessageLabelInsets = UIEdgeInsets(top: 7, left: 18, bottom: 7, right: 14)
+    public var outgoingMessageLabelInsets = UIEdgeInsets(top: 7, left: 14, bottom: 7, right: 18)
+
+    public var messageLabelFont = UIFont.preferredFont(forTextStyle: .body)
+
+    internal func messageLabelInsets(for message: MessageType) -> UIEdgeInsets {
+        let dataSource = messagesLayout.messagesDataSource
+        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
+        return isFromCurrentSender ? outgoingMessageLabelInsets : incomingMessageLabelInsets
+    }
+
+    open override func messageContainerMaxWidth(for message: MessageType) -> CGFloat {
+        let maxWidth = super.messageContainerMaxWidth(for: message)
+        let textInsets = messageLabelInsets(for: message)
+        return maxWidth - textInsets.horizontal
+    }
+
+    open override func messageContainerSize(for message: MessageType) -> CGSize {
+        let maxWidth = messageContainerMaxWidth(for: message)
+
+        var messageContainerSize: CGSize
+        let attributedText: NSAttributedString
+
+        switch message.kind {
+        case .attributedText(let text):
+            attributedText = text
+        case .text(let text), .emoji(let text):
+            attributedText = NSAttributedString(string: text, attributes: [.font: messageLabelFont])
+        default:
+            fatalError("messageContainerSize received unhandled MessageDataType: \(message.kind)")
+        }
+
+        messageContainerSize = labelSize(for: attributedText, considering: maxWidth)
+
+        let messageInsets = messageLabelInsets(for: message)
+        messageContainerSize.width += messageInsets.horizontal
+        messageContainerSize.height += messageInsets.vertical
+
+        return messageContainerSize
+    }
+
+    open override func configure(attributes: UICollectionViewLayoutAttributes) {
+        super.configure(attributes: attributes)
+        guard let attributes = attributes as? MessagesCollectionViewLayoutAttributes else { return }
+
+        let dataSource = messagesLayout.messagesDataSource
+        let indexPath = attributes.indexPath
+        let message = dataSource.messageForItem(at: indexPath, in: messagesLayout.messagesCollectionView)
+
+        attributes.messageLabelInsets = messageLabelInsets(for: message)
+        attributes.messageLabelFont = messageLabelFont
+
+        switch message.kind {
+        case .attributedText(let text):
+            guard !text.string.isEmpty else { return }
+            guard let font = text.attribute(.font, at: 0, effectiveRange: nil) as? UIFont else { return }
+            attributes.messageLabelFont = font
+        default:
+            break
+        }
+    }
+}

+ 18 - 4
Pods/MessageKit/Sources/Models/AvatarPosition.swift

@@ -49,17 +49,21 @@ public struct AvatarPosition {
         /// Aligns the `AvatarView`'s top edge to the cell's top edge.
         case cellTop
         
-        /// Aligns the `AvatarView`'s bottom edge to the cell's bottom edge.
-        case cellBottom
+        /// Aligns the `AvatarView`'s top edge to the `messageTopLabel`'s top edge.
+        case messageLabelTop
         
         /// Aligns the `AvatarView`'s top edge to the `MessageContainerView`'s top edge.
         case messageTop
         
+        /// Aligns the `AvatarView` center to the `MessageContainerView` center.
+        case messageCenter
+        
         /// Aligns the `AvatarView`'s bottom edge to the `MessageContainerView`s bottom edge.
         case messageBottom
         
-        /// Aligns the `AvatarView` center to the `MessageContainerView` center.
-        case messageCenter
+        /// Aligns the `AvatarView`'s bottom edge to the cell's bottom edge.
+        case cellBottom
+        
     }
     
     // MARK: - Properties
@@ -82,3 +86,13 @@ public struct AvatarPosition {
     }
     
 }
+
+// MARK: - Equatable Conformance
+
+extension AvatarPosition: Equatable {
+
+    public static func == (lhs: AvatarPosition, rhs: AvatarPosition) -> Bool {
+        return lhs.vertical == rhs.vertical && lhs.horizontal == rhs.horizontal
+    }
+
+}

+ 3 - 1
Pods/MessageKit/Sources/Models/DetectorType.swift

@@ -30,6 +30,7 @@ public enum DetectorType {
     case date
     case phoneNumber
     case url
+    case transitInformation
 
     // MARK: - Not supported yet
 
@@ -37,12 +38,13 @@ public enum DetectorType {
     //case hashtag
     //case custom
 
-    var textCheckingType: NSTextCheckingResult.CheckingType {
+    internal var textCheckingType: NSTextCheckingResult.CheckingType {
         switch self {
         case .address: return .address
         case .date: return .date
         case .phoneNumber: return .phoneNumber
         case .url: return .link
+        case .transitInformation: return .transitInformation
         }
     }
 

+ 16 - 30
Pods/MessageKit/Sources/Models/LabelAlignment.swift

@@ -24,38 +24,24 @@
 
 import UIKit
 
-/// An enum represnting the horizontal alignment of a `MessageCollectionViewCell`'s top and bottom labels.
-public enum LabelAlignment {
+public struct LabelAlignment {
 
-    /// Aligns the label's trailing edge to the cell's trailing edge.
-    /// The `UIEdgeInsets` associated value represents the offset from this position.
-    case cellTrailing(UIEdgeInsets)
+    public var textAlignment: NSTextAlignment
+    public var textInsets: UIEdgeInsets
     
-    /// Aligns the label's leading edge to the cell's leading edge.
-    /// The `UIEdgeInsets` associated value represents the offset from this position.
-    case cellLeading(UIEdgeInsets)
-    
-    /// Aligns the label's center to the cell's center.
-    /// The `UIEdgeInsets` associated value represents the offset from this position.
-    case cellCenter(UIEdgeInsets)
-    
-    /// Aligns the label's trailing edge to the `MessageContainerView`'s trailing edge.
-    /// The `UIEdgeInsets` associated value represents the offset from this position.
-    case messageTrailing(UIEdgeInsets)
-    
-    /// Aligns the label's leading edge to the `MessageContainerView`'s leading edge.
-    /// The `UIEdgeInsets` associated value represents the offset from this position.
-    case messageLeading(UIEdgeInsets)
-
-    /// Returns the `UIEdgeInsets` associated value for the `LabelAlignment` case.
-    public var insets: UIEdgeInsets {
-        switch self {
-        case .cellTrailing(let insets): return insets
-        case .cellLeading(let insets): return insets
-        case .cellCenter(let insets): return insets
-        case .messageTrailing(let insets): return insets
-        case .messageLeading(let insets): return insets
-        }
+    public init(textAlignment: NSTextAlignment, textInsets: UIEdgeInsets) {
+        self.textAlignment = textAlignment
+        self.textInsets = textInsets
+    }
+
+}
+
+// MARK: - Equatable Conformance
+
+extension LabelAlignment: Equatable {
+
+    public static func == (lhs: LabelAlignment, rhs: LabelAlignment) -> Bool {
+        return lhs.textAlignment == rhs.textAlignment && lhs.textInsets == rhs.textInsets
     }
 
 }

+ 13 - 10
Pods/MessageKit/Sources/Models/MessageData.swift → Pods/MessageKit/Sources/Models/MessageKind.swift

@@ -23,17 +23,16 @@
  */
 
 import Foundation
-import class CoreLocation.CLLocation
 
-/// An enum representing the kind of message and its underlying data.
-public enum MessageData {
+/// An enum representing the kind of message and its underlying kind.
+public enum MessageKind {
 
     /// A standard text message.
     ///
-    /// NOTE: The font used for this message will be the value of the
+    /// - Note: The font used for this message will be the value of the
     /// `messageLabelFont` property in the `MessagesCollectionViewFlowLayout` object.
     ///
-    /// Tip: Using `MessageData.attributedText(NSAttributedString)` doesn't require you
+    /// Using `MessageKind.attributedText(NSAttributedString)` doesn't require you
     /// to set this property and results in higher performance.
     case text(String)
     
@@ -41,25 +40,29 @@ public enum MessageData {
     case attributedText(NSAttributedString)
 
     /// A photo message.
-    case photo(UIImage)
+    case photo(MediaItem)
 
     /// A video message.
-    case video(file: URL, thumbnail: UIImage)
+    case video(MediaItem)
 
     /// A location message.
-    case location(CLLocation)
+    case location(LocationItem)
 
     /// An emoji message.
     case emoji(String)
 
+    /// A custom message.
+    /// - Note: Using this case requires that you override the following methods and handle this case:
+    ///   - `collectionView(_:cellForItemAt indexPath: IndexPath) -> UICollectionViewCell`
+    ///   - `cellSizeCalculatorForItem(at indexPath: IndexPath) -> CellSizeCalculator`
+    case custom(Any?)
+
     // MARK: - Not supported yet
 
 //    case audio(Data)
 //
 //    case system(String)
 //    
-//    case custom(Any)
-//    
 //    case placeholder
 
 }

+ 13 - 11
Pods/MessageKit/Sources/Models/MessageKitError.swift

@@ -22,15 +22,17 @@
  SOFTWARE.
  */
 
-enum MessageKitError {
-    static let avatarPositionUnresolved = "AvatarPosition Horizontal.natural needs to be resolved."
-    static let nilMessagesDataSource = "MessagesDataSource has not been set."
-    static let nilMessagesDisplayDelegate = "MessagesDisplayDelegate has not been set."
-    static let nilMessagesLayoutDeleagte = "MessagesLayoutDelegate has not been set."
-    static let notMessagesCollectionView = "The collectionView is not a MessagesCollectionView."
-    static let layoutUsedOnForeignType = "MessagesCollectionViewFlowLayout is being used on a foreign type."
-    static let unrecognizedSectionKind = "Received unrecognized element kind:"
-    static let unrecognizedCheckingResult = "Received an unrecognized NSTextCheckingResult.CheckingType"
-    static let couldNotLoadAssetsBundle = "MessageKit: Could not load the assets bundle"
-    static let couldNotCreateAssetsPath = "MessageKit: Could not create path to the assets bundle."
+internal enum MessageKitError {
+    internal static let avatarPositionUnresolved = "AvatarPosition Horizontal.natural needs to be resolved."
+    internal static let nilMessagesDataSource = "MessagesDataSource has not been set."
+    internal static let nilMessagesDisplayDelegate = "MessagesDisplayDelegate has not been set."
+    internal static let nilMessagesLayoutDelegate = "MessagesLayoutDelegate has not been set."
+    internal static let notMessagesCollectionView = "The collectionView is not a MessagesCollectionView."
+    internal static let layoutUsedOnForeignType = "MessagesCollectionViewFlowLayout is being used on a foreign type."
+    internal static let unrecognizedSectionKind = "Received unrecognized element kind:"
+    internal static let unrecognizedCheckingResult = "Received an unrecognized NSTextCheckingResult.CheckingType"
+    internal static let couldNotLoadAssetsBundle = "MessageKit: Could not load the assets bundle"
+    internal static let couldNotCreateAssetsPath = "MessageKit: Could not create path to the assets bundle."
+    internal static let customDataUnresolvedCell = "Did not return a cell for MessageKind.custom(Any)."
+    internal static let customDataUnresolvedSize = "Did not return a size for MessageKind.custom(Any)."
 }

+ 2 - 2
Pods/MessageKit/Sources/Models/MessageStyle.swift

@@ -35,7 +35,7 @@ public enum MessageStyle {
         case topRight
         case bottomRight
 
-        var imageOrientation: UIImageOrientation {
+        internal var imageOrientation: UIImageOrientation {
             switch self {
             case .bottomRight: return .up
             case .bottomLeft: return .upMirrored
@@ -52,7 +52,7 @@ public enum MessageStyle {
         case curved
         case pointedEdge
 
-        var imageNameSuffix: String {
+        internal var imageNameSuffix: String {
             switch self {
             case .curved:
                 return "_tail_v2"

+ 20 - 14
Pods/MessageKit/Sources/Models/NSConstraintLayoutSet.swift

@@ -24,18 +24,18 @@
 
 import UIKit
 
-public class NSLayoutConstraintSet {
+internal class NSLayoutConstraintSet {
     
-    public var top: NSLayoutConstraint?
-    public var bottom: NSLayoutConstraint?
-    public var left: NSLayoutConstraint?
-    public var right: NSLayoutConstraint?
-    public var centerX: NSLayoutConstraint?
-    public var centerY: NSLayoutConstraint?
-    public var width: NSLayoutConstraint?
-    public var height: NSLayoutConstraint?
+    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?
     
-    public 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) {
@@ -51,15 +51,21 @@ public class NSLayoutConstraintSet {
 
     /// All of the currently configured constraints
     private var availableConstraints: [NSLayoutConstraint] {
-	    return [top, bottom, left, right, centerX, centerY, width, height]
-    	    .flatMap {$0}
+        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
-    func activate() -> Self {
+    internal func activate() -> Self {
         NSLayoutConstraint.activate(availableConstraints)
         return self
     }
@@ -68,7 +74,7 @@ public class NSLayoutConstraintSet {
     ///
     /// - Returns: Self
     @discardableResult
-    func deactivate() -> Self {
+    internal func deactivate() -> Self {
         NSLayoutConstraint.deactivate(availableConstraints)
         return self
     }

+ 36 - 0
Pods/MessageKit/Sources/Protocols/LocationItem.swift

@@ -0,0 +1,36 @@
+/*
+ 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 class CoreLocation.CLLocation
+
+/// A protocol used to represent the data for a location message.
+public protocol LocationItem {
+
+    /// The location.
+    var location: CLLocation { get }
+
+    /// The size of the location item.
+    var size: CGSize { get }
+
+}

+ 42 - 0
Pods/MessageKit/Sources/Protocols/MediaItem.swift

@@ -0,0 +1,42 @@
+/*
+ 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 protocol used to represent the data for a media message.
+public protocol MediaItem {
+
+    /// The url where the media is located.
+    var url: URL? { get }
+
+    /// The image.
+    var image: UIImage? { get }
+
+    /// A placeholder image for when the image is obtained asychronously.
+    var placeholderImage: UIImage { get }
+
+    /// The size of the media item.
+    var size: CGSize { get }
+
+}

+ 25 - 13
Pods/MessageKit/Sources/Protocols/MessageCellDelegate.swift

@@ -24,48 +24,59 @@
 
 import Foundation
 
-/// A protocol used by `MessageCollectionViewCell` subclasses to detect taps in the cell's contents.
+/// A protocol used by `MessageContentCell` subclasses to detect taps in the cell's subviews.
 public protocol MessageCellDelegate: MessageLabelDelegate {
 
-    /// Triggered when a touch occurs in the `MessageContainerView`.
+    /// Triggered when a tap occurs in the `MessageContainerView`.
     ///
     /// - Parameters:
-    ///   - cell: The cell where the touch occurred.
+    ///   - cell: The cell where the tap occurred.
     ///
+    /// - Note:
     /// 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 didTapMessage(in cell: MessageCollectionViewCell)
 
-    /// Triggered when a touch occurs in the `AvatarView`.
+    /// Triggered when a tap occurs in the `AvatarView`.
     ///
     /// - Parameters:
-    ///   - cell: The cell where the touch occurred.
+    ///   - 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 didTapAvatar(in cell: MessageCollectionViewCell)
 
-    /// Triggered when a touch occurs in the cellBottomLabel.
+    /// Triggered when a tap occurs in the cellTopLabel.
     ///
     /// - Parameters:
-    ///   - cell: The cell where the touch occurred.
+    ///   - cell: The cell tap the touch 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 didTapBottomLabel(in cell: MessageCollectionViewCell)
+    func didTapCellTopLabel(in cell: MessageCollectionViewCell)
+    
+    /// Triggered when a tap occurs in the messageTopLabel.
+    ///
+    /// - Parameters:
+    ///   - cell: The cell tap the touch 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 didTapMessageTopLabel(in cell: MessageCollectionViewCell)
 
-    /// Triggered when a touch occurs in the cellTopLabel.
+    /// Triggered when a tap occurs in the messageBottomLabel.
     ///
     /// - Parameters:
-    ///   - cell: The cell where the touch occurred.
+    ///   - 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 didTapTopLabel(in cell: MessageCollectionViewCell)
+    func didTapMessageBottomLabel(in cell: MessageCollectionViewCell)
 
 }
 
@@ -75,8 +86,9 @@ public extension MessageCellDelegate {
 
     func didTapAvatar(in cell: MessageCollectionViewCell) {}
 
-    func didTapBottomLabel(in cell: MessageCollectionViewCell) {}
+    func didTapCellTopLabel(in cell: MessageCollectionViewCell) {}
 
-    func didTapTopLabel(in cell: MessageCollectionViewCell) {}
+    func didTapMessageTopLabel(in cell: MessageCollectionViewCell) {}
 
+    func didTapMessageBottomLabel(in cell: MessageCollectionViewCell) {}
 }

+ 11 - 10
Pods/MessageKit/Sources/Protocols/MessageInputBarDelegate.swift

@@ -24,26 +24,27 @@
 
 import Foundation
 
-/// MessageInputBarDelegate is a protocol that can recieve notifications from the MessageInputBar
+/// A protocol that can receive different event notifications from the MessageInputBar.
 public protocol MessageInputBarDelegate: AnyObject {
     
-    /// Called when the default send button has been selected
+    /// Called when the default send button has been selected.
     ///
     /// - Parameters:
-    ///   - inputBar: The MessageInputBar
-    ///   - text: The current text in the MessageInputBar's InputTextView
+    ///   - inputBar: The `MessageInputBar`.
+    ///   - text: The current text in the `InputTextView` of the `MessageInputBar`.
     func messageInputBar(_ inputBar: MessageInputBar, didPressSendButtonWith text: String)
     
-    /// Called when the instrinsicContentSize of the MessageInputBar has changed. Can be used for adjusting content insets
-    /// on other views to make sure the MessageInputBar does not cover up any other view
+    /// Called when the instrinsicContentSize of the MessageInputBar has changed.
+    /// Can be used for adjusting content insets on other views to make sure
+    /// the MessageInputBar does not cover up any other view.
     ///
     /// - Parameters:
-    ///   - inputBar: The MessageInputBar
-    ///   - size: The new instrinsicContentSize
+    ///   - inputBar: The `MessageInputBar`.
+    ///   - size: The new instrinsic content size.
     func messageInputBar(_ inputBar: MessageInputBar, didChangeIntrinsicContentTo size: CGSize)
     
-    /// Called when the MessageInputBar's InputTextView's text has changed. Useful for adding your own logic without the
-    /// need of assigning a delegate or notification
+    /// Called when the `MessageInputBar`'s `InputTextView`'s text has changed.
+    /// Useful for adding your own logic without the need of assigning a delegate or notification.
     ///
     /// - Parameters:
     ///   - inputBar: The MessageInputBar

+ 25 - 0
Pods/MessageKit/Sources/Protocols/MessageLabelDelegate.swift

@@ -24,16 +24,39 @@
 
 import Foundation
 
+/// A protocol used to handle tap events on detected text.
 public protocol MessageLabelDelegate: AnyObject {
 
+    /// Triggered when a tap occurs on a detected address.
+    ///
+    /// - Parameters:
+    ///   - addressComponents: The components of the selected address.
     func didSelectAddress(_ addressComponents: [String: String])
 
+    /// Triggered when a tap occurs on a detected date.
+    ///
+    /// - Parameters:
+    ///   - date: The selected date.
     func didSelectDate(_ date: Date)
 
+    /// Triggered when a tap occurs on a detected phone number.
+    ///
+    /// - Parameters:
+    ///   - phoneNumber: The selected phone number.
     func didSelectPhoneNumber(_ phoneNumber: String)
 
+    /// Triggered when a tap occurs on a detected URL.
+    ///
+    /// - Parameters:
+    ///   - url: The selected URL.
     func didSelectURL(_ url: URL)
 
+    /// Triggered when a tap occurs on detected transit information.
+    ///
+    /// - Parameters:
+    ///   - transitInformation: The selected transit information.
+    func didSelectTransitInformation(_ transitInformation: [String: String])
+
 }
 
 public extension MessageLabelDelegate {
@@ -45,5 +68,7 @@ public extension MessageLabelDelegate {
     func didSelectPhoneNumber(_ phoneNumber: String) {}
 
     func didSelectURL(_ url: URL) {}
+    
+    func didSelectTransitInformation(_ transitInformation: [String: String]) {}
 
 }

+ 4 - 7
Pods/MessageKit/Sources/Protocols/MessageType.swift

@@ -24,23 +24,20 @@
 
 import Foundation
 
-/// A standard protocol representing a message. Use this protocol to create
-/// your own message object to be used by MessageKit.
+/// A standard protocol representing a message.
+/// Use this protocol to create your own message object to be used by MessageKit.
 public protocol MessageType {
 
     /// The sender of the message.
     var sender: Sender { get }
 
     /// The unique identifier for the message.
-    ///
-    /// NOTE: This value must be unique for all messages as it is
-    /// used to cache layout information.
     var messageId: String { get }
 
     /// The date the message was sent.
     var sentDate: Date { get }
 
-    /// The kind of message and its underlying data.
-    var data: MessageData { get }
+    /// The kind of message and its underlying kind.
+    var kind: MessageKind { get }
 
 }

+ 38 - 8
Pods/MessageKit/Sources/Protocols/MessagesDataSource.swift

@@ -24,18 +24,21 @@
 
 import UIKit
 
+/// An object that adopts the `MessagesDataSource` protocol is responsible for providing
+/// the data required by a `MessagesCollectionView`.
 public protocol MessagesDataSource: AnyObject {
 
     /// The `Sender` of new messages in the `MessagesCollectionView`.
     func currentSender() -> Sender
 
-    /// A helper method to determine if a given message is from the current sender.
+    /// A helper method to determine if a given message is from the current `Sender`.
     ///
     /// - Parameters:
-    ///   - message: The message to check if it was sent by the current Sender.
+    ///   - message: The message to check if it was sent by the current `Sender`.
     ///
-    /// The default implementation of this method checks for equality between the message's `Sender`
-    /// and the current Sender.
+    /// - Note:
+    ///   The default implementation of this method checks for equality between
+    ///   the message's `Sender` and the current `Sender`.
     func isFromCurrentSender(message: MessageType) -> Bool
 
     /// The message to be used for a `MessageCollectionViewCell` at the given `IndexPath`.
@@ -45,11 +48,20 @@ public protocol MessagesDataSource: AnyObject {
     ///   - messagesCollectionView: The `MessagesCollectionView` in which the message will be displayed.
     func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType
 
-    /// The number of messages to be displayed in the `MessagesCollectionView`.
+    /// The number of sections to be displayed in the `MessagesCollectionView`.
     ///
     /// - Parameters:
     ///   - messagesCollectionView: The `MessagesCollectionView` in which the messages will be displayed.
-    func numberOfMessages(in messagesCollectionView: MessagesCollectionView) -> Int
+    func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int
+
+    /// The number of cells to be displayed in the `MessagesCollectionView`.
+    ///
+    /// - Parameters:
+    ///   - section: The number of the section in which the cells will be displayed.
+    ///   - messagesCollectionView: The `MessagesCollectionView` in which the messages will be displayed.
+    /// - Note:
+    ///   The default implementation of this method returns 1. Putting each message in its own section.
+    func numberOfItems(inSection section: Int, in messagesCollectionView: MessagesCollectionView) -> Int
 
     /// The attributed text to be used for cell's top label.
     ///
@@ -60,6 +72,16 @@ public protocol MessagesDataSource: AnyObject {
     ///
     /// The default value returned by this method is `nil`.
     func cellTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString?
+    
+    /// The attributed text to be used for message bubble's top label.
+    ///
+    /// - Parameters:
+    ///   - 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.
+    ///
+    /// The default value returned by this method is `nil`.
+    func messageTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString?
 
     /// The attributed text to be used for cell's bottom label.
     ///
@@ -69,7 +91,7 @@ public protocol MessagesDataSource: AnyObject {
     ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
     ///
     /// The default value returned by this method is `nil`.
-    func cellBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString?
+    func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString?
 
 }
 
@@ -79,11 +101,19 @@ public extension MessagesDataSource {
         return message.sender == currentSender()
     }
 
+    func numberOfItems(inSection section: Int, in messagesCollectionView: MessagesCollectionView) -> Int {
+        return 1
+    }
+
     func cellTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
         return nil
     }
+    
+    func messageTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
+        return nil
+    }
 
-    func cellBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
+    func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
         return nil
     }
 

+ 61 - 72
Pods/MessageKit/Sources/Protocols/MessagesDisplayDelegate.swift

@@ -25,7 +25,7 @@
 import Foundation
 import MapKit
 
-/// A protocol used by the `MessagesViewController` to customize the appearance of a `MessageCollectionViewCell`.
+/// A protocol used by the `MessagesViewController` to customize the appearance of a `MessageContentCell`.
 public protocol MessagesDisplayDelegate: AnyObject {
 
     // MARK: - All Messages
@@ -37,7 +37,8 @@ public protocol MessagesDisplayDelegate: AnyObject {
     ///   - indexPath: The `IndexPath` of the cell.
     ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
     ///
-    /// The default value returned by this method is `MessageStyle.bubble`.
+    /// - Note:
+    ///   The default value returned by this method is `MessageStyle.bubble`.
     func messageStyle(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageStyle
 
     /// Specifies the background color of the `MessageContainerView`.
@@ -47,44 +48,31 @@ public protocol MessagesDisplayDelegate: AnyObject {
     ///   - indexPath: The `IndexPath` of the cell.
     ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
     ///
-    /// The default value is `UIColor.clear` for emoji messages. For all other `MessageData` cases, the color depends on the `Sender`:
+    /// - Note:
+    ///   The default value is `UIColor.clear` for emoji messages.
+    ///   For all other `MessageKind` cases, the color depends on the `Sender`.
     ///
-    /// Current Sender: Green
+    ///   Current sender: Green
     ///
-    /// All other Senders: Gray
+    ///   All other senders: Gray
     func backgroundColor(for message: MessageType, at  indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor
 
-    /// The section header to use for a given `MessageType`.
+    /// The section header to use for a given `IndexPath`.
     ///
     /// - Parameters:
     ///   - message: The `MessageType` that will be displayed for this header.
     ///   - indexPath: The `IndexPath` of the header.
     ///   - messagesCollectionView: The `MessagesCollectionView` in which this header will be displayed.
-    ///
-    /// The default value returned by this method is a `MessageDateHeaderView`.
-    func messageHeaderView(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageHeaderView
-
-    /// Used by the `MessageLayoutDelegate` method `headerViewSize(_:_:_:)` to determine if a header should be displayed.
-    /// This method checks `MessageCollectionView`'s `showsDateHeaderAfterTimeInterval` property and returns true if
-    /// the current messages sent date occurs after the specified time interval when compared to the previous message.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed for this header.
-    ///   - indexPath: The `IndexPath` of the header.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this header will be displayed.
-    func shouldDisplayHeader(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> Bool
+    func messageHeaderView(for indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageReusableView
 
-    /// The section footer to use for a given `MessageType`.
+    /// The section footer to use for a given `IndexPath`.
     ///
     /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed for this footer.
     ///   - indexPath: The `IndexPath` of the footer.
     ///   - messagesCollectionView: The `MessagesCollectionView` in which this footer will be displayed.
-    ///
-    /// The default value returned by this method is a `MessageFooterView`.
-    func messageFooterView(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageFooterView
+    func messageFooterView(for indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageReusableView
     
-    /// Configure `AvatarView`‘s image.
+    /// Used to configure the `AvatarView`‘s image in a `MessageContentCell` class.
     ///
     /// - Parameters:
     ///   - avatarView: The `AvatarView` of the cell.
@@ -92,7 +80,8 @@ public protocol MessagesDisplayDelegate: AnyObject {
     ///   - indexPath: The `IndexPath` of the cell.
     ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
     ///
-    /// The default image configured by this method is `?`.
+    /// - Note:
+    ///   The default image configured by this method is `?`.
     func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView)
 
     // MARK: - Text Messages
@@ -100,70 +89,78 @@ public protocol MessagesDisplayDelegate: AnyObject {
     /// Specifies the color of the text for a `TextMessageCell`.
     ///
     /// - Parameters:
-    ///   - message: A `MessageType` with a `MessageData` case of `.text` or `.attributedText` to which the color will apply.
+    ///   - message: A `MessageType` with a `MessageKind` case of `.text` to which the color will apply.
     ///   - indexPath: The `IndexPath` of the cell.
     ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
     ///
-    /// The default value returned by this method is determined by the messages `Sender`:
+    /// - Note:
+    ///   The default value returned by this method is determined by the messages `Sender`.
     ///
-    /// Current Sender: UIColor.white
+    ///   Current sender: UIColor.white
     ///
-    /// All other Senders: UIColor.darkText
+    ///   All other senders: UIColor.darkText
     func textColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor
 
     /// Specifies the `DetectorType`s to check for the `MessageType`'s text against.
     ///
     /// - Parameters:
-    ///   - message: A `MessageType` with a `MessageData` case of `.text` or `.attributedText` to which the detectors will apply.
+    ///   - message: A `MessageType` with a `MessageKind` case of `.text` or `.attributedText` to which the detectors will apply.
     ///   - indexPath: The `IndexPath` of the cell.
     ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
     ///
-    /// The default value returned by this method is all available detector types.
+    /// - Note:
+    ///   This method returns an empty array by default.
     func enabledDetectors(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> [DetectorType]
 
     /// Specifies the attributes for a given `DetectorType`
     ///
     /// - Parameters:
     ///   - detector: The `DetectorType` for the applied attributes.
-    ///   - message: A `MessageType` with a `MessageData` case of `.text` or `.attributedText`
-    ///   to which the detectors will apply.
+    ///   - message: A `MessageType` with a `MessageKind` case of `.text` or `.attributedText` to which the detectors will apply.
     ///   - indexPath: The `IndexPath` of the cell.
     func detectorAttributes(for detector: DetectorType, and message: MessageType, at indexPath: IndexPath) -> [NSAttributedStringKey: Any]
 
     // MARK: - Location Messages
 
-    /// Ask the delegate for a LocationMessageSnapshotOptions instance to customize the MapView on the given message
+    /// Used to configure a `LocationMessageSnapshotOptions` instance to customize the map image on the given location message.
     ///
     /// - Parameters:
-    ///   - message: The location message to be customized
-    ///   - indexPath: Message's index path
-    ///   - messagesCollectionView: The collection view requesting the information
-    /// - Returns: Your LocationMessageSnapshotOptions instance with the options to customize map style
+    ///   - message: A `MessageType` with a `MessageKind` case of `.location`.
+    ///   - indexPath: The `IndexPath` of the cell.
+    ///   - messagesCollectionView: The `MessagesCollectionView` requesting the information.
+    /// - Returns: The LocationMessageSnapshotOptions instance with the options to customize map style.
     func snapshotOptionsForLocation(message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> LocationMessageSnapshotOptions
 
-    /// Ask the delegate for a custom MKAnnotationView to show on the given message.
-    /// You can return nil if you don't want to show any annotation.
-    ///
-    /// default: MKPinAnnotationView
+    /// Used to configure the annoation view of the map image on the given location message.
     ///
     /// - Parameters:
-    ///   - message: The location message with the annotation to customize
-    ///   - indexPath: Message's index path
-    ///   - messageCollectionView: The collection view requesting the information
-    /// - Returns: Your customized MKAnnotationView or nil to not show any.
+    ///   - message: A `MessageType` with a `MessageKind` case of `.location`.
+    ///   - indexPath: The `IndexPath` of the cell.
+    ///   - messagesCollectionView: The `MessagesCollectionView` requesting the information.
+    /// - Returns: The `MKAnnotationView` to use as the annotation view.
     func annotationViewForLocation(message: MessageType, at indexPath: IndexPath, in messageCollectionView: MessagesCollectionView) -> MKAnnotationView?
 
-    /// Ask the delegate for a custom animation block to run when whe map screenshot is ready to be displaied in the given location message
-    /// The animation block is called with the image view to be animated. You can animate it with CoreAnimation, UIView.animate or any library you prefer.
-    ///
-    /// default: nil
+    /// Ask the delegate for a custom animation block to run when whe map screenshot is ready to be displaied in the given location message.
+    /// The animation block is called with the `UIImageView` to be animated.
     ///
     /// - Parameters:
-    ///   - message: The location message with the map to animate
-    ///   - indexPath: Message's index path
-    ///   - messagesCollectionView: The collection view requesting the information
-    /// - Returns: Your customized animation block.
+    ///   - message: A `MessageType` with a `MessageKind` case of `.location`.
+    ///   - indexPath: The `IndexPath` of the cell.
+    ///   - messagesCollectionView: The `MessagesCollectionView` requesting the information.
+    /// - Returns: The animation block to use to apply the location image.
     func animationBlockForLocation(message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> ((UIImageView) -> Void)?
+
+    // MARK: - Media Messages
+
+    /// Used to configure the `UIImageView` of a `MediaMessageCell.
+    ///
+    /// - Parameters:
+    ///   - imageView: The `UIImageView` 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.
+    func configureMediaMessageImageView(_ imageView: UIImageView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView)
+
 }
 
 public extension MessagesDisplayDelegate {
@@ -176,7 +173,7 @@ public extension MessagesDisplayDelegate {
 
     func backgroundColor(for message: MessageType, at  indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor {
 
-        switch message.data {
+        switch message.kind {
         case .emoji:
             return .clear
         default:
@@ -185,24 +182,12 @@ public extension MessagesDisplayDelegate {
         }
     }
     
-    func messageHeaderView(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageHeaderView {
-        let header = messagesCollectionView.dequeueReusableHeaderView(MessageDateHeaderView.self, for: indexPath)
-        header.dateLabel.text = MessageKitDateFormatter.shared.string(from: message.sentDate)
-        return header
-    }
-
-    func shouldDisplayHeader(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> Bool {
-        guard let dataSource = messagesCollectionView.messagesDataSource else { return false }
-        if indexPath.section == 0 { return false }
-        let previousSection = indexPath.section - 1
-        let previousIndexPath = IndexPath(item: 0, section: previousSection)
-        let previousMessage = dataSource.messageForItem(at: previousIndexPath, in: messagesCollectionView)
-        let timeIntervalSinceLastMessage = message.sentDate.timeIntervalSince(previousMessage.sentDate)
-        return timeIntervalSinceLastMessage >= messagesCollectionView.showsDateHeaderAfterTimeInterval
+    func messageHeaderView(for indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageReusableView {
+        return messagesCollectionView.dequeueReusableHeaderView(MessageReusableView.self, for: indexPath)
     }
 
-    func messageFooterView(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageFooterView {
-        return messagesCollectionView.dequeueReusableFooterView(MessageFooterView.self, for: indexPath)
+    func messageFooterView(for indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageReusableView {
+        return messagesCollectionView.dequeueReusableFooterView(MessageReusableView.self, for: indexPath)
     }
     
     func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) {
@@ -240,4 +225,8 @@ public extension MessagesDisplayDelegate {
         return nil
     }
 
+    // MARK: - Media Message Defaults
+
+    func configureMediaMessageImageView(_ imageView: UIImageView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) {
+    }
 }

+ 36 - 206
Pods/MessageKit/Sources/Protocols/MessagesLayoutDelegate.swift

@@ -23,255 +23,85 @@
  */
 
 import Foundation
-import AVFoundation
 
 /// A protocol used by the `MessagesCollectionViewFlowLayout` object to determine
 /// the size and layout of a `MessageCollectionViewCell` and its contents.
 public protocol MessagesLayoutDelegate: AnyObject {
 
-    // MARK: - All Messages
-
-    /// Specifies the padding around the `MessageContainerView` in a `MessageCollectionViewCell`.
-    ///
-    /// - Parameters:
-    ///   - 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.
-    ///
-    /// The default value returned by this method is determined by the messages `Sender`:
-    ///
-    /// Current Sender: `UIEdgeInsets(top: 0, left: 30, bottom: 0, right: 4)`
-    ///
-    /// All other Senders: `UIEdgeInsets(top: 0, left: 4, bottom: 0, right: 30)`
-    func messagePadding(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets
-    
-    /// Specifies the vertical and horizontal alignment for the `AvatarView` in a `MessageCollectionViewCell`.
-    ///
-    /// - Parameters:
-    ///   - 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.
-    ///
-    /// The default value returned by this method is an `AvatarPosition` with
-    /// `Horizontal.natural` and `Vertical.messageBottom`.
-    func avatarPosition(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> AvatarPosition
-
-    /// Specifies the horizontal alignment of a `MessageCollectionViewCell`'s top label.
-    ///
-    /// - Parameters:
-    ///   - 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.
-    ///
-    /// The default value returned by this method is determined by the messages `Sender`:
-    ///
-    /// Current Sender: .messageTrailing(.zero)
-    ///
-    /// All other senders: .messageLeading(.zero)
-    func cellTopLabelAlignment(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> LabelAlignment
-
-    /// Specifies the horizontal alignment of a `MessageCollectionViewCell`'s bottom label.
-    ///
-    /// - Parameters:
-    ///   - 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.
-    ///
-    /// The default value returned by this method is determined by the messages `Sender`:
-    ///
-    /// Current Sender: .messageLeading(.zero)
-    ///
-    /// All other senders: .messageTrailing(.zero)
-    func cellBottomLabelAlignment(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> LabelAlignment
-
-    /// Specifies the size of the `AvatarView` in a `MessageCollectionViewCell`.
-    ///
-    /// - Parameters:
-    ///   - 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.
-    ///
-    /// The default value returned by this method is a size of `30 x 30`.
-    func avatarSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize
-
-    /// Specifies the size to use for a `MessageHeaderView`.
+    /// Specifies the size to use for a header view.
     ///
     /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed for this header.
-    ///   - indexPath: The `IndexPath` of the header.
+    ///   - section: The section number of the header.
     ///   - messagesCollectionView: The `MessagesCollectionView` in which this header will be displayed.
     ///
-    /// The default value returned by this method is the width of the `MessagesCollectionView` and a height of 12.
-    func headerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize
+    /// - Note:
+    ///   The default value returned by this method is a size of `GGSize.zero`.
+    func headerViewSize(for section: Int, in messagesCollectionView: MessagesCollectionView) -> CGSize
 
-    /// Specifies the size to use for a `MessageFooterView`.
+    /// Specifies the size to use for a footer view.
     ///
     /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed for this footer.
-    ///   - indexPath: The `IndexPath` of the footer.
+    ///   - section: The section number of the footer.
     ///   - messagesCollectionView: The `MessagesCollectionView` in which this footer will be displayed.
     ///
-    /// The default value returned by this method is a size of `GGSize.zero`.
-    func footerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize
-
-    // MARK: - Text Messages
+    /// - Note:
+    ///   The default value returned by this method is a size of `GGSize.zero`.
+    func footerViewSize(for section: Int, in messagesCollectionView: MessagesCollectionView) -> CGSize
 
-    /// Specifies the insets for the text rect of the `MessageLabel` in a `TextMessageCell`.
+    /// Specifies the height for the `MessageContentCell`'s top label.
     ///
     /// - Parameters:
-    ///   - message: A `MessageType` with a `MessageData` case of `.text` or `.attributedText` to which these insets will apply.
+    ///   - message: The `MessageType` that will be displayed for this cell.
     ///   - indexPath: The `IndexPath` of the cell.
     ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
     ///
-    /// The default value returned by this method is determined by the messages `Sender`:
-    ///
-    /// Current Sender: `UIEdgeInsets(top: 7, left: 14, bottom: 7, right: 18)`
-    ///
-    /// All other Senders: `UIEdgeInsets(top: 7, left: 18, bottom: 7, right: 14)`
-    func messageLabelInset(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets
-
-    // MARK: - Media Messages
-
-    /// Specifies the width for a `MessageContainerView`.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed by this cell.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - maxWidth: The max available width for the `MessageContainerView` respecting the cell's other content.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// The default value returned by this method is the `maxWidth`.
-    func widthForMedia(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat
-
-    /// Specifies the height for a `MessageContainerView`.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed by this cell.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - maxWidth: The max available width for the `MessageContainerView` respecting the cell's other content.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// The default value returned by this method uses `AVMakeRect(aspectRatio:insideRect:)` with a bounding
-    /// rect using the `maxWidth` and `.greatestFiniteMagnitude` for the height.
-    func heightForMedia(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat
-
-    // MARK: - Location Messages
-
-    /// Specifies the width for a `MessageContainerView`.
+    /// - Note:
+    ///   The default value returned by this method is zero.
+    func cellTopLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat
+    
+    /// Specifies the height for the message bubble's top label.
     ///
     /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed by this cell.
+    ///   - message: The `MessageType` that will be displayed for this cell.
     ///   - indexPath: The `IndexPath` of the cell.
-    ///   - maxWidth: The max available width for the `MessageContainerView` respecting the cell's other content.
     ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
     ///
-    /// The default value returned by this method is the `maxWidth`.
-    func widthForLocation(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat
+    /// - Note:
+    ///   The default value returned by this method is zero.
+    func messageTopLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat
 
-    /// Specifies the height for a `MessageContainerView`.
+    /// Specifies the height for the `MessageContentCell`'s bottom label.
     ///
     /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed by this cell.
+    ///   - message: The `MessageType` that will be displayed for this cell.
     ///   - indexPath: The `IndexPath` of the cell.
-    ///   - maxWidth: The max available width for the `MessageContainerView` respecting the cell's other content.
     ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    func heightForLocation(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat
-
-    /// Specifies whether the layout attributes for a given `MessageType`
-    /// should be cached by the `MessagesCollectionViewFlowLayout`.
-    /// - Parameters:
-    ///   - message: The `MessageType` whose attributes to cache.
     ///
-    /// The default value returned by this method is `false`.
-    func shouldCacheLayoutAttributes(for message: MessageType) -> Bool
+    /// - Note:
+    ///   The default value returned by this method is zero.
+    func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat
 
 }
 
 public extension MessagesLayoutDelegate {
 
-    // MARK: - All Messages Defaults
-
-    func messagePadding(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets {
-        guard let dataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-        if dataSource.isFromCurrentSender(message: message) {
-            return UIEdgeInsets(top: 0, left: 30, bottom: 0, right: 4)
-        } else {
-            return UIEdgeInsets(top: 0, left: 4, bottom: 0, right: 30)
-        }
-    }
-
-    func cellTopLabelAlignment(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> LabelAlignment {
-        guard let dataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-        return dataSource.isFromCurrentSender(message: message) ? .messageTrailing(.zero) : .messageLeading(.zero)
-    }
-
-    func cellBottomLabelAlignment(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> LabelAlignment {
-        guard let dataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-        return dataSource.isFromCurrentSender(message: message) ? .messageLeading(.zero) : .messageTrailing(.zero)
-    }
-
-    func avatarSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
-        return CGSize(width: 30, height: 30)
-    }
-    
-    func avatarPosition(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> AvatarPosition {
-        return AvatarPosition(horizontal: .natural, vertical: .messageBottom)
-    }
-
-    func headerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
-        guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
-            fatalError(MessageKitError.nilMessagesDisplayDelegate)
-        }
-        let shouldDisplay = displayDelegate.shouldDisplayHeader(for: message, at: indexPath, in: messagesCollectionView)
-        return shouldDisplay ? CGSize(width: messagesCollectionView.bounds.width, height: 12) : .zero
-    }
-
-    func footerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
+    func headerViewSize(for section: Int, in messagesCollectionView: MessagesCollectionView) -> CGSize {
         return .zero
     }
 
-    func shouldCacheLayoutAttributes(for message: MessageType) -> Bool {
-        return false
+    func footerViewSize(for section: Int, in messagesCollectionView: MessagesCollectionView) -> CGSize {
+        return .zero
     }
 
-    // MARK: - Text Messages Defaults
-
-    func messageLabelInset(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets {
-        guard let dataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-        if dataSource.isFromCurrentSender(message: message) {
-            return UIEdgeInsets(top: 7, left: 14, bottom: 7, right: 18)
-        } else {
-            return UIEdgeInsets(top: 7, left: 18, bottom: 7, right: 14)
-        }
+    func cellTopLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
+        return 0
     }
-
-    // MARK: - Media Messages Defaults
-
-    func widthForMedia(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
-        return maxWidth
-    }
-
-    func heightForMedia(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
-        switch message.data {
-        case .photo(let image), .video(_, let image):
-            let boundingRect = CGRect(origin: .zero, size: CGSize(width: maxWidth, height: .greatestFiniteMagnitude))
-            return AVMakeRect(aspectRatio: image.size, insideRect: boundingRect).height
-        default:
-            return 0
-        }
+    
+    func messageTopLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
+        return 0
     }
 
-    // MARK: - Location Messages Defaults
-
-    func widthForLocation(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
-        return maxWidth
+    func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
+        return 0
     }
 }

+ 30 - 79
Pods/MessageKit/Sources/Supporting/MessageKit+Availability.swift

@@ -24,98 +24,49 @@
 
 import Foundation
 
-// MARK: - Deprecated Protocols
+public extension MessagesLayoutDelegate {
 
-@available(*, deprecated: 0.11.0, message: "LocationMessageDisplayDelegate has been deprecated in favor of MessagesDisplayDelegate")
-typealias LocationMessageDisplayDelegate = MessagesDisplayDelegate
-
-@available(*, deprecated: 0.11.0, message: "TextMessageDisplayDelegate has been deprecated in favor of MessagesDisplayDelegate")
-typealias TextMessageDisplayDelegate = MessagesDisplayDelegate
-
-@available(*, deprecated: 0.11.0, message: "LocationMessageLayoutDelegate has been deprecated in favor of MessagesDisplayDelegate")
-typealias LocationMessageLayoutDelegate = MessagesLayoutDelegate
-
-@available(*, deprecated: 0.11.0, message: "MediaMessageLayoutDelegate has been deprecated in favor of MessagesDisplayDelegate")
-typealias MediaMessageLayoutDelegate = MessagesLayoutDelegate
-
-// MARK: - AvatarAlignment
+    func avatarSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
+        fatalError("avatarSize(for:at:in) has been removed in MessageKit 1.0.")
+    }
 
-@available(*, deprecated: 0.11.0, message: "Removed in MessageKit 0.11.0. Please use AvatarPosition instead.")
-public enum AvatarAlignment {}
+    func avatarPosition(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> AvatarPosition {
+        fatalError("avatarPosition(for:at:in) has been removed in MessageKit 1.0.")
+    }
 
-// MARK: - MessagesLayoutDelegate
+    func messageLabelInset(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets {
+        fatalError("messageLabelInset(for:at:in) has been removed in MessageKit 1.0")
+    }
 
-extension MessagesLayoutDelegate {
-    
-    /// Specifies the vertical alignment for the `AvatarView` in a `MessageCollectionViewCell`.
-    ///
-    /// - Parameters:
-    ///   - 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.
-    ///
-    /// The default value returned by this method is `AvatarAlignment.cellBottom`.
-    @available(*, deprecated: 0.11.0, message: "Removed in MessageKit 0.11.0. Please use avatarPosition(for:at:in:) instead.")
-    public func avatarAlignment(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> AvatarAlignment {
-        fatalError("Please use avatarPosition(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> AvatarPosition instead.")
+    func messagePadding(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets {
+        fatalError("messagePadding(for:at:in) has been removed in MessageKit 1.0.")
     }
-    
-}
 
-// MARK: - MessagesCollectionViewFlowLayout
+    func cellTopLabelAlignment(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> LabelAlignment {
+        fatalError("cellTopLabelAlignment(for:at:in) has been removed in MessageKit 1.0.")
+    }
 
-extension MessagesCollectionViewFlowLayout {
-    
-    /// A Boolean value that determines if the `AvatarView` is always on the leading
-    /// side of a MessageCollectionViewCell.
-    ///
-    /// Setting this property to `true` causes `avatarAlwaysTrailing` to be set to `false`.
-    ///
-    /// The default value of this property is `false`.
-    @available(*, deprecated: 0.11.0, message: "Removed in MessageKit 0.11.0. Please use the avatarPosition(for:at:in) delegate method.")
-    public var avatarAlwaysLeading: Bool {
-        fatalError("Fatal Error: avatarAlwaysLeading is no longer supported")
+    func cellBottomLabelAlignment(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> LabelAlignment {
+        fatalError("cellBottomLabelAlignment(for:at:in) has been removed in MessageKit 1.0.")
     }
-    
-    /// A Boolean value that determines if the `AvatarView` is always on the trailing
-    /// side of a `MessageCollectionViewCell`.
-    ///
-    /// Setting this property to `true` causes `avatarAlwaysLeading` to be set to `false`.
-    ///
-    /// The default value of this property is `false`.
-    @available(*, deprecated: 0.11.0, message: "Removed in MessageKit 0.11.0. Please use the avatarPosition(for:at:in) delegate method instead.")
-    public var avatarAlwaysTrailing: Bool {
-        fatalError("Fatal Error: avatarAlwaysTrailing is no longer supported")
+
+    func widthForMedia(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
+        fatalError("widthForMedia(message:at:with:in) has been removed in MessageKit 1.0.")
     }
-    
-}
 
-// MARK: - MessagesDataSource
+    func heightForMedia(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
+        fatalError("heightForMedia(message:at:with:in) has been removed in MessageKit 1.0.")
+    }
 
-extension MessagesDataSource {
-    /// The `Avatar` information to be used by the `AvatarView`.
-    ///
-    /// - Parameters:
-    ///   - 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.
-    ///
-    /// The default value returned by this method is `Avatar()`.
-    @available(*, deprecated: 0.12.1, message: "Removed in MessageKit 0.12.1.")
-    func avatar(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> Avatar {
-        fatalError("Fatal Error: avatar(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) is no longer supported")
+    func widthForLocation(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
+        fatalError("widthForLocation(message:at:with:in) has been removed in MessageKit 1.0.")
     }
-}
 
-// MARK: - MessagesViewController
+   func heightForLocation(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
+        fatalError("heightForLocation(message:at:with:in) has been removed in MessageKit 1.0.")
+    }
 
-extension MessagesViewController {
-    /// A Boolean value that determines whether the `MessagesCollectionView` scrolls to the
-    /// bottom on the view's first layout.
-    ///
-    /// The default value of this property is `false`.
-    @available(*, deprecated: 0.11.1, message: "Removed in MessageKit 0.11.1.")
-    open var scrollsToBottomOnFirstLayout: Bool {
-        fatalError("Fatal Error: scrollsToBottomOnFirstLayout is no longer supported")
+    func shouldCacheLayoutAttributes(for message: MessageType) -> Bool {
+        fatalError("shouldCacheLayoutAttributes(for:) has been removed in MessageKit 1.0.")
     }
 }

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

@@ -96,8 +96,9 @@ open class AvatarView: UIImageView {
 
         //// Text Drawing
         let textRect = calculateTextRect(outerViewWidth: width, outerViewHeight: height)
+        let initialsText = NSAttributedString(string: initials, attributes: [.font: font])
         if adjustsFontSizeToFitWidth,
-            initials.width(considering: textRect.height, and: font) > textRect.width {
+            initialsText.width(considering: textRect.height) > textRect.width {
             let newFontSize = calculateFontSize(text: initials, font: font, width: textRect.width, height: textRect.height)
             font = placeholderFont.withSize(newFontSize)
         }
@@ -119,7 +120,8 @@ open class AvatarView: UIImageView {
      Recursively find the biggest size to fit the text with a given width and height
      */
     private func calculateFontSize(text: String, font: UIFont, width: CGFloat, height: CGFloat) -> CGFloat {
-        if text.width(considering: height, and: font) > width {
+        let attributedText = NSAttributedString(string: text, attributes: [.font: font])
+        if attributedText.width(considering: height) > width {
             let newFont = font.withSize(font.pointSize - 1)
             if newFont.pointSize > minimumFontSize {
                 return font.pointSize

+ 8 - 8
Pods/MessageKit/Sources/Views/Cells/LocationMessageCell.swift

@@ -25,14 +25,13 @@
 import UIKit
 import MapKit
 
-open class LocationMessageCell: MessageCollectionViewCell {
-
-    open override class func reuseIdentifier() -> String { return "messagekit.cell.location" }
-
-    // MARK: - Properties
+/// A subclass of `MessageContentCell` used to display location messages.
+open class LocationMessageCell: MessageContentCell {
 
+    /// The activity indicator to be displayed while the map image is loading.
     open var activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
 
+    /// The image view holding the map image.
     open var imageView = UIImageView()
     
     private weak var snapShotter: MKMapSnapshotter?
@@ -45,6 +44,7 @@ open class LocationMessageCell: MessageCollectionViewCell {
         setupConstraints()
     }
 
+    /// Responsible for setting up the constraints of the cell's subviews.
     open func setupConstraints() {
         imageView.fillSuperview()
         activityIndicator.centerInSuperview()
@@ -64,12 +64,12 @@ open class LocationMessageCell: MessageCollectionViewCell {
         let annotationView = displayDelegate.annotationViewForLocation(message: message, at: indexPath, in: messagesCollectionView)
         let animationBlock = displayDelegate.animationBlockForLocation(message: message, at: indexPath, in: messagesCollectionView)
 
-        guard case let .location(location) = message.data else { fatalError("") }
+        guard case let .location(locationItem) = message.kind else { fatalError("") }
 
         activityIndicator.startAnimating()
 
         let snapshotOptions = MKMapSnapshotOptions()
-        snapshotOptions.region = MKCoordinateRegion(center: location.coordinate, span: options.span)
+        snapshotOptions.region = MKCoordinateRegion(center: locationItem.location.coordinate, span: options.span)
         snapshotOptions.showsBuildings = options.showsBuildings
         snapshotOptions.showsPointsOfInterest = options.showsPointsOfInterest
 
@@ -93,7 +93,7 @@ open class LocationMessageCell: MessageCollectionViewCell {
 
             snapshot.image.draw(at: .zero)
 
-            var point = snapshot.point(for: location.coordinate)
+            var point = snapshot.point(for: locationItem.location.coordinate)
             //Move point to reflect annotation anchor
             point.x -= annotationView.bounds.size.width / 2
             point.y -= annotationView.bounds.size.height / 2

+ 22 - 11
Pods/MessageKit/Sources/Views/Cells/MediaMessageCell.swift

@@ -24,21 +24,25 @@
 
 import UIKit
 
-open class MediaMessageCell: MessageCollectionViewCell {
-
-    open override class func reuseIdentifier() -> String { return "messagekit.cell.mediamessage" }
-
-    // MARK: - Properties
+/// A subclass of `MessageContentCell` used to display video and audio messages.
+open class MediaMessageCell: MessageContentCell {
 
+    /// The play button view to display on video messages.
     open lazy var playButtonView: PlayButtonView = {
         let playButtonView = PlayButtonView()
         return playButtonView
     }()
 
-    open var imageView = UIImageView()
+    /// The image view display the media content.
+    open var imageView: UIImageView = {
+        let imageView = UIImageView()
+        imageView.contentMode = .scaleAspectFill
+        return imageView
+    }()
 
     // MARK: - Methods
 
+    /// Responsible for setting up the constraints of the cell's subviews.
     open func setupConstraints() {
         imageView.fillSuperview()
         playButtonView.centerInSuperview()
@@ -54,15 +58,22 @@ open class MediaMessageCell: MessageCollectionViewCell {
 
     open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
         super.configure(with: message, at: indexPath, and: messagesCollectionView)
-        switch message.data {
-        case .photo(let image):
-            imageView.image = image
+
+        guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
+            fatalError(MessageKitError.nilMessagesDisplayDelegate)
+        }
+
+        switch message.kind {
+        case .photo(let mediaItem):
+            imageView.image = mediaItem.image ?? mediaItem.placeholderImage
             playButtonView.isHidden = true
-        case .video(_, let image):
-            imageView.image = image
+        case .video(let mediaItem):
+            imageView.image = mediaItem.image ?? mediaItem.placeholderImage
             playButtonView.isHidden = false
         default:
             break
         }
+
+        displayDelegate.configureMediaMessageImageView(imageView, for: message, at: indexPath, in: messagesCollectionView)
     }
 }

+ 4 - 111
Pods/MessageKit/Sources/Views/Cells/MessageCollectionViewCell.swift

@@ -24,124 +24,17 @@
 
 import UIKit
 
-open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusable {
+/// A subclass of `UICollectionViewCell` to be used inside of a `MessagesCollectionView`.
+open class MessageCollectionViewCell: UICollectionViewCell {
 
-    open class func reuseIdentifier() -> String {
-        return "messagekit.cell.base-cell"
-    }
-
-    open var avatarView = AvatarView()
-
-    open var messageContainerView: MessageContainerView = {
-        let containerView = MessageContainerView()
-        containerView.clipsToBounds = true
-        containerView.layer.masksToBounds = true
-        return containerView
-    }()
-
-    open var cellTopLabel: UILabel = {
-        let label = UILabel()
-        label.numberOfLines = 0
-        return label
-    }()
-
-    open var cellBottomLabel: UILabel = {
-        let label = UILabel()
-        label.numberOfLines = 0
-        return label
-    }()
-
-    open weak var delegate: MessageCellDelegate?
+    // MARK: - Initializers
 
     public override init(frame: CGRect) {
         super.init(frame: frame)
-        contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
-        setupSubviews()
     }
 
-    required public init?(coder aDecoder: NSCoder) {
+    public required init?(coder aDecoder: NSCoder) {
         fatalError("init(coder:) has not been implemented")
     }
 
-    open func setupSubviews() {
-        contentView.addSubview(messageContainerView)
-        contentView.addSubview(avatarView)
-        contentView.addSubview(cellTopLabel)
-        contentView.addSubview(cellBottomLabel)
-    }
-
-    open override func prepareForReuse() {
-        super.prepareForReuse()
-        cellTopLabel.text = nil
-        cellTopLabel.attributedText = nil
-        cellBottomLabel.text = nil
-        cellBottomLabel.attributedText = nil
-    }
-
-    // MARK: - Configuration
-
-    open override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
-        super.apply(layoutAttributes)
-        if let attributes = layoutAttributes as? MessagesCollectionViewLayoutAttributes {
-            avatarView.frame = attributes.avatarFrame
-            cellTopLabel.frame = attributes.topLabelFrame
-            cellBottomLabel.frame = attributes.bottomLabelFrame
-            messageContainerView.frame = attributes.messageContainerFrame
-        }
-    }
-
-    open func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
-        guard let dataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-        guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
-            fatalError(MessageKitError.nilMessagesDisplayDelegate)
-        }
-
-        delegate = messagesCollectionView.messageCellDelegate
-
-        let messageColor = displayDelegate.backgroundColor(for: message, at: indexPath, in: messagesCollectionView)
-        let messageStyle = displayDelegate.messageStyle(for: message, at: indexPath, in: messagesCollectionView)
-        
-        displayDelegate.configureAvatarView(avatarView, for: message, at: indexPath, in: messagesCollectionView)
-
-        messageContainerView.backgroundColor = messageColor
-        messageContainerView.style = messageStyle
-
-        let topText = dataSource.cellTopLabelAttributedText(for: message, at: indexPath)
-        let bottomText = dataSource.cellBottomLabelAttributedText(for: message, at: indexPath)
-
-        cellTopLabel.attributedText = topText
-        cellBottomLabel.attributedText = bottomText
-    }
-
-    /// Handle tap gesture on contentView and its subviews like messageContainerView, cellTopLabel, cellBottomLabel, avatarView ....
-    open func handleTapGesture(_ gesture: UIGestureRecognizer) {
-        let touchLocation = gesture.location(in: self)
-
-        switch true {
-        case messageContainerView.frame.contains(touchLocation) && !cellContentView(canHandle: convert(touchLocation, to: messageContainerView)):
-            delegate?.didTapMessage(in: self)
-        case avatarView.frame.contains(touchLocation):
-            delegate?.didTapAvatar(in: self)
-        case cellTopLabel.frame.contains(touchLocation):
-            delegate?.didTapTopLabel(in: self)
-        case cellBottomLabel.frame.contains(touchLocation):
-            delegate?.didTapBottomLabel(in: self)
-        default:
-            break
-        }
-    }
-    
-    /// Handle long press gesture, return true when gestureRecognizer's touch point in `messageContainerView`'s frame
-    open override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
-        let touchPoint = gestureRecognizer.location(in: self)
-        guard gestureRecognizer.isKind(of: UILongPressGestureRecognizer.self) else { return false }
-        return messageContainerView.frame.contains(touchPoint)
-    }
-
-    /// Handle `ContentView`'s tap gesture, return false when `ContentView` doesn't needs to handle gesture
-    open func cellContentView(canHandle touchPoint: CGPoint) -> Bool {
-        return false
-    }
 }

+ 264 - 0
Pods/MessageKit/Sources/Views/Cells/MessageContentCell.swift

@@ -0,0 +1,264 @@
+/*
+ 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
+
+/// A subclass of `MessageCollectionViewCell` used to display text, media, and location messages.
+open class MessageContentCell: MessageCollectionViewCell {
+
+    /// The image view displaying the avatar.
+    open var avatarView = AvatarView()
+
+    /// The container used for styling and holding the message's content view.
+    open var messageContainerView: MessageContainerView = {
+        let containerView = MessageContainerView()
+        containerView.clipsToBounds = true
+        containerView.layer.masksToBounds = true
+        return containerView
+    }()
+
+    /// The top label of the cell.
+    open var cellTopLabel: InsetLabel = {
+        let label = InsetLabel()
+        label.numberOfLines = 0
+        label.textAlignment = .center
+        return label
+    }()
+    
+    /// The top label of the messageBubble.
+    open var messageTopLabel: InsetLabel = {
+        let label = InsetLabel()
+        label.numberOfLines = 0
+        return label
+    }()
+
+    /// The bottom label of the messageBubble.
+    open var messageBottomLabel: InsetLabel = {
+        let label = InsetLabel()
+        label.numberOfLines = 0
+        return label
+    }()
+
+    /// The `MessageCellDelegate` for the cell.
+    open weak var delegate: MessageCellDelegate?
+
+    public override init(frame: CGRect) {
+        super.init(frame: frame)
+        contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+        setupSubviews()
+    }
+
+    required public init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    open func setupSubviews() {
+        contentView.addSubview(cellTopLabel)
+        contentView.addSubview(messageTopLabel)
+        contentView.addSubview(messageBottomLabel)
+        contentView.addSubview(messageContainerView)
+        contentView.addSubview(avatarView)
+    }
+
+    open override func prepareForReuse() {
+        super.prepareForReuse()
+        cellTopLabel.text = nil
+        messageTopLabel.text = nil
+        messageBottomLabel.text = nil
+    }
+
+    // MARK: - Configuration
+
+    open override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
+        super.apply(layoutAttributes)
+        guard let attributes = layoutAttributes as? MessagesCollectionViewLayoutAttributes else { return }
+        // Call this before other laying out other subviews
+        layoutMessageContainerView(with: attributes)
+        layoutBottomLabel(with: attributes)
+        layoutCellTopLabel(with: attributes)
+        layoutMessageTopLabel(with: attributes)
+        layoutAvatarView(with: attributes)
+    }
+
+    /// Used to configure the cell.
+    ///
+    /// - Parameters:
+    ///   - message: The `MessageType` this cell displays.
+    ///   - indexPath: The `IndexPath` for this cell.
+    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell is contained.
+    open func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
+        guard let dataSource = messagesCollectionView.messagesDataSource else {
+            fatalError(MessageKitError.nilMessagesDataSource)
+        }
+        guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
+            fatalError(MessageKitError.nilMessagesDisplayDelegate)
+        }
+
+        delegate = messagesCollectionView.messageCellDelegate
+
+        let messageColor = displayDelegate.backgroundColor(for: message, at: indexPath, in: messagesCollectionView)
+        let messageStyle = displayDelegate.messageStyle(for: message, at: indexPath, in: messagesCollectionView)
+
+        displayDelegate.configureAvatarView(avatarView, for: message, at: indexPath, in: messagesCollectionView)
+
+        messageContainerView.backgroundColor = messageColor
+        messageContainerView.style = messageStyle
+
+        let topCellLabelText = dataSource.cellTopLabelAttributedText(for: message, at: indexPath)
+        let topMessageLabelText = dataSource.messageTopLabelAttributedText(for: message, at: indexPath)
+        let bottomText = dataSource.messageBottomLabelAttributedText(for: message, at: indexPath)
+
+        cellTopLabel.attributedText = topCellLabelText
+        messageTopLabel.attributedText = topMessageLabelText
+        messageBottomLabel.attributedText = bottomText
+    }
+
+    /// Handle tap gesture on contentView and its subviews.
+    open func handleTapGesture(_ gesture: UIGestureRecognizer) {
+        let touchLocation = gesture.location(in: self)
+
+        switch true {
+        case messageContainerView.frame.contains(touchLocation) && !cellContentView(canHandle: convert(touchLocation, to: messageContainerView)):
+            delegate?.didTapMessage(in: self)
+        case avatarView.frame.contains(touchLocation):
+            delegate?.didTapAvatar(in: self)
+        case cellTopLabel.frame.contains(touchLocation):
+            delegate?.didTapCellTopLabel(in: self)
+        case messageTopLabel.frame.contains(touchLocation):
+            delegate?.didTapMessageTopLabel(in: self)
+        case messageBottomLabel.frame.contains(touchLocation):
+            delegate?.didTapMessageBottomLabel(in: self)
+        default:
+            break
+        }
+    }
+
+    /// Handle long press gesture, return true when gestureRecognizer's touch point in `messageContainerView`'s frame
+    open override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
+        let touchPoint = gestureRecognizer.location(in: self)
+        guard gestureRecognizer.isKind(of: UILongPressGestureRecognizer.self) else { return false }
+        return messageContainerView.frame.contains(touchPoint)
+    }
+
+    /// Handle `ContentView`'s tap gesture, return false when `ContentView` doesn't needs to handle gesture
+    open func cellContentView(canHandle touchPoint: CGPoint) -> Bool {
+        return false
+    }
+
+    // MARK: - Origin Calculations
+
+    /// Positions the cell's `AvatarView`.
+    /// - attributes: The `MessagesCollectionViewLayoutAttributes` for the cell.
+    open func layoutAvatarView(with attributes: MessagesCollectionViewLayoutAttributes) {
+        var origin: CGPoint = .zero
+
+        switch attributes.avatarPosition.horizontal {
+        case .cellLeading:
+            break
+        case .cellTrailing:
+            origin.x = attributes.frame.width - attributes.avatarSize.width
+        case .natural:
+            fatalError(MessageKitError.avatarPositionUnresolved)
+        }
+
+        switch attributes.avatarPosition.vertical {
+        case .messageLabelTop:
+            origin.y = messageTopLabel.frame.minY
+        case .messageTop: // Needs messageContainerView frame to be set
+            origin.y = messageContainerView.frame.minY
+        case .messageBottom: // Needs messageContainerView frame to be set
+            origin.y = messageContainerView.frame.maxY - attributes.avatarSize.height
+        case .messageCenter: // Needs messageContainerView frame to be set
+            origin.y = messageContainerView.frame.midY - (attributes.avatarSize.height/2)
+        case .cellBottom:
+            origin.y = attributes.frame.height - attributes.avatarSize.height
+        default:
+            break
+        }
+
+        avatarView.frame = CGRect(origin: origin, size: attributes.avatarSize)
+    }
+
+    /// Positions the cell's `MessageContainerView`.
+    /// - attributes: The `MessagesCollectionViewLayoutAttributes` for the cell.
+    open func layoutMessageContainerView(with attributes: MessagesCollectionViewLayoutAttributes) {
+        var origin: CGPoint = .zero
+
+        switch attributes.avatarPosition.vertical {
+        case .messageBottom:
+            origin.y = attributes.size.height - attributes.messageContainerPadding.bottom - attributes.messageBottomLabelSize.height - attributes.messageContainerSize.height - attributes.messageContainerPadding.top
+        case .messageCenter:
+            if attributes.avatarSize.height > attributes.messageContainerSize.height {
+                let messageHeight = attributes.messageContainerSize.height + attributes.messageContainerPadding.vertical
+                origin.y = (attributes.size.height / 2) - (messageHeight / 2)
+            } else {
+                fallthrough
+            }
+        default:
+            origin.y = attributes.cellTopLabelSize.height + attributes.messageTopLabelSize.height + attributes.messageContainerPadding.top
+        }
+
+        switch attributes.avatarPosition.horizontal {
+        case .cellLeading:
+            origin.x = attributes.avatarSize.width + attributes.messageContainerPadding.left
+        case .cellTrailing:
+            origin.x = attributes.frame.width - attributes.avatarSize.width - attributes.messageContainerSize.width - attributes.messageContainerPadding.right
+        case .natural:
+            fatalError(MessageKitError.avatarPositionUnresolved)
+        }
+
+        messageContainerView.frame = CGRect(origin: origin, size: attributes.messageContainerSize)
+    }
+
+    /// Positions the cell's top label.
+    /// - attributes: The `MessagesCollectionViewLayoutAttributes` for the cell.
+    open func layoutCellTopLabel(with attributes: MessagesCollectionViewLayoutAttributes) {
+        cellTopLabel.frame = CGRect(origin: .zero, size: attributes.cellTopLabelSize)
+    }
+    
+    /// Positions the message bubble's top label.
+    /// - attributes: The `MessagesCollectionViewLayoutAttributes` for the cell.
+    open func layoutMessageTopLabel(with attributes: MessagesCollectionViewLayoutAttributes) {
+        messageTopLabel.textAlignment = attributes.messageTopLabelAlignment.textAlignment
+        messageTopLabel.textInsets = attributes.messageTopLabelAlignment.textInsets
+
+        let y = messageContainerView.frame.minY - attributes.messageContainerPadding.top - attributes.messageTopLabelSize.height
+        let origin = CGPoint(x: 0, y: y)
+        
+        messageTopLabel.frame = CGRect(origin: origin, size: attributes.messageTopLabelSize)
+    }
+
+    /// Positions the cell's bottom label.
+    /// - attributes: The `MessagesCollectionViewLayoutAttributes` for the cell.
+    open func layoutBottomLabel(with attributes: MessagesCollectionViewLayoutAttributes) {
+        messageBottomLabel.textAlignment = attributes.messageBottomLabelAlignment.textAlignment
+        messageBottomLabel.textInsets = attributes.messageBottomLabelAlignment.textInsets
+
+        let y = messageContainerView.frame.maxY + attributes.messageContainerPadding.bottom
+        let origin = CGPoint(x: 0, y: y)
+
+        messageBottomLabel.frame = CGRect(origin: origin, size: attributes.messageBottomLabelSize)
+    }
+    
+}

+ 10 - 8
Pods/MessageKit/Sources/Views/Cells/TextMessageCell.swift

@@ -24,18 +24,19 @@
 
 import UIKit
 
-open class TextMessageCell: MessageCollectionViewCell {
-
-    open override class func reuseIdentifier() -> String { return "messagekit.cell.text" }
+/// A subclass of `MessageContentCell` used to display text messages.
+open class TextMessageCell: MessageContentCell {
 
     // MARK: - Properties
 
+    /// The `MessageCellDelegate` for the cell.
     open override weak var delegate: MessageCellDelegate? {
         didSet {
             messageLabel.delegate = delegate
         }
     }
 
+    /// The label used to display the message's text.
     open var messageLabel = MessageLabel()
 
     // MARK: - Methods
@@ -67,7 +68,6 @@ open class TextMessageCell: MessageCollectionViewCell {
             fatalError(MessageKitError.nilMessagesDisplayDelegate)
         }
 
-        let textColor = displayDelegate.textColor(for: message, at: indexPath, in: messagesCollectionView)
         let enabledDetectors = displayDelegate.enabledDetectors(for: message, at: indexPath, in: messagesCollectionView)
 
         messageLabel.configure {
@@ -76,9 +76,11 @@ open class TextMessageCell: MessageCollectionViewCell {
                 let attributes = displayDelegate.detectorAttributes(for: detector, and: message, at: indexPath)
                 messageLabel.setAttributes(attributes, detector: detector)
             }
-            switch message.data {
+            switch message.kind {
             case .text(let text), .emoji(let text):
+                let textColor = displayDelegate.textColor(for: message, at: indexPath, in: messagesCollectionView)
                 messageLabel.text = text
+                messageLabel.textColor = textColor
                 if let font = messageLabel.messageLabelFont {
                     messageLabel.font = font
                 }
@@ -87,13 +89,13 @@ open class TextMessageCell: MessageCollectionViewCell {
             default:
                 break
             }
-            // Needs to be set after the attributedText because it takes precedence
-            messageLabel.textColor = textColor
         }
     }
     
-    /// Handle `ContentView`'s tap gesture, return false when `ContentView` don't needs to handle gesture
+    /// Used to handle the cell's contentView's tap gesture.
+    /// Return false when the contentView does not need to handle the gesture.
     open override func cellContentView(canHandle touchPoint: CGPoint) -> Bool {
         return messageLabel.handleGesture(touchPoint)
     }
+
 }

+ 6 - 7
Pods/MessageKit/Sources/Views/Headers & Footers/MessageFooterView.swift → Pods/MessageKit/Sources/Views/Headers & Footers/MessageReusableView.swift

@@ -1,18 +1,18 @@
 /*
  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
@@ -22,10 +22,9 @@
  SOFTWARE.
  */
 
-import UIKit
+import Foundation
 
-open class MessageFooterView: UICollectionReusableView, CollectionViewReusable {
-    open class func reuseIdentifier() -> String { return "messagekit.footer.base" }
+open class MessageReusableView: UICollectionReusableView {
 
     // MARK: - Initializers
 

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

@@ -46,7 +46,7 @@ open class InputStackView: UIStackView {
     
     // MARK: Initialization
     
-    convenience init(axis: UILayoutConstraintAxis, spacing: CGFloat) {
+    public convenience init(axis: UILayoutConstraintAxis, spacing: CGFloat) {
         self.init(frame: .zero)
         self.axis = axis
         self.spacing = spacing

+ 2 - 0
Pods/MessageKit/Sources/Views/InputTextView.swift

@@ -166,6 +166,7 @@ open class InputTextView: UITextView {
         setupObservers()
     }
     
+    // swiftlint:disable colon
     /// Adds the placeholderLabel to the view and sets up its initial constraints
     private func setupPlaceholderLabel() {
         
@@ -182,6 +183,7 @@ open class InputTextView: UITextView {
         placeholderLabelConstraintSet?.centerY?.priority = .defaultLow
         placeholderLabelConstraintSet?.activate()
     }
+    // swiftlint:enable colon
     
     /// Adds the required notification observers
     private func setupObservers() {

+ 10 - 12
Pods/MessageKit/Sources/Views/Headers & Footers/MessageHeaderView.swift → Pods/MessageKit/Sources/Views/InsetLabel.swift

@@ -1,18 +1,18 @@
 /*
  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
@@ -24,17 +24,15 @@
 
 import UIKit
 
-open class MessageHeaderView: UICollectionReusableView, CollectionViewReusable {
-    open class func reuseIdentifier() -> String { return "messagekit.header.base" }
-
-    // MARK: - Properties
+open class InsetLabel: UILabel {
 
-    public override init(frame: CGRect) {
-        super.init(frame: frame)
+    open var textInsets: UIEdgeInsets = .zero {
+        didSet { setNeedsDisplay() }
     }
 
-    public required init?(coder aDecoder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
+    open override func drawText(in rect: CGRect) {
+        let insetRect = UIEdgeInsetsInsetRect(rect, textInsets)
+        super.drawText(in: insetRect)
     }
 
 }

+ 3 - 5
Pods/MessageKit/Sources/Views/MessageContainerView.swift

@@ -48,10 +48,8 @@ open class MessageContainerView: UIImageView {
         switch style {
         case .none, .custom:
             break
-        case .bubble, .bubbleTail:
+        case .bubble, .bubbleTail, .bubbleOutline, .bubbleTailOutline:
             imageMask.frame = bounds
-        case .bubbleOutline, .bubbleTailOutline:
-            imageMask.frame = bounds.insetBy(dx: 1.0, dy: 1.0)
         }
     }
 
@@ -70,11 +68,11 @@ open class MessageContainerView: UIImageView {
             image = style.image?.withRenderingMode(.alwaysTemplate)
             tintColor = color
         case .bubbleTailOutline(let color, let tail, let corner):
-            let bubbleStyle: MessageStyle = .bubbleTailOutline(.white, tail, corner)
+            let bubbleStyle: MessageStyle = .bubbleTail(tail, corner)
             imageMask.image = bubbleStyle.image
             sizeMaskToView()
             mask = imageMask
-            image = style.image
+            image = style.image?.withRenderingMode(.alwaysTemplate)
             tintColor = color
         case .none:
             mask = nil

+ 5 - 1
Pods/MessageKit/Sources/Views/MessageInputBar.swift

@@ -335,11 +335,12 @@ open class MessageInputBar: UIView {
         setStackViewItems([sendButton], forStack: .right, animated: false)
     }
     
+    // swiftlint:disable function_body_length colon
     /// Sets up the initial constraints of each subview
     private func setupConstraints() {
         
         // The constraints within the MessageInputBar
-        separatorLine.addConstraints(topAnchor, left: leftAnchor, right: rightAnchor, heightConstant: 1)
+        separatorLine.addConstraints(topAnchor, left: leftAnchor, right: rightAnchor)
         backgroundViewBottomAnchor = backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor)
         backgroundViewBottomAnchor?.isActive = true
         backgroundView.addConstraints(topStackView.bottomAnchor, left: leftAnchor, right: rightAnchor)
@@ -400,6 +401,7 @@ open class MessageInputBar: UIView {
         )
         activateConstraints()
     }
+    // swiftlint:enable function_body_length colon
     
     /// Respect iPhone X safeAreaInsets
     /// Adds a constraint to anchor the bottomAnchor of the contentView to the window's safeAreaLayoutGuide.bottomAnchor
@@ -565,6 +567,7 @@ open class MessageInputBar: UIView {
     
     // 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
     ///
     /// - Parameters:
@@ -623,6 +626,7 @@ open class MessageInputBar: UIView {
             setNewItems()
         }
     }
+    // swiftlint:enable function_body_length
     
     /// Sets the leftStackViewWidthConstant
     ///

+ 29 - 4
Pods/MessageKit/Sources/Views/MessageLabel.swift

@@ -132,6 +132,8 @@ open class MessageLabel: UILabel {
     open internal(set) var phoneNumberAttributes: [NSAttributedStringKey: Any] = defaultAttributes
 
     open internal(set) var urlAttributes: [NSAttributedStringKey: Any] = defaultAttributes
+    
+    open internal(set) var transitInformationAttributes: [NSAttributedStringKey: Any] = defaultAttributes
 
     public func setAttributes(_ attributes: [NSAttributedStringKey: Any], detector: DetectorType) {
         switch detector {
@@ -143,6 +145,8 @@ open class MessageLabel: UILabel {
             dateAttributes = attributes
         case .url:
             urlAttributes = attributes
+        case .transitInformation:
+            transitInformationAttributes = attributes
         }
         if isConfiguring {
             attributesNeedUpdate = true
@@ -270,6 +274,8 @@ open class MessageLabel: UILabel {
             return phoneNumberAttributes
         case .url:
             return urlAttributes
+        case .transitInformation:
+            return transitInformationAttributes
         }
 
     }
@@ -284,6 +290,8 @@ open class MessageLabel: UILabel {
             return phoneNumberAttributes
         case .link:
             return urlAttributes
+        case .transitInformation:
+            return transitInformationAttributes
         default:
             fatalError(MessageKitError.unrecognizedCheckingResult)
         }
@@ -326,6 +334,12 @@ open class MessageLabel: UILabel {
                 let tuple: (NSRange, MessageTextCheckingType) = (result.range, .link(result.url))
                 ranges.append(tuple)
                 rangesForDetectors.updateValue(ranges, forKey: .url)
+            case .transitInformation:
+                var ranges = rangesForDetectors[.transitInformation] ?? []
+                let tuple: (NSRange, MessageTextCheckingType) = (result.range, .transitInfoComponents(result.components))
+                ranges.append(tuple)
+                rangesForDetectors.updateValue(ranges, forKey: .transitInformation)
+
             default:
                 fatalError("Received an unrecognized NSTextCheckingResult.CheckingType")
             }
@@ -340,10 +354,9 @@ open class MessageLabel: UILabel {
         guard textStorage.length > 0 else { return nil }
 
         var location = location
-        let textOffset = CGPoint(x: textInsets.left, y: textInsets.right)
 
-        location.x -= textOffset.x
-        location.y -= textOffset.y
+        location.x -= textInsets.left
+        location.y -= textInsets.top
 
         let index = layoutManager.glyphIndex(for: location, in: textContainer)
 
@@ -359,7 +372,7 @@ open class MessageLabel: UILabel {
 
     }
 
-  func handleGesture(_ touchLocation: CGPoint) -> Bool {
+  internal func handleGesture(_ touchLocation: CGPoint) -> Bool {
 
         guard let index = stringIndex(at: touchLocation) else { return false }
 
@@ -393,6 +406,13 @@ open class MessageLabel: UILabel {
         case let .link(url):
             guard let url = url else { return }
             handleURL(url)
+        case let .transitInfoComponents(transitInformation):
+            var transformedTransitInformation = [String: String]()
+            guard let transitInformation = transitInformation else { return }
+            transitInformation.forEach { (key, value) in
+                transformedTransitInformation[key.rawValue] = value
+            }
+            handleTransitInformation(transformedTransitInformation)
         }
     }
     
@@ -412,6 +432,10 @@ open class MessageLabel: UILabel {
         delegate?.didSelectPhoneNumber(phoneNumber)
     }
     
+    private func handleTransitInformation(_ components: [String: String]) {
+        delegate?.didSelectTransitInformation(components)
+    }
+    
 }
 
 private enum MessageTextCheckingType {
@@ -419,4 +443,5 @@ private enum MessageTextCheckingType {
     case date(Date?)
     case phoneNumber(String?)
     case link(URL?)
+    case transitInfoComponents([NSTextCheckingKey: String]?)
 }

+ 49 - 6
Pods/MessageKit/Sources/Views/MessagesCollectionView.swift

@@ -36,14 +36,10 @@ open class MessagesCollectionView: UICollectionView {
 
     open weak var messageCellDelegate: MessageCellDelegate?
 
-    open var showsDateHeaderAfterTimeInterval: TimeInterval = 3600
-
     private var indexPathForLastItem: IndexPath? {
-
         let lastSection = numberOfSections - 1
         guard lastSection >= 0, numberOfItems(inSection: lastSection) > 0 else { return nil }
         return IndexPath(item: numberOfItems(inSection: lastSection) - 1, section: lastSection)
-
     }
 
     // MARK: - Initializers
@@ -51,6 +47,7 @@ open class MessagesCollectionView: UICollectionView {
     public override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
         super.init(frame: frame, collectionViewLayout: layout)
         backgroundColor = .white
+        registerReusableViews()
         setupGestureRecognizers()
     }
     
@@ -64,7 +61,15 @@ open class MessagesCollectionView: UICollectionView {
 
     // MARK: - Methods
     
-    func setupGestureRecognizers() {
+    private func registerReusableViews() {
+        register(TextMessageCell.self)
+        register(MediaMessageCell.self)
+        register(LocationMessageCell.self)
+        register(MessageReusableView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader)
+        register(MessageReusableView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter)
+    }
+    
+    private func setupGestureRecognizers() {
         let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture(_:)))
         tapGesture.delaysTouchesBegan = true
         addGestureRecognizer(tapGesture)
@@ -77,7 +82,7 @@ open class MessagesCollectionView: UICollectionView {
         let touchLocation = gesture.location(in: self)
         guard let indexPath = indexPathForItem(at: touchLocation) else { return }
         
-        let cell = cellForItem(at: indexPath) as? MessageCollectionViewCell
+        let cell = cellForItem(at: indexPath) as? MessageContentCell
         cell?.handleTapGesture(gesture)
     }
 
@@ -106,4 +111,42 @@ open class MessagesCollectionView: UICollectionView {
         setContentOffset(newOffset, animated: false)
     }
 
+    /// Registers a particular cell using its reuse-identifier
+    public func register<T: UICollectionViewCell>(_ cellClass: T.Type) {
+        register(cellClass, forCellWithReuseIdentifier: String(describing: T.self))
+    }
+
+    /// Registers a reusable view for a specific SectionKind
+    public func register<T: UICollectionReusableView>(_ headerFooterClass: T.Type, forSupplementaryViewOfKind kind: String) {
+        register(headerFooterClass,
+                 forSupplementaryViewOfKind: kind,
+                 withReuseIdentifier: String(describing: T.self))
+    }
+
+    /// Generically dequeues a cell of the correct type allowing you to avoid scattering your code with guard-let-else-fatal
+    public func dequeueReusableCell<T: UICollectionViewCell>(_ cellClass: T.Type, for indexPath: IndexPath) -> T {
+        guard let cell = dequeueReusableCell(withReuseIdentifier: String(describing: T.self), for: indexPath) as? T else {
+            fatalError("Unable to dequeue \(String(describing: cellClass)) with reuseId of \(String(describing: T.self))")
+        }
+        return cell
+    }
+
+    /// Generically dequeues a header of the correct type allowing you to avoid scattering your code with guard-let-else-fatal
+    public func dequeueReusableHeaderView<T: UICollectionReusableView>(_ viewClass: T.Type, for indexPath: IndexPath) -> T {
+        let view = dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: String(describing: T.self), for: indexPath)
+        guard let viewType = view as? T else {
+            fatalError("Unable to dequeue \(String(describing: viewClass)) with reuseId of \(String(describing: T.self))")
+        }
+        return viewType
+    }
+
+    /// Generically dequeues a footer of the correct type allowing you to avoid scattering your code with guard-let-else-fatal
+    public func dequeueReusableFooterView<T: UICollectionReusableView>(_ viewClass: T.Type, for indexPath: IndexPath) -> T {
+        let view = dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionFooter, withReuseIdentifier: String(describing: T.self), for: indexPath)
+        guard let viewType = view as? T else {
+            fatalError("Unable to dequeue \(String(describing: viewClass)) with reuseId of \(String(describing: T.self))")
+        }
+        return viewType
+    }
+
 }

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 532 - 369
Pods/Pods.xcodeproj/project.pbxproj


+ 19 - 0
Pods/SnapKit/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+
+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.

+ 129 - 0
Pods/SnapKit/README.md

@@ -0,0 +1,129 @@
+<img src="http://snapkit.io/images/banner.jpg" alt="" />
+
+SnapKit is a DSL to make Auto Layout easy on both iOS and OS X.
+
+[![Build Status](https://travis-ci.org/SnapKit/SnapKit.svg)](https://travis-ci.org/SnapKit/SnapKit)
+[![Platform](https://img.shields.io/cocoapods/p/SnapKit.svg?style=flat)](https://github.com/SnapKit/SnapKit)
+[![Cocoapods Compatible](https://img.shields.io/cocoapods/v/SnapKit.svg)](https://cocoapods.org/pods/SnapKit)
+[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
+
+#### ⚠️ **To use with Swift 3.x please ensure you are using >= 3.0.0** ⚠️ 
+#### ⚠️ **To use with Swift 4.x please ensure you are using >= 4.0.0** ⚠️ 
+
+## Contents
+
+- [Requirements](#requirements)
+- [Migration Guides](#migration-guides)
+- [Communication](#communication)
+- [Installation](#installation)
+- [Usage](#usage)
+- [Credits](#credits)
+- [License](#license)
+
+## Requirements
+
+- iOS 8.0+ / Mac OS X 10.11+ / tvOS 9.0+
+- Xcode 9.0+
+- Swift 3.0+
+
+## Communication
+
+- If you **need help**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/snapkit). (Tag 'snapkit')
+- If you'd like to **ask a general question**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/snapkit).
+- If you **found a bug**, open an issue.
+- If you **have a feature request**, open an issue.
+- If you **want to contribute**, submit a pull request.
+
+
+## Installation
+
+### CocoaPods
+
+[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command:
+
+```bash
+$ gem install cocoapods
+```
+
+> CocoaPods 1.1.0+ is required to build SnapKit 4.0.0+.
+
+To integrate SnapKit into your Xcode project using CocoaPods, specify it in your `Podfile`:
+
+```ruby
+source 'https://github.com/CocoaPods/Specs.git'
+platform :ios, '10.0'
+use_frameworks!
+
+target '<Your Target Name>' do
+    pod 'SnapKit', '~> 4.0.0'
+end
+```
+
+Then, run the following command:
+
+```bash
+$ pod install
+```
+
+### Carthage
+
+[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
+
+You can install Carthage with [Homebrew](http://brew.sh/) using the following command:
+
+```bash
+$ brew update
+$ brew install carthage
+```
+
+To integrate SnapKit into your Xcode project using Carthage, specify it in your `Cartfile`:
+
+```ogdl
+github "SnapKit/SnapKit" ~> 4.0.0
+```
+
+Run `carthage update` to build the framework and drag the built `SnapKit.framework` into your Xcode project.
+
+### Manually
+
+If you prefer not to use either of the aforementioned dependency managers, you can integrate SnapKit into your project manually.
+
+---
+
+## Usage
+
+### Quick Start
+
+```swift
+import SnapKit
+
+class MyViewController: UIViewController {
+
+    lazy var box = UIView()
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+
+        self.view.addSubview(box)
+        box.snp.makeConstraints { (make) -> Void in
+           make.width.height.equalTo(50)
+           make.center.equalTo(self.view)
+        }
+    }
+
+}
+```
+
+### Resources
+
+- [Documentation](http://snapkit.io/docs/)
+- [F.A.Q.](http://snapkit.io/faq/)
+
+## Credits
+
+- Robert Payne ([@robertjpayne](https://twitter.com/robertjpayne))
+- Many other contributors
+
+## License
+
+SnapKit is released under the MIT license. See LICENSE for details.

+ 306 - 0
Pods/SnapKit/Source/Constraint.swift

@@ -0,0 +1,306 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+public final class Constraint {
+
+    internal let sourceLocation: (String, UInt)
+    internal let label: String?
+
+    private let from: ConstraintItem
+    private let to: ConstraintItem
+    private let relation: ConstraintRelation
+    private let multiplier: ConstraintMultiplierTarget
+    private var constant: ConstraintConstantTarget {
+        didSet {
+            self.updateConstantAndPriorityIfNeeded()
+        }
+    }
+    private var priority: ConstraintPriorityTarget {
+        didSet {
+          self.updateConstantAndPriorityIfNeeded()
+        }
+    }
+    public var layoutConstraints: [LayoutConstraint]
+    
+    public var isActive: Bool {
+        set {
+            if newValue {
+                activate()
+            }
+            else {
+                deactivate()
+            }
+        }
+        
+        get {
+            for layoutConstraint in self.layoutConstraints {
+                if layoutConstraint.isActive {
+                    return true
+                }
+            }
+            return false
+        }
+    }
+    
+    // MARK: Initialization
+
+    internal init(from: ConstraintItem,
+                  to: ConstraintItem,
+                  relation: ConstraintRelation,
+                  sourceLocation: (String, UInt),
+                  label: String?,
+                  multiplier: ConstraintMultiplierTarget,
+                  constant: ConstraintConstantTarget,
+                  priority: ConstraintPriorityTarget) {
+        self.from = from
+        self.to = to
+        self.relation = relation
+        self.sourceLocation = sourceLocation
+        self.label = label
+        self.multiplier = multiplier
+        self.constant = constant
+        self.priority = priority
+        self.layoutConstraints = []
+
+        // get attributes
+        let layoutFromAttributes = self.from.attributes.layoutAttributes
+        let layoutToAttributes = self.to.attributes.layoutAttributes
+
+        // get layout from
+        let layoutFrom = self.from.layoutConstraintItem!
+
+        // get relation
+        let layoutRelation = self.relation.layoutRelation
+
+        for layoutFromAttribute in layoutFromAttributes {
+            // get layout to attribute
+            let layoutToAttribute: LayoutAttribute
+            #if os(iOS) || os(tvOS)
+                if layoutToAttributes.count > 0 {
+                    if self.from.attributes == .edges && self.to.attributes == .margins {
+                        switch layoutFromAttribute {
+                        case .left:
+                            layoutToAttribute = .leftMargin
+                        case .right:
+                            layoutToAttribute = .rightMargin
+                        case .top:
+                            layoutToAttribute = .topMargin
+                        case .bottom:
+                            layoutToAttribute = .bottomMargin
+                        default:
+                            fatalError()
+                        }
+                    } else if self.from.attributes == .margins && self.to.attributes == .edges {
+                        switch layoutFromAttribute {
+                        case .leftMargin:
+                            layoutToAttribute = .left
+                        case .rightMargin:
+                            layoutToAttribute = .right
+                        case .topMargin:
+                            layoutToAttribute = .top
+                        case .bottomMargin:
+                            layoutToAttribute = .bottom
+                        default:
+                            fatalError()
+                        }
+                    } else if self.from.attributes == self.to.attributes {
+                        layoutToAttribute = layoutFromAttribute
+                    } else {
+                        layoutToAttribute = layoutToAttributes[0]
+                    }
+                } else {
+                    if self.to.target == nil && (layoutFromAttribute == .centerX || layoutFromAttribute == .centerY) {
+                        layoutToAttribute = layoutFromAttribute == .centerX ? .left : .top
+                    } else {
+                        layoutToAttribute = layoutFromAttribute
+                    }
+                }
+            #else
+                if self.from.attributes == self.to.attributes {
+                    layoutToAttribute = layoutFromAttribute
+                } else if layoutToAttributes.count > 0 {
+                    layoutToAttribute = layoutToAttributes[0]
+                } else {
+                    layoutToAttribute = layoutFromAttribute
+                }
+            #endif
+
+            // get layout constant
+            let layoutConstant: CGFloat = self.constant.constraintConstantTargetValueFor(layoutAttribute: layoutToAttribute)
+
+            // get layout to
+            var layoutTo: AnyObject? = self.to.target
+
+            // use superview if possible
+            if layoutTo == nil && layoutToAttribute != .width && layoutToAttribute != .height {
+                layoutTo = layoutFrom.superview
+            }
+
+            // create layout constraint
+            let layoutConstraint = LayoutConstraint(
+                item: layoutFrom,
+                attribute: layoutFromAttribute,
+                relatedBy: layoutRelation,
+                toItem: layoutTo,
+                attribute: layoutToAttribute,
+                multiplier: self.multiplier.constraintMultiplierTargetValue,
+                constant: layoutConstant
+            )
+
+            // set label
+            layoutConstraint.label = self.label
+
+            // set priority
+            layoutConstraint.priority = LayoutPriority(rawValue: self.priority.constraintPriorityTargetValue)
+
+            // set constraint
+            layoutConstraint.constraint = self
+
+            // append
+            self.layoutConstraints.append(layoutConstraint)
+        }
+    }
+
+    // MARK: Public
+
+    @available(*, deprecated:3.0, message:"Use activate().")
+    public func install() {
+        self.activate()
+    }
+
+    @available(*, deprecated:3.0, message:"Use deactivate().")
+    public func uninstall() {
+        self.deactivate()
+    }
+
+    public func activate() {
+        self.activateIfNeeded()
+    }
+
+    public func deactivate() {
+        self.deactivateIfNeeded()
+    }
+
+    @discardableResult
+    public func update(offset: ConstraintOffsetTarget) -> Constraint {
+        self.constant = offset.constraintOffsetTargetValue
+        return self
+    }
+
+    @discardableResult
+    public func update(inset: ConstraintInsetTarget) -> Constraint {
+        self.constant = inset.constraintInsetTargetValue
+        return self
+    }
+
+    @discardableResult
+    public func update(priority: ConstraintPriorityTarget) -> Constraint {
+        self.priority = priority.constraintPriorityTargetValue
+        return self
+    }
+
+    @discardableResult
+    public func update(priority: ConstraintPriority) -> Constraint {
+        self.priority = priority.value
+        return self
+    }
+
+    @available(*, deprecated:3.0, message:"Use update(offset: ConstraintOffsetTarget) instead.")
+    public func updateOffset(amount: ConstraintOffsetTarget) -> Void { self.update(offset: amount) }
+
+    @available(*, deprecated:3.0, message:"Use update(inset: ConstraintInsetTarget) instead.")
+    public func updateInsets(amount: ConstraintInsetTarget) -> Void { self.update(inset: amount) }
+
+    @available(*, deprecated:3.0, message:"Use update(priority: ConstraintPriorityTarget) instead.")
+    public func updatePriority(amount: ConstraintPriorityTarget) -> Void { self.update(priority: amount) }
+
+    @available(*, obsoleted:3.0, message:"Use update(priority: ConstraintPriorityTarget) instead.")
+    public func updatePriorityRequired() -> Void {}
+
+    @available(*, obsoleted:3.0, message:"Use update(priority: ConstraintPriorityTarget) instead.")
+    public func updatePriorityHigh() -> Void { fatalError("Must be implemented by Concrete subclass.") }
+
+    @available(*, obsoleted:3.0, message:"Use update(priority: ConstraintPriorityTarget) instead.")
+    public func updatePriorityMedium() -> Void { fatalError("Must be implemented by Concrete subclass.") }
+
+    @available(*, obsoleted:3.0, message:"Use update(priority: ConstraintPriorityTarget) instead.")
+    public func updatePriorityLow() -> Void { fatalError("Must be implemented by Concrete subclass.") }
+
+    // MARK: Internal
+
+    internal func updateConstantAndPriorityIfNeeded() {
+        for layoutConstraint in self.layoutConstraints {
+            let attribute = (layoutConstraint.secondAttribute == .notAnAttribute) ? layoutConstraint.firstAttribute : layoutConstraint.secondAttribute
+            layoutConstraint.constant = self.constant.constraintConstantTargetValueFor(layoutAttribute: attribute)
+
+            let requiredPriority = ConstraintPriority.required.value
+            if (layoutConstraint.priority.rawValue < requiredPriority), (self.priority.constraintPriorityTargetValue != requiredPriority) {
+                layoutConstraint.priority = LayoutPriority(rawValue: self.priority.constraintPriorityTargetValue)
+            }
+        }
+    }
+
+    internal func activateIfNeeded(updatingExisting: Bool = false) {
+        guard let item = self.from.layoutConstraintItem else {
+            print("WARNING: SnapKit failed to get from item from constraint. Activate will be a no-op.")
+            return
+        }
+        let layoutConstraints = self.layoutConstraints
+
+        if updatingExisting {
+            var existingLayoutConstraints: [LayoutConstraint] = []
+            for constraint in item.constraints {
+                existingLayoutConstraints += constraint.layoutConstraints
+            }
+
+            for layoutConstraint in layoutConstraints {
+                let existingLayoutConstraint = existingLayoutConstraints.first { $0 == layoutConstraint }
+                guard let updateLayoutConstraint = existingLayoutConstraint else {
+                    fatalError("Updated constraint could not find existing matching constraint to update: \(layoutConstraint)")
+                }
+
+                let updateLayoutAttribute = (updateLayoutConstraint.secondAttribute == .notAnAttribute) ? updateLayoutConstraint.firstAttribute : updateLayoutConstraint.secondAttribute
+                updateLayoutConstraint.constant = self.constant.constraintConstantTargetValueFor(layoutAttribute: updateLayoutAttribute)
+            }
+        } else {
+            NSLayoutConstraint.activate(layoutConstraints)
+            item.add(constraints: [self])
+        }
+    }
+
+    internal func deactivateIfNeeded() {
+        guard let item = self.from.layoutConstraintItem else {
+            print("WARNING: SnapKit failed to get from item from constraint. Deactivate will be a no-op.")
+            return
+        }
+        let layoutConstraints = self.layoutConstraints
+        NSLayoutConstraint.deactivate(layoutConstraints)
+        item.remove(constraints: [self])
+    }
+}

+ 195 - 0
Pods/SnapKit/Source/ConstraintAttributes.swift

@@ -0,0 +1,195 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+internal struct ConstraintAttributes : OptionSet, ExpressibleByIntegerLiteral {
+    
+    typealias IntegerLiteralType = UInt
+    
+    internal init(rawValue: UInt) {
+        self.rawValue = rawValue
+    }
+    internal init(_ rawValue: UInt) {
+        self.init(rawValue: rawValue)
+    }
+    internal init(nilLiteral: ()) {
+        self.rawValue = 0
+    }
+    internal init(integerLiteral rawValue: IntegerLiteralType) {
+        self.init(rawValue: rawValue)
+    }
+    
+    internal private(set) var rawValue: UInt
+    internal static var allZeros: ConstraintAttributes { return 0 }
+    internal static func convertFromNilLiteral() -> ConstraintAttributes { return 0 }
+    internal var boolValue: Bool { return self.rawValue != 0 }
+    
+    internal func toRaw() -> UInt { return self.rawValue }
+    internal static func fromRaw(_ raw: UInt) -> ConstraintAttributes? { return self.init(raw) }
+    internal static func fromMask(_ raw: UInt) -> ConstraintAttributes { return self.init(raw) }
+    
+    // normal
+    
+    internal static var none: ConstraintAttributes { return 0 }
+    internal static var left: ConstraintAttributes { return 1 }
+    internal static var top: ConstraintAttributes {  return 2 }
+    internal static var right: ConstraintAttributes { return 4 }
+    internal static var bottom: ConstraintAttributes { return 8 }
+    internal static var leading: ConstraintAttributes { return 16 }
+    internal static var trailing: ConstraintAttributes { return 32 }
+    internal static var width: ConstraintAttributes { return 64 }
+    internal static var height: ConstraintAttributes { return 128 }
+    internal static var centerX: ConstraintAttributes { return 256 }
+    internal static var centerY: ConstraintAttributes { return 512 }
+    internal static var lastBaseline: ConstraintAttributes { return 1024 }
+    
+    @available(iOS 8.0, OSX 10.11, *)
+    internal static var firstBaseline: ConstraintAttributes { return 2048 }
+    
+    @available(iOS 8.0, *)
+    internal static var leftMargin: ConstraintAttributes { return 4096 }
+    
+    @available(iOS 8.0, *)
+    internal static var rightMargin: ConstraintAttributes { return 8192 }
+    
+    @available(iOS 8.0, *)
+    internal static var topMargin: ConstraintAttributes { return 16384 }
+    
+    @available(iOS 8.0, *)
+    internal static var bottomMargin: ConstraintAttributes { return 32768 }
+    
+    @available(iOS 8.0, *)
+    internal static var leadingMargin: ConstraintAttributes { return 65536 }
+    
+    @available(iOS 8.0, *)
+    internal static var trailingMargin: ConstraintAttributes { return 131072 }
+    
+    @available(iOS 8.0, *)
+    internal static var centerXWithinMargins: ConstraintAttributes { return 262144 }
+    
+    @available(iOS 8.0, *)
+    internal static var centerYWithinMargins: ConstraintAttributes { return 524288 }
+    
+    // aggregates
+    
+    internal static var edges: ConstraintAttributes { return 15 }
+    internal static var size: ConstraintAttributes { return 192 }
+    internal static var center: ConstraintAttributes { return 768 }
+    
+    @available(iOS 8.0, *)
+    internal static var margins: ConstraintAttributes { return 61440 }
+    
+    @available(iOS 8.0, *)
+    internal static var centerWithinMargins: ConstraintAttributes { return 786432 }
+    
+    internal var layoutAttributes:[LayoutAttribute] {
+        var attrs = [LayoutAttribute]()
+        if (self.contains(ConstraintAttributes.left)) {
+            attrs.append(.left)
+        }
+        if (self.contains(ConstraintAttributes.top)) {
+            attrs.append(.top)
+        }
+        if (self.contains(ConstraintAttributes.right)) {
+            attrs.append(.right)
+        }
+        if (self.contains(ConstraintAttributes.bottom)) {
+            attrs.append(.bottom)
+        }
+        if (self.contains(ConstraintAttributes.leading)) {
+            attrs.append(.leading)
+        }
+        if (self.contains(ConstraintAttributes.trailing)) {
+            attrs.append(.trailing)
+        }
+        if (self.contains(ConstraintAttributes.width)) {
+            attrs.append(.width)
+        }
+        if (self.contains(ConstraintAttributes.height)) {
+            attrs.append(.height)
+        }
+        if (self.contains(ConstraintAttributes.centerX)) {
+            attrs.append(.centerX)
+        }
+        if (self.contains(ConstraintAttributes.centerY)) {
+            attrs.append(.centerY)
+        }
+        if (self.contains(ConstraintAttributes.lastBaseline)) {
+            attrs.append(.lastBaseline)
+        }
+        
+        #if os(iOS) || os(tvOS)
+            if (self.contains(ConstraintAttributes.firstBaseline)) {
+                attrs.append(.firstBaseline)
+            }
+            if (self.contains(ConstraintAttributes.leftMargin)) {
+                attrs.append(.leftMargin)
+            }
+            if (self.contains(ConstraintAttributes.rightMargin)) {
+                attrs.append(.rightMargin)
+            }
+            if (self.contains(ConstraintAttributes.topMargin)) {
+                attrs.append(.topMargin)
+            }
+            if (self.contains(ConstraintAttributes.bottomMargin)) {
+                attrs.append(.bottomMargin)
+            }
+            if (self.contains(ConstraintAttributes.leadingMargin)) {
+                attrs.append(.leadingMargin)
+            }
+            if (self.contains(ConstraintAttributes.trailingMargin)) {
+                attrs.append(.trailingMargin)
+            }
+            if (self.contains(ConstraintAttributes.centerXWithinMargins)) {
+                attrs.append(.centerXWithinMargins)
+            }
+            if (self.contains(ConstraintAttributes.centerYWithinMargins)) {
+                attrs.append(.centerYWithinMargins)
+            }
+        #endif
+        
+        return attrs
+    }
+}
+
+internal func + (left: ConstraintAttributes, right: ConstraintAttributes) -> ConstraintAttributes {
+    return left.union(right)
+}
+
+internal func +=(left: inout ConstraintAttributes, right: ConstraintAttributes) {
+    left.formUnion(right)
+}
+
+internal func -=(left: inout ConstraintAttributes, right: ConstraintAttributes) {
+    left.subtract(right)
+}
+
+internal func ==(left: ConstraintAttributes, right: ConstraintAttributes) -> Bool {
+    return left.rawValue == right.rawValue
+}

+ 37 - 0
Pods/SnapKit/Source/ConstraintConfig.swift

@@ -0,0 +1,37 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+    public typealias ConstraintInterfaceLayoutDirection = UIUserInterfaceLayoutDirection
+#else
+    import AppKit
+    public typealias ConstraintInterfaceLayoutDirection = NSUserInterfaceLayoutDirection
+#endif
+
+
+public struct ConstraintConfig {
+    
+    public static var interfaceLayoutDirection: ConstraintInterfaceLayoutDirection = .leftToRight
+    
+}

+ 147 - 0
Pods/SnapKit/Source/ConstraintConstantTarget.swift

@@ -0,0 +1,147 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public protocol ConstraintConstantTarget {
+}
+
+extension CGPoint: ConstraintConstantTarget {
+}
+
+extension CGSize: ConstraintConstantTarget {    
+}
+
+extension ConstraintInsets: ConstraintConstantTarget {
+}
+
+extension ConstraintConstantTarget {
+    
+    internal func constraintConstantTargetValueFor(layoutAttribute: LayoutAttribute) -> CGFloat {
+        if let value = self as? CGFloat {
+            return value
+        }
+        
+        if let value = self as? Float {
+            return CGFloat(value)
+        }
+        
+        if let value = self as? Double {
+            return CGFloat(value)
+        }
+        
+        if let value = self as? Int {
+            return CGFloat(value)
+        }
+        
+        if let value = self as? UInt {
+            return CGFloat(value)
+        }
+        
+        if let value = self as? CGSize {
+            if layoutAttribute == .width {
+                return value.width
+            } else if layoutAttribute == .height {
+                return value.height
+            } else {
+                return 0.0
+            }
+        }
+        
+        if let value = self as? CGPoint {
+            #if os(iOS) || os(tvOS)
+                switch layoutAttribute {
+                case .left, .right, .leading, .trailing, .centerX, .leftMargin, .rightMargin, .leadingMargin, .trailingMargin, .centerXWithinMargins:
+                    return value.x
+                case .top, .bottom, .centerY, .topMargin, .bottomMargin, .centerYWithinMargins, .lastBaseline, .firstBaseline:
+                    return value.y
+                case .width, .height, .notAnAttribute:
+                    return 0.0
+                }
+            #else
+                switch layoutAttribute {
+                case .left, .right, .leading, .trailing, .centerX:
+                    return value.x
+                case .top, .bottom, .centerY, .lastBaseline, .firstBaseline:
+                    return value.y
+                case .width, .height, .notAnAttribute:
+                    return 0.0
+                }
+            #endif
+        }
+        
+        if let value = self as? ConstraintInsets {
+            #if os(iOS) || os(tvOS)
+                switch layoutAttribute {
+                case .left, .leftMargin, .centerX, .centerXWithinMargins:
+                    return value.left
+                case .top, .topMargin, .centerY, .centerYWithinMargins, .lastBaseline, .firstBaseline:
+                    return value.top
+                case .right, .rightMargin:
+                    return -value.right
+                case .bottom, .bottomMargin:
+                    return -value.bottom
+                case .leading, .leadingMargin:
+                    return (ConstraintConfig.interfaceLayoutDirection == .leftToRight) ? value.left : value.right
+                case .trailing, .trailingMargin:
+                    return (ConstraintConfig.interfaceLayoutDirection == .leftToRight) ? -value.right : -value.left
+                case .width:
+                    return -(value.left + value.right)
+                case .height:
+                    return -(value.top + value.bottom)
+                case .notAnAttribute:
+                    return 0.0
+                }
+            #else
+                switch layoutAttribute {
+                case .left, .centerX:
+                    return value.left
+                case .top, .centerY, .lastBaseline, .firstBaseline:
+                    return value.top
+                case .right:
+                    return -value.right
+                case .bottom:
+                    return -value.bottom
+                case .leading:
+                    return (ConstraintConfig.interfaceLayoutDirection == .leftToRight) ? value.left : value.right
+                case .trailing:
+                    return (ConstraintConfig.interfaceLayoutDirection == .leftToRight) ? -value.right : -value.left
+                case .width:
+                    return -(value.left + value.right)
+                case .height:
+                    return -(value.top + value.bottom)
+                case .notAnAttribute:
+                    return 0.0
+                }
+            #endif
+        }
+        
+        return 0.0
+    }
+    
+}

+ 185 - 0
Pods/SnapKit/Source/ConstraintDSL.swift

@@ -0,0 +1,185 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public protocol ConstraintDSL {
+    
+    var target: AnyObject? { get }
+    
+    func setLabel(_ value: String?)
+    func label() -> String?
+    
+}
+extension ConstraintDSL {
+    
+    public func setLabel(_ value: String?) {
+        objc_setAssociatedObject(self.target as Any, &labelKey, value, .OBJC_ASSOCIATION_COPY_NONATOMIC)
+    }
+    public func label() -> String? {
+        return objc_getAssociatedObject(self.target as Any, &labelKey) as? String
+    }
+    
+}
+private var labelKey: UInt8 = 0
+
+
+public protocol ConstraintBasicAttributesDSL : ConstraintDSL {
+}
+extension ConstraintBasicAttributesDSL {
+    
+    // MARK: Basics
+    
+    public var left: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.left)
+    }
+    
+    public var top: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.top)
+    }
+    
+    public var right: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.right)
+    }
+    
+    public var bottom: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.bottom)
+    }
+    
+    public var leading: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.leading)
+    }
+    
+    public var trailing: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.trailing)
+    }
+    
+    public var width: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.width)
+    }
+    
+    public var height: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.height)
+    }
+    
+    public var centerX: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.centerX)
+    }
+    
+    public var centerY: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.centerY)
+    }
+    
+    public var edges: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.edges)
+    }
+    
+    public var size: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.size)
+    }
+    
+    public var center: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.center)
+    }
+    
+}
+
+public protocol ConstraintAttributesDSL : ConstraintBasicAttributesDSL {
+}
+extension ConstraintAttributesDSL {
+    
+    // MARK: Baselines
+    
+    @available(*, deprecated:3.0, message:"Use .lastBaseline instead")
+    public var baseline: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.lastBaseline)
+    }
+    
+    @available(iOS 8.0, OSX 10.11, *)
+    public var lastBaseline: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.lastBaseline)
+    }
+    
+    @available(iOS 8.0, OSX 10.11, *)
+    public var firstBaseline: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.firstBaseline)
+    }
+    
+    // MARK: Margins
+    
+    @available(iOS 8.0, *)
+    public var leftMargin: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.leftMargin)
+    }
+    
+    @available(iOS 8.0, *)
+    public var topMargin: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.topMargin)
+    }
+    
+    @available(iOS 8.0, *)
+    public var rightMargin: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.rightMargin)
+    }
+    
+    @available(iOS 8.0, *)
+    public var bottomMargin: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.bottomMargin)
+    }
+    
+    @available(iOS 8.0, *)
+    public var leadingMargin: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.leadingMargin)
+    }
+    
+    @available(iOS 8.0, *)
+    public var trailingMargin: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.trailingMargin)
+    }
+    
+    @available(iOS 8.0, *)
+    public var centerXWithinMargins: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.centerXWithinMargins)
+    }
+    
+    @available(iOS 8.0, *)
+    public var centerYWithinMargins: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.centerYWithinMargins)
+    }
+    
+    @available(iOS 8.0, *)
+    public var margins: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.margins)
+    }
+    
+    @available(iOS 8.0, *)
+    public var centerWithinMargins: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.centerWithinMargins)
+    }
+    
+}

+ 69 - 0
Pods/SnapKit/Source/ConstraintDescription.swift

@@ -0,0 +1,69 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public class ConstraintDescription {
+    
+    internal let item: LayoutConstraintItem
+    internal var attributes: ConstraintAttributes
+    internal var relation: ConstraintRelation? = nil
+    internal var sourceLocation: (String, UInt)? = nil
+    internal var label: String? = nil
+    internal var related: ConstraintItem? = nil
+    internal var multiplier: ConstraintMultiplierTarget = 1.0
+    internal var constant: ConstraintConstantTarget = 0.0
+    internal var priority: ConstraintPriorityTarget = 1000.0
+    internal lazy var constraint: Constraint? = {
+        guard let relation = self.relation,
+              let related = self.related,
+              let sourceLocation = self.sourceLocation else {
+            return nil
+        }
+        let from = ConstraintItem(target: self.item, attributes: self.attributes)
+        
+        return Constraint(
+            from: from,
+            to: related,
+            relation: relation,
+            sourceLocation: sourceLocation,
+            label: self.label,
+            multiplier: self.multiplier,
+            constant: self.constant,
+            priority: self.priority
+        )
+    }()
+    
+    // MARK: Initialization
+    
+    internal init(item: LayoutConstraintItem, attributes: ConstraintAttributes) {
+        self.item = item
+        self.attributes = attributes
+    }
+    
+}

+ 72 - 0
Pods/SnapKit/Source/ConstraintInsetTarget.swift

@@ -0,0 +1,72 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public protocol ConstraintInsetTarget: ConstraintConstantTarget {
+}
+
+extension Int: ConstraintInsetTarget {
+}
+
+extension UInt: ConstraintInsetTarget {
+}
+
+extension Float: ConstraintInsetTarget {
+}
+
+extension Double: ConstraintInsetTarget {
+}
+
+extension CGFloat: ConstraintInsetTarget {
+}
+
+extension ConstraintInsets: ConstraintInsetTarget {
+}
+
+extension ConstraintInsetTarget {
+
+    internal var constraintInsetTargetValue: ConstraintInsets {
+        if let amount = self as? ConstraintInsets {
+            return amount
+        } else if let amount = self as? Float {
+            return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount))
+        } else if let amount = self as? Double {
+            return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount))
+        } else if let amount = self as? CGFloat {
+            return ConstraintInsets(top: amount, left: amount, bottom: amount, right: amount)
+        } else if let amount = self as? Int {
+            return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount))
+        } else if let amount = self as? UInt {
+            return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount))
+        } else {
+            return ConstraintInsets(top: 0, left: 0, bottom: 0, right: 0)
+        }
+    }
+    
+}

+ 35 - 0
Pods/SnapKit/Source/ConstraintInsets.swift

@@ -0,0 +1,35 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+#if os(iOS) || os(tvOS)
+    public typealias ConstraintInsets = UIEdgeInsets
+#else
+    public typealias ConstraintInsets = NSEdgeInsets
+#endif

+ 61 - 0
Pods/SnapKit/Source/ConstraintItem.swift

@@ -0,0 +1,61 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public final class ConstraintItem {
+    
+    internal weak var target: AnyObject?
+    internal let attributes: ConstraintAttributes
+    
+    internal init(target: AnyObject?, attributes: ConstraintAttributes) {
+        self.target = target
+        self.attributes = attributes
+    }
+    
+    internal var layoutConstraintItem: LayoutConstraintItem? {
+        return self.target as? LayoutConstraintItem
+    }
+    
+}
+
+public func ==(lhs: ConstraintItem, rhs: ConstraintItem) -> Bool {
+    // pointer equality
+    guard lhs !== rhs else {
+        return true
+    }
+    
+    // must both have valid targets and identical attributes
+    guard let target1 = lhs.target,
+          let target2 = rhs.target,
+          target1 === target2 && lhs.attributes == rhs.attributes else {
+            return false
+    }
+    
+    return true
+}

+ 36 - 0
Pods/SnapKit/Source/ConstraintLayoutGuide+Extensions.swift

@@ -0,0 +1,36 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#endif
+    
+    
+@available(iOS 9.0, OSX 10.11, *)
+public extension ConstraintLayoutGuide {
+    
+    public var snp: ConstraintLayoutGuideDSL {
+        return ConstraintLayoutGuideDSL(guide: self)
+    }
+    
+}

+ 37 - 0
Pods/SnapKit/Source/ConstraintLayoutGuide.swift

@@ -0,0 +1,37 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+#if os(iOS) || os(tvOS)
+    @available(iOS 9.0, *)
+    public typealias ConstraintLayoutGuide = UILayoutGuide
+#else
+    @available(OSX 10.11, *)
+    public typealias ConstraintLayoutGuide = NSLayoutGuide
+#endif

+ 66 - 0
Pods/SnapKit/Source/ConstraintLayoutGuideDSL.swift

@@ -0,0 +1,66 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+@available(iOS 9.0, OSX 10.11, *)
+public struct ConstraintLayoutGuideDSL: ConstraintAttributesDSL {
+    
+    @discardableResult
+    public func prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
+        return ConstraintMaker.prepareConstraints(item: self.guide, closure: closure)
+    }
+    
+    public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
+        ConstraintMaker.makeConstraints(item: self.guide, closure: closure)
+    }
+    
+    public func remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
+        ConstraintMaker.remakeConstraints(item: self.guide, closure: closure)
+    }
+    
+    public func updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
+        ConstraintMaker.updateConstraints(item: self.guide, closure: closure)
+    }
+    
+    public func removeConstraints() {
+        ConstraintMaker.removeConstraints(item: self.guide)
+    }
+    
+    public var target: AnyObject? {
+        return self.guide
+    }
+    
+    internal let guide: ConstraintLayoutGuide
+    
+    internal init(guide: ConstraintLayoutGuide) {
+        self.guide = guide
+        
+    }
+    
+}

+ 36 - 0
Pods/SnapKit/Source/ConstraintLayoutSupport.swift

@@ -0,0 +1,36 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+#if os(iOS) || os(tvOS)
+    @available(iOS 8.0, *)
+    public typealias ConstraintLayoutSupport = UILayoutSupport
+#else
+    public class ConstraintLayoutSupport {}
+#endif

+ 56 - 0
Pods/SnapKit/Source/ConstraintLayoutSupportDSL.swift

@@ -0,0 +1,56 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+@available(iOS 8.0, *)
+public struct ConstraintLayoutSupportDSL: ConstraintDSL {
+    
+    public var target: AnyObject? {
+        return self.support
+    }
+    
+    internal let support: ConstraintLayoutSupport
+    
+    internal init(support: ConstraintLayoutSupport) {
+        self.support = support
+        
+    }
+    
+    public var top: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.top)
+    }
+    
+    public var bottom: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.bottom)
+    }
+    
+    public var height: ConstraintItem {
+        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.height)
+    }
+}

+ 204 - 0
Pods/SnapKit/Source/ConstraintMaker.swift

@@ -0,0 +1,204 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+public class ConstraintMaker {
+    
+    public var left: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.left)
+    }
+    
+    public var top: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.top)
+    }
+    
+    public var bottom: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.bottom)
+    }
+    
+    public var right: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.right)
+    }
+    
+    public var leading: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.leading)
+    }
+    
+    public var trailing: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.trailing)
+    }
+    
+    public var width: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.width)
+    }
+    
+    public var height: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.height)
+    }
+    
+    public var centerX: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.centerX)
+    }
+    
+    public var centerY: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.centerY)
+    }
+    
+    @available(*, deprecated:3.0, message:"Use lastBaseline instead")
+    public var baseline: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.lastBaseline)
+    }
+    
+    public var lastBaseline: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.lastBaseline)
+    }
+    
+    @available(iOS 8.0, OSX 10.11, *)
+    public var firstBaseline: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.firstBaseline)
+    }
+    
+    @available(iOS 8.0, *)
+    public var leftMargin: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.leftMargin)
+    }
+    
+    @available(iOS 8.0, *)
+    public var rightMargin: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.rightMargin)
+    }
+    
+    @available(iOS 8.0, *)
+    public var topMargin: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.topMargin)
+    }
+    
+    @available(iOS 8.0, *)
+    public var bottomMargin: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.bottomMargin)
+    }
+    
+    @available(iOS 8.0, *)
+    public var leadingMargin: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.leadingMargin)
+    }
+    
+    @available(iOS 8.0, *)
+    public var trailingMargin: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.trailingMargin)
+    }
+    
+    @available(iOS 8.0, *)
+    public var centerXWithinMargins: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.centerXWithinMargins)
+    }
+    
+    @available(iOS 8.0, *)
+    public var centerYWithinMargins: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.centerYWithinMargins)
+    }
+    
+    public var edges: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.edges)
+    }
+    public var size: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.size)
+    }
+    public var center: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.center)
+    }
+    
+    @available(iOS 8.0, *)
+    public var margins: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.margins)
+    }
+    
+    @available(iOS 8.0, *)
+    public var centerWithinMargins: ConstraintMakerExtendable {
+        return self.makeExtendableWithAttributes(.centerWithinMargins)
+    }
+    
+    private let item: LayoutConstraintItem
+    private var descriptions = [ConstraintDescription]()
+    
+    internal init(item: LayoutConstraintItem) {
+        self.item = item
+        self.item.prepare()
+    }
+    
+    internal func makeExtendableWithAttributes(_ attributes: ConstraintAttributes) -> ConstraintMakerExtendable {
+        let description = ConstraintDescription(item: self.item, attributes: attributes)
+        self.descriptions.append(description)
+        return ConstraintMakerExtendable(description)
+    }
+    
+    internal static func prepareConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
+        let maker = ConstraintMaker(item: item)
+        closure(maker)
+        var constraints: [Constraint] = []
+        for description in maker.descriptions {
+            guard let constraint = description.constraint else {
+                continue
+            }
+            constraints.append(constraint)
+        }
+        return constraints
+    }
+    
+    internal static func makeConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {
+        let constraints = prepareConstraints(item: item, closure: closure)
+        for constraint in constraints {
+            constraint.activateIfNeeded(updatingExisting: false)
+        }
+    }
+    
+    internal static func remakeConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {
+        self.removeConstraints(item: item)
+        self.makeConstraints(item: item, closure: closure)
+    }
+    
+    internal static func updateConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {
+        guard item.constraints.count > 0 else {
+            self.makeConstraints(item: item, closure: closure)
+            return
+        }
+        
+        let constraints = prepareConstraints(item: item, closure: closure)
+        for constraint in constraints {
+            constraint.activateIfNeeded(updatingExisting: true)
+        }
+    }
+    
+    internal static func removeConstraints(item: LayoutConstraintItem) {
+        let constraints = item.constraints
+        for constraint in constraints {
+            constraint.deactivateIfNeeded()
+        }
+    }
+    
+}

+ 56 - 0
Pods/SnapKit/Source/ConstraintMakerEditable.swift

@@ -0,0 +1,56 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public class ConstraintMakerEditable: ConstraintMakerPriortizable {
+
+    @discardableResult
+    public func multipliedBy(_ amount: ConstraintMultiplierTarget) -> ConstraintMakerEditable {
+        self.description.multiplier = amount
+        return self
+    }
+    
+    @discardableResult
+    public func dividedBy(_ amount: ConstraintMultiplierTarget) -> ConstraintMakerEditable {
+        return self.multipliedBy(1.0 / amount.constraintMultiplierTargetValue)
+    }
+    
+    @discardableResult
+    public func offset(_ amount: ConstraintOffsetTarget) -> ConstraintMakerEditable {
+        self.description.constant = amount.constraintOffsetTargetValue
+        return self
+    }
+    
+    @discardableResult
+    public func inset(_ amount: ConstraintInsetTarget) -> ConstraintMakerEditable {
+        self.description.constant = amount.constraintInsetTargetValue
+        return self
+    }
+    
+}

+ 169 - 0
Pods/SnapKit/Source/ConstraintMakerExtendable.swift

@@ -0,0 +1,169 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public class ConstraintMakerExtendable: ConstraintMakerRelatable {
+    
+    public var left: ConstraintMakerExtendable {
+        self.description.attributes += .left
+        return self
+    }
+    
+    public var top: ConstraintMakerExtendable {
+        self.description.attributes += .top
+        return self
+    }
+    
+    public var bottom: ConstraintMakerExtendable {
+        self.description.attributes += .bottom
+        return self
+    }
+    
+    public var right: ConstraintMakerExtendable {
+        self.description.attributes += .right
+        return self
+    }
+    
+    public var leading: ConstraintMakerExtendable {
+        self.description.attributes += .leading
+        return self
+    }
+    
+    public var trailing: ConstraintMakerExtendable {
+        self.description.attributes += .trailing
+        return self
+    }
+    
+    public var width: ConstraintMakerExtendable {
+        self.description.attributes += .width
+        return self
+    }
+    
+    public var height: ConstraintMakerExtendable {
+        self.description.attributes += .height
+        return self
+    }
+    
+    public var centerX: ConstraintMakerExtendable {
+        self.description.attributes += .centerX
+        return self
+    }
+    
+    public var centerY: ConstraintMakerExtendable {
+        self.description.attributes += .centerY
+        return self
+    }
+    
+    @available(*, deprecated:3.0, message:"Use lastBaseline instead")
+    public var baseline: ConstraintMakerExtendable {
+        self.description.attributes += .lastBaseline
+        return self
+    }
+    
+    public var lastBaseline: ConstraintMakerExtendable {
+        self.description.attributes += .lastBaseline
+        return self
+    }
+    
+    @available(iOS 8.0, OSX 10.11, *)
+    public var firstBaseline: ConstraintMakerExtendable {
+        self.description.attributes += .firstBaseline
+        return self
+    }
+    
+    @available(iOS 8.0, *)
+    public var leftMargin: ConstraintMakerExtendable {
+        self.description.attributes += .leftMargin
+        return self
+    }
+    
+    @available(iOS 8.0, *)
+    public var rightMargin: ConstraintMakerExtendable {
+        self.description.attributes += .rightMargin
+        return self
+    }
+    
+    @available(iOS 8.0, *)
+    public var topMargin: ConstraintMakerExtendable {
+        self.description.attributes += .topMargin
+        return self
+    }
+    
+    @available(iOS 8.0, *)
+    public var bottomMargin: ConstraintMakerExtendable {
+        self.description.attributes += .bottomMargin
+        return self
+    }
+    
+    @available(iOS 8.0, *)
+    public var leadingMargin: ConstraintMakerExtendable {
+        self.description.attributes += .leadingMargin
+        return self
+    }
+    
+    @available(iOS 8.0, *)
+    public var trailingMargin: ConstraintMakerExtendable {
+        self.description.attributes += .trailingMargin
+        return self
+    }
+    
+    @available(iOS 8.0, *)
+    public var centerXWithinMargins: ConstraintMakerExtendable {
+        self.description.attributes += .centerXWithinMargins
+        return self
+    }
+    
+    @available(iOS 8.0, *)
+    public var centerYWithinMargins: ConstraintMakerExtendable {
+        self.description.attributes += .centerYWithinMargins
+        return self
+    }
+    
+    public var edges: ConstraintMakerExtendable {
+        self.description.attributes += .edges
+        return self
+    }
+    public var size: ConstraintMakerExtendable {
+        self.description.attributes += .size
+        return self
+    }
+    
+    @available(iOS 8.0, *)
+    public var margins: ConstraintMakerExtendable {
+        self.description.attributes += .margins
+        return self
+    }
+    
+    @available(iOS 8.0, *)
+    public var centerWithinMargins: ConstraintMakerExtendable {
+        self.description.attributes += .centerWithinMargins
+        return self
+    }
+    
+}

+ 49 - 0
Pods/SnapKit/Source/ConstraintMakerFinalizable.swift

@@ -0,0 +1,49 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public class ConstraintMakerFinalizable {
+    
+    internal let description: ConstraintDescription
+    
+    internal init(_ description: ConstraintDescription) {
+        self.description = description
+    }
+    
+    @discardableResult
+    public func labeled(_ label: String) -> ConstraintMakerFinalizable {
+        self.description.label = label
+        return self
+    }
+    
+    public var constraint: Constraint {
+        return self.description.constraint!
+    }
+    
+}

+ 68 - 0
Pods/SnapKit/Source/ConstraintMakerPriortizable.swift

@@ -0,0 +1,68 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public class ConstraintMakerPriortizable: ConstraintMakerFinalizable {
+    
+    @discardableResult
+    public func priority(_ amount: ConstraintPriority) -> ConstraintMakerFinalizable {
+        self.description.priority = amount.value
+        return self
+    }
+    
+    @discardableResult
+    public func priority(_ amount: ConstraintPriorityTarget) -> ConstraintMakerFinalizable {
+        self.description.priority = amount
+        return self
+    }
+    
+    @available(*, deprecated:3.0, message:"Use priority(.required) instead.")
+    @discardableResult
+    public func priorityRequired() -> ConstraintMakerFinalizable {
+        return self.priority(.required)
+    }
+    
+    @available(*, deprecated:3.0, message:"Use priority(.high) instead.")
+    @discardableResult
+    public func priorityHigh() -> ConstraintMakerFinalizable {
+        return self.priority(.high)
+    }
+    
+    @available(*, deprecated:3.0, message:"Use priority(.medium) instead.")
+    @discardableResult
+    public func priorityMedium() -> ConstraintMakerFinalizable {
+        return self.priority(.medium)
+    }
+    
+    @available(*, deprecated:3.0, message:"Use priority(.low) instead.")
+    @discardableResult
+    public func priorityLow() -> ConstraintMakerFinalizable {
+        return self.priority(.low)
+    }
+}

+ 113 - 0
Pods/SnapKit/Source/ConstraintMakerRelatable.swift

@@ -0,0 +1,113 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public class ConstraintMakerRelatable {
+    
+    internal let description: ConstraintDescription
+    
+    internal init(_ description: ConstraintDescription) {
+        self.description = description
+    }
+    
+    internal func relatedTo(_ other: ConstraintRelatableTarget, relation: ConstraintRelation, file: String, line: UInt) -> ConstraintMakerEditable {
+        let related: ConstraintItem
+        let constant: ConstraintConstantTarget
+        
+        if let other = other as? ConstraintItem {
+            guard other.attributes == ConstraintAttributes.none ||
+                  other.attributes.layoutAttributes.count <= 1 ||
+                  other.attributes.layoutAttributes == self.description.attributes.layoutAttributes ||
+                  other.attributes == .edges && self.description.attributes == .margins ||
+                  other.attributes == .margins && self.description.attributes == .edges else {
+                fatalError("Cannot constraint to multiple non identical attributes. (\(file), \(line))");
+            }
+            
+            related = other
+            constant = 0.0
+        } else if let other = other as? ConstraintView {
+            related = ConstraintItem(target: other, attributes: ConstraintAttributes.none)
+            constant = 0.0
+        } else if let other = other as? ConstraintConstantTarget {
+            related = ConstraintItem(target: nil, attributes: ConstraintAttributes.none)
+            constant = other
+        } else if #available(iOS 9.0, OSX 10.11, *), let other = other as? ConstraintLayoutGuide {
+            related = ConstraintItem(target: other, attributes: ConstraintAttributes.none)
+            constant = 0.0
+        } else {
+            fatalError("Invalid constraint. (\(file), \(line))")
+        }
+        
+        let editable = ConstraintMakerEditable(self.description)
+        editable.description.sourceLocation = (file, line)
+        editable.description.relation = relation
+        editable.description.related = related
+        editable.description.constant = constant
+        return editable
+    }
+    
+    @discardableResult
+    public func equalTo(_ other: ConstraintRelatableTarget, _ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
+        return self.relatedTo(other, relation: .equal, file: file, line: line)
+    }
+    
+    @discardableResult
+    public func equalToSuperview(_ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
+        guard let other = self.description.item.superview else {
+            fatalError("Expected superview but found nil when attempting make constraint `equalToSuperview`.")
+        }
+        return self.relatedTo(other, relation: .equal, file: file, line: line)
+    }
+    
+    @discardableResult
+    public func lessThanOrEqualTo(_ other: ConstraintRelatableTarget, _ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
+        return self.relatedTo(other, relation: .lessThanOrEqual, file: file, line: line)
+    }
+    
+    @discardableResult
+    public func lessThanOrEqualToSuperview(_ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
+        guard let other = self.description.item.superview else {
+            fatalError("Expected superview but found nil when attempting make constraint `lessThanOrEqualToSuperview`.")
+        }
+        return self.relatedTo(other, relation: .lessThanOrEqual, file: file, line: line)
+    }
+    
+    @discardableResult
+    public func greaterThanOrEqualTo(_ other: ConstraintRelatableTarget, _ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable {
+        return self.relatedTo(other, relation: .greaterThanOrEqual, file: file, line: line)
+    }
+    
+    @discardableResult
+    public func greaterThanOrEqualToSuperview(_ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable {
+        guard let other = self.description.item.superview else {
+            fatalError("Expected superview but found nil when attempting make constraint `greaterThanOrEqualToSuperview`.")
+        }
+        return self.relatedTo(other, relation: .greaterThanOrEqual, file: file, line: line)
+    }
+}

+ 75 - 0
Pods/SnapKit/Source/ConstraintMultiplierTarget.swift

@@ -0,0 +1,75 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public protocol ConstraintMultiplierTarget {
+    
+    var constraintMultiplierTargetValue: CGFloat { get }
+    
+}
+
+extension Int: ConstraintMultiplierTarget {
+    
+    public var constraintMultiplierTargetValue: CGFloat {
+        return CGFloat(self)
+    }
+    
+}
+
+extension UInt: ConstraintMultiplierTarget {
+    
+    public var constraintMultiplierTargetValue: CGFloat {
+        return CGFloat(self)
+    }
+    
+}
+
+extension Float: ConstraintMultiplierTarget {
+    
+    public var constraintMultiplierTargetValue: CGFloat {
+        return CGFloat(self)
+    }
+    
+}
+
+extension Double: ConstraintMultiplierTarget {
+    
+    public var constraintMultiplierTargetValue: CGFloat {
+        return CGFloat(self)
+    }
+    
+}
+
+extension CGFloat: ConstraintMultiplierTarget {
+    
+    public var constraintMultiplierTargetValue: CGFloat {
+        return self
+    }
+    
+}

+ 69 - 0
Pods/SnapKit/Source/ConstraintOffsetTarget.swift

@@ -0,0 +1,69 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public protocol ConstraintOffsetTarget: ConstraintConstantTarget {
+}
+
+extension Int: ConstraintOffsetTarget {
+}
+
+extension UInt: ConstraintOffsetTarget {
+}
+
+extension Float: ConstraintOffsetTarget {
+}
+
+extension Double: ConstraintOffsetTarget {
+}
+
+extension CGFloat: ConstraintOffsetTarget {
+}
+
+extension ConstraintOffsetTarget {
+    
+    internal var constraintOffsetTargetValue: CGFloat {
+        let offset: CGFloat
+        if let amount = self as? Float {
+            offset = CGFloat(amount)
+        } else if let amount = self as? Double {
+            offset = CGFloat(amount)
+        } else if let amount = self as? CGFloat {
+            offset = CGFloat(amount)
+        } else if let amount = self as? Int {
+            offset = CGFloat(amount)
+        } else if let amount = self as? UInt {
+            offset = CGFloat(amount)
+        } else {
+            offset = 0.0
+        }
+        return offset
+    }
+    
+}

+ 77 - 0
Pods/SnapKit/Source/ConstraintPriority.swift

@@ -0,0 +1,77 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+public struct ConstraintPriority : ExpressibleByFloatLiteral, Equatable, Strideable {
+    public typealias FloatLiteralType = Float
+    
+    public let value: Float
+    
+    public init(floatLiteral value: Float) {
+        self.value = value
+    }
+    
+    public init(_ value: Float) {
+        self.value = value
+    }
+    
+    public static var required: ConstraintPriority {
+        return 1000.0
+    }
+    
+    public static var high: ConstraintPriority {
+        return 750.0
+    }
+    
+    public static var medium: ConstraintPriority {
+        #if os(OSX)
+            return 501.0
+        #else
+            return 500.0
+        #endif
+        
+    }
+    
+    public static var low: ConstraintPriority {
+        return 250.0
+    }
+    
+    public static func ==(lhs: ConstraintPriority, rhs: ConstraintPriority) -> Bool {
+        return lhs.value == rhs.value
+    }
+
+    // MARK: Strideable
+
+    public func advanced(by n: FloatLiteralType) -> ConstraintPriority {
+        return ConstraintPriority(floatLiteral: value + n)
+    }
+
+    public func distance(to other: ConstraintPriority) -> FloatLiteralType {
+        return other.value - value
+    }
+}

+ 85 - 0
Pods/SnapKit/Source/ConstraintPriorityTarget.swift

@@ -0,0 +1,85 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public protocol ConstraintPriorityTarget {
+    
+    var constraintPriorityTargetValue: Float { get }
+    
+}
+
+extension Int: ConstraintPriorityTarget {
+    
+    public var constraintPriorityTargetValue: Float {
+        return Float(self)
+    }
+    
+}
+
+extension UInt: ConstraintPriorityTarget {
+    
+    public var constraintPriorityTargetValue: Float {
+        return Float(self)
+    }
+    
+}
+
+extension Float: ConstraintPriorityTarget {
+    
+    public var constraintPriorityTargetValue: Float {
+        return self
+    }
+    
+}
+
+extension Double: ConstraintPriorityTarget {
+    
+    public var constraintPriorityTargetValue: Float {
+        return Float(self)
+    }
+    
+}
+
+extension CGFloat: ConstraintPriorityTarget {
+    
+    public var constraintPriorityTargetValue: Float {
+        return Float(self)
+    }
+    
+}
+
+#if os(iOS) || os(tvOS)
+extension UILayoutPriority: ConstraintPriorityTarget {
+
+    public var constraintPriorityTargetValue: Float {
+        return self.rawValue
+    }
+
+}
+#endif

+ 66 - 0
Pods/SnapKit/Source/ConstraintRelatableTarget.swift

@@ -0,0 +1,66 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public protocol ConstraintRelatableTarget {
+}
+
+extension Int: ConstraintRelatableTarget {
+}
+
+extension UInt: ConstraintRelatableTarget {
+}
+
+extension Float: ConstraintRelatableTarget {
+}
+
+extension Double: ConstraintRelatableTarget {
+}
+
+extension CGFloat: ConstraintRelatableTarget {
+}
+
+extension CGSize: ConstraintRelatableTarget {
+}
+
+extension CGPoint: ConstraintRelatableTarget {
+}
+
+extension ConstraintInsets: ConstraintRelatableTarget {
+}
+
+extension ConstraintItem: ConstraintRelatableTarget {
+}
+
+extension ConstraintView: ConstraintRelatableTarget {
+}
+
+@available(iOS 9.0, OSX 10.11, *)
+extension ConstraintLayoutGuide: ConstraintRelatableTarget {
+}

+ 48 - 0
Pods/SnapKit/Source/ConstraintRelation.swift

@@ -0,0 +1,48 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+internal enum ConstraintRelation : Int {
+    case equal = 1
+    case lessThanOrEqual
+    case greaterThanOrEqual
+    
+    internal var layoutRelation: LayoutRelation {
+        get {
+            switch(self) {
+            case .equal:
+                return .equal
+            case .lessThanOrEqual:
+                return .lessThanOrEqual
+            case .greaterThanOrEqual:
+                return .greaterThanOrEqual
+            }
+        }
+    }
+}

+ 152 - 0
Pods/SnapKit/Source/ConstraintView+Extensions.swift

@@ -0,0 +1,152 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public extension ConstraintView {
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public var snp_left: ConstraintItem { return self.snp.left }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public var snp_top: ConstraintItem { return self.snp.top }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public var snp_right: ConstraintItem { return self.snp.right }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public var snp_bottom: ConstraintItem { return self.snp.bottom }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public var snp_leading: ConstraintItem { return self.snp.leading }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public var snp_trailing: ConstraintItem { return self.snp.trailing }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public var snp_width: ConstraintItem { return self.snp.width }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public var snp_height: ConstraintItem { return self.snp.height }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public var snp_centerX: ConstraintItem { return self.snp.centerX }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public var snp_centerY: ConstraintItem { return self.snp.centerY }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public var snp_baseline: ConstraintItem { return self.snp.baseline }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    @available(iOS 8.0, OSX 10.11, *)
+    public var snp_lastBaseline: ConstraintItem { return self.snp.lastBaseline }
+    
+    @available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
+    @available(iOS 8.0, OSX 10.11, *)
+    public var snp_firstBaseline: ConstraintItem { return self.snp.firstBaseline }
+    
+    @available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
+    @available(iOS 8.0, *)
+    public var snp_leftMargin: ConstraintItem { return self.snp.leftMargin }
+    
+    @available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
+    @available(iOS 8.0, *)
+    public var snp_topMargin: ConstraintItem { return self.snp.topMargin }
+    
+    @available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
+    @available(iOS 8.0, *)
+    public var snp_rightMargin: ConstraintItem { return self.snp.rightMargin }
+    
+    @available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
+    @available(iOS 8.0, *)
+    public var snp_bottomMargin: ConstraintItem { return self.snp.bottomMargin }
+    
+    @available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
+    @available(iOS 8.0, *)
+    public var snp_leadingMargin: ConstraintItem { return self.snp.leadingMargin }
+    
+    @available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
+    @available(iOS 8.0, *)
+    public var snp_trailingMargin: ConstraintItem { return self.snp.trailingMargin }
+    
+    @available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
+    @available(iOS 8.0, *)
+    public var snp_centerXWithinMargins: ConstraintItem { return self.snp.centerXWithinMargins }
+    
+    @available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
+    @available(iOS 8.0, *)
+    public var snp_centerYWithinMargins: ConstraintItem { return self.snp.centerYWithinMargins }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public var snp_edges: ConstraintItem { return self.snp.edges }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public var snp_size: ConstraintItem { return self.snp.size }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public var snp_center: ConstraintItem { return self.snp.center }
+    
+    @available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
+    @available(iOS 8.0, *)
+    public var snp_margins: ConstraintItem { return self.snp.margins }
+    
+    @available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
+    @available(iOS 8.0, *)
+    public var snp_centerWithinMargins: ConstraintItem { return self.snp.centerWithinMargins }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public func snp_prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
+        return self.snp.prepareConstraints(closure)
+    }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public func snp_makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
+        self.snp.makeConstraints(closure)
+    }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public func snp_remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
+        self.snp.remakeConstraints(closure)
+    }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public func snp_updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
+        self.snp.updateConstraints(closure)
+    }
+    
+    @available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
+    public func snp_removeConstraints() {
+        self.snp.removeConstraints()
+    }
+    
+    public var snp: ConstraintViewDSL {
+        return ConstraintViewDSL(view: self)
+    }
+    
+}

+ 35 - 0
Pods/SnapKit/Source/ConstraintView.swift

@@ -0,0 +1,35 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+#if os(iOS) || os(tvOS)
+    public typealias ConstraintView = UIView
+#else
+    public typealias ConstraintView = NSView
+#endif

+ 101 - 0
Pods/SnapKit/Source/ConstraintViewDSL.swift

@@ -0,0 +1,101 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public struct ConstraintViewDSL: ConstraintAttributesDSL {
+    
+    @discardableResult
+    public func prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
+        return ConstraintMaker.prepareConstraints(item: self.view, closure: closure)
+    }
+    
+    public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
+        ConstraintMaker.makeConstraints(item: self.view, closure: closure)
+    }
+    
+    public func remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
+        ConstraintMaker.remakeConstraints(item: self.view, closure: closure)
+    }
+    
+    public func updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
+        ConstraintMaker.updateConstraints(item: self.view, closure: closure)
+    }
+    
+    public func removeConstraints() {
+        ConstraintMaker.removeConstraints(item: self.view)
+    }
+    
+    public var contentHuggingHorizontalPriority: Float {
+        get {
+            return self.view.contentHuggingPriority(for: .horizontal).rawValue
+        }
+        set {
+            self.view.setContentHuggingPriority(LayoutPriority(rawValue: newValue), for: .horizontal)
+        }
+    }
+    
+    public var contentHuggingVerticalPriority: Float {
+        get {
+            return self.view.contentHuggingPriority(for: .vertical).rawValue
+        }
+        set {
+            self.view.setContentHuggingPriority(LayoutPriority(rawValue: newValue), for: .vertical)
+        }
+    }
+    
+    public var contentCompressionResistanceHorizontalPriority: Float {
+        get {
+            return self.view.contentCompressionResistancePriority(for: .horizontal).rawValue
+        }
+        set {
+            self.view.setContentCompressionResistancePriority(LayoutPriority(rawValue: newValue), for: .horizontal)
+        }
+    }
+    
+    public var contentCompressionResistanceVerticalPriority: Float {
+        get {
+            return self.view.contentCompressionResistancePriority(for: .vertical).rawValue
+        }
+        set {
+            self.view.setContentCompressionResistancePriority(LayoutPriority(rawValue: newValue), for: .vertical)
+        }
+    }
+    
+    public var target: AnyObject? {
+        return self.view
+    }
+    
+    internal let view: ConstraintView
+    
+    internal init(view: ConstraintView) {
+        self.view = view
+        
+    }
+    
+}

+ 160 - 0
Pods/SnapKit/Source/Debugging.swift

@@ -0,0 +1,160 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+public extension LayoutConstraint {
+    
+    override public var description: String {
+        var description = "<"
+        
+        description += descriptionForObject(self)
+        
+        if let firstItem = conditionalOptional(from: self.firstItem) {
+            description += " \(descriptionForObject(firstItem))"
+        }
+        
+        if self.firstAttribute != .notAnAttribute {
+            description += ".\(descriptionForAttribute(self.firstAttribute))"
+        }
+        
+        description += " \(descriptionForRelation(self.relation))"
+        
+        if let secondItem = self.secondItem {
+            description += " \(descriptionForObject(secondItem))"
+        }
+        
+        if self.secondAttribute != .notAnAttribute {
+            description += ".\(descriptionForAttribute(self.secondAttribute))"
+        }
+        
+        if self.multiplier != 1.0 {
+            description += " * \(self.multiplier)"
+        }
+        
+        if self.secondAttribute == .notAnAttribute {
+            description += " \(self.constant)"
+        } else {
+            if self.constant > 0.0 {
+                description += " + \(self.constant)"
+            } else if self.constant < 0.0 {
+                description += " - \(abs(self.constant))"
+            }
+        }
+        
+        if self.priority.rawValue != 1000.0 {
+            description += " ^\(self.priority)"
+        }
+        
+        description += ">"
+        
+        return description
+    }
+    
+}
+
+private func descriptionForRelation(_ relation: LayoutRelation) -> String {
+    switch relation {
+    case .equal:                return "=="
+    case .greaterThanOrEqual:   return ">="
+    case .lessThanOrEqual:      return "<="
+    }
+}
+
+private func descriptionForAttribute(_ attribute: LayoutAttribute) -> String {
+    #if os(iOS) || os(tvOS)
+        switch attribute {
+        case .notAnAttribute:       return "notAnAttribute"
+        case .top:                  return "top"
+        case .left:                 return "left"
+        case .bottom:               return "bottom"
+        case .right:                return "right"
+        case .leading:              return "leading"
+        case .trailing:             return "trailing"
+        case .width:                return "width"
+        case .height:               return "height"
+        case .centerX:              return "centerX"
+        case .centerY:              return "centerY"
+        case .lastBaseline:         return "lastBaseline"
+        case .firstBaseline:        return "firstBaseline"
+        case .topMargin:            return "topMargin"
+        case .leftMargin:           return "leftMargin"
+        case .bottomMargin:         return "bottomMargin"
+        case .rightMargin:          return "rightMargin"
+        case .leadingMargin:        return "leadingMargin"
+        case .trailingMargin:       return "trailingMargin"
+        case .centerXWithinMargins: return "centerXWithinMargins"
+        case .centerYWithinMargins: return "centerYWithinMargins"
+        }
+    #else
+        switch attribute {
+        case .notAnAttribute:       return "notAnAttribute"
+        case .top:                  return "top"
+        case .left:                 return "left"
+        case .bottom:               return "bottom"
+        case .right:                return "right"
+        case .leading:              return "leading"
+        case .trailing:             return "trailing"
+        case .width:                return "width"
+        case .height:               return "height"
+        case .centerX:              return "centerX"
+        case .centerY:              return "centerY"
+        case .lastBaseline:         return "lastBaseline"
+        case .firstBaseline:        return "firstBaseline"
+        }
+    #endif
+}
+
+private func conditionalOptional<T>(from object: Optional<T>) -> Optional<T> {
+    return object
+}
+
+private func conditionalOptional<T>(from object: T) -> Optional<T> {
+    return Optional.some(object)
+}
+
+private func descriptionForObject(_ object: AnyObject) -> String {
+    let pointerDescription = String(format: "%p", UInt(bitPattern: ObjectIdentifier(object)))
+    var desc = ""
+    
+    desc += type(of: object).description()
+    
+    if let object = object as? ConstraintView {
+        desc += ":\(object.snp.label() ?? pointerDescription)"
+    } else if let object = object as? LayoutConstraint {
+        desc += ":\(object.label ?? pointerDescription)"
+    } else {
+        desc += ":\(pointerDescription)"
+    }
+    
+    if let object = object as? LayoutConstraint, let file = object.constraint?.sourceLocation.0, let line = object.constraint?.sourceLocation.1 {
+        desc += "@\((file as NSString).lastPathComponent)#\(line)"
+    }
+    
+    desc += ""
+    return desc
+}

+ 57 - 0
Pods/SnapKit/Source/LayoutConstraint.swift

@@ -0,0 +1,57 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public class LayoutConstraint : NSLayoutConstraint {
+    
+    public var label: String? {
+        get {
+            return self.identifier
+        }
+        set {
+            self.identifier = newValue
+        }
+    }
+    
+    internal weak var constraint: Constraint? = nil
+    
+}
+
+internal func ==(lhs: LayoutConstraint, rhs: LayoutConstraint) -> Bool {
+    guard lhs.firstItem === rhs.firstItem &&
+          lhs.secondItem === rhs.secondItem &&
+          lhs.firstAttribute == rhs.firstAttribute &&
+          lhs.secondAttribute == rhs.secondAttribute &&
+          lhs.relation == rhs.relation &&
+          lhs.priority == rhs.priority &&
+          lhs.multiplier == rhs.multiplier else {
+        return false
+    }
+    return true
+}

+ 93 - 0
Pods/SnapKit/Source/LayoutConstraintItem.swift

@@ -0,0 +1,93 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#else
+    import AppKit
+#endif
+
+
+public protocol LayoutConstraintItem: class {
+}
+
+@available(iOS 9.0, OSX 10.11, *)
+extension ConstraintLayoutGuide : LayoutConstraintItem {
+}
+
+extension ConstraintView : LayoutConstraintItem {
+}
+
+
+extension LayoutConstraintItem {
+    
+    internal func prepare() {
+        if let view = self as? ConstraintView {
+            view.translatesAutoresizingMaskIntoConstraints = false
+        }
+    }
+    
+    internal var superview: ConstraintView? {
+        if let view = self as? ConstraintView {
+            return view.superview
+        }
+        
+        if #available(iOS 9.0, OSX 10.11, *), let guide = self as? ConstraintLayoutGuide {
+            return guide.owningView
+        }
+        
+        return nil
+    }
+    internal var constraints: [Constraint] {
+        return self.constraintsSet.allObjects as! [Constraint]
+    }
+    
+    internal func add(constraints: [Constraint]) {
+        let constraintsSet = self.constraintsSet
+        for constraint in constraints {
+            constraintsSet.add(constraint)
+        }
+    }
+    
+    internal func remove(constraints: [Constraint]) {
+        let constraintsSet = self.constraintsSet
+        for constraint in constraints {
+            constraintsSet.remove(constraint)
+        }
+    }
+    
+    private var constraintsSet: NSMutableSet {
+        let constraintsSet: NSMutableSet
+        
+        if let existing = objc_getAssociatedObject(self, &constraintsKey) as? NSMutableSet {
+            constraintsSet = existing
+        } else {
+            constraintsSet = NSMutableSet()
+            objc_setAssociatedObject(self, &constraintsKey, constraintsSet, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
+        }
+        return constraintsSet
+        
+    }
+    
+}
+private var constraintsKey: UInt8 = 0

+ 42 - 0
Pods/SnapKit/Source/Typealiases.swift

@@ -0,0 +1,42 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#if swift(>=4.2)
+    typealias LayoutRelation = NSLayoutConstraint.Relation
+    typealias LayoutAttribute = NSLayoutConstraint.Attribute
+#else
+    typealias LayoutRelation = NSLayoutRelation
+    typealias LayoutAttribute = NSLayoutAttribute
+#endif
+    typealias LayoutPriority = UILayoutPriority
+#else
+    import AppKit
+    typealias LayoutRelation = NSLayoutConstraint.Relation
+    typealias LayoutAttribute = NSLayoutConstraint.Attribute
+    typealias LayoutPriority = NSLayoutConstraint.Priority
+#endif
+

+ 36 - 0
Pods/SnapKit/Source/UILayoutSupport+Extensions.swift

@@ -0,0 +1,36 @@
+//
+//  SnapKit
+//
+//  Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+//
+//  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.
+
+#if os(iOS) || os(tvOS)
+    import UIKit
+#endif
+
+    
+@available(iOS 8.0, *)
+public extension ConstraintLayoutSupport {
+    
+    public var snp: ConstraintLayoutSupportDSL {
+        return ConstraintLayoutSupportDSL(support: self)
+    }
+    
+}

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

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

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

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

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

@@ -26,6 +26,29 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 
 
+## SnapKit
+
+Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+
+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.
+
+
 ## openssl-ios-bitcode
 
 

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

@@ -43,6 +43,35 @@ SOFTWARE.
 			<key>Type</key>
 			<string>PSGroupSpecifier</string>
 		</dict>
+		<dict>
+			<key>FooterText</key>
+			<string>Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
+
+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.
+</string>
+			<key>License</key>
+			<string>MIT</string>
+			<key>Title</key>
+			<string>SnapKit</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
 		<dict>
 			<key>FooterText</key>
 			<string>

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

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

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

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

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

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

+ 26 - 0
Pods/Target Support Files/SnapKit/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>4.0.1</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>${CURRENT_PROJECT_VERSION}</string>
+  <key>NSPrincipalClass</key>
+  <string></string>
+</dict>
+</plist>

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů