From f91e2d7cdcbccc4bc33345876a5500df41fa8bce Mon Sep 17 00:00:00 2001 From: Nathan Tannar Date: Wed, 18 Oct 2017 00:43:43 -0700 Subject: [PATCH 1/9] CHANGELOG Entry --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82bd6741..7c1c201b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,9 @@ The changelog for `MessageKit`. Also see the [releases](https://github.com/Messa - Changes the `MessageInputBar` bottom `UIStackView`'s `bottomAnchor` to `layoutMarginsGuide.bottomAnchor` to fix issues on the iPhone X [#266](https://github.com/MessageKit/MessageKit/pull/266) by [@nathantannar4](https://github.com/nathantannar4). +- Initial `contentInset.bottom` reference changed from `messageInputBar` to `inputAccessoryView` to allow custom inp`inputAccessoryView`'s that don't break the initial layout +[#267](https://github.com/MessageKit/MessageKit/pull/262) by [@nathantannar4](https://github.com/nathantannar4). + ### Removed - **Breaking Change** Removed `additionalTopContentInset` property of `MessagesViewController` because this is no longer necessary From 43a0e7ad7dbc483ca3bca7cb94a1694efa9bc541 Mon Sep 17 00:00:00 2001 From: Steven Deutsch Date: Sat, 21 Oct 2017 07:02:29 -0500 Subject: [PATCH 2/9] Add MessagesViewController documentation --- .../Controllers/MessagesViewController.swift | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/Sources/Controllers/MessagesViewController.swift b/Sources/Controllers/MessagesViewController.swift index 91a569fe..8d122326 100644 --- a/Sources/Controllers/MessagesViewController.swift +++ b/Sources/Controllers/MessagesViewController.swift @@ -25,19 +25,27 @@ import UIKit open class MessagesViewController: UIViewController { + + // MARK: - Properties [Public] - // MARK: - Properties - + /// The `MessagesCollectionView` managed by the messages view controller object. open var messagesCollectionView = MessagesCollectionView() + /// The `MessageInputBar` used as the `inputAccessoryView` in the view controller. open var messageInputBar = MessageInputBar() + /// 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`. open var scrollsToBottomOnFirstLayout: Bool = false + /// A Boolean value that determines whether the `MessagesCollectionView` scrolls to the + /// bottom whenever the `InputTextView` begins editing. + /// + /// The default value of this property is `false`. open var scrollsToBottomOnKeybordBeginsEditing: Bool = false - private var isFirstLayout: Bool = true - open override var canBecomeFirstResponder: Bool { return true } @@ -49,6 +57,9 @@ open class MessagesViewController: UIViewController { open override var shouldAutorotate: Bool { return false } + + /// A Boolean value used to determine if `viewDidLayoutSubviews()` has been called. + private var isFirstLayout: Bool = true // MARK: - View Life Cycle @@ -89,13 +100,15 @@ open class MessagesViewController: UIViewController { removeKeyboardObservers() } - // MARK: - Methods + // MARK: - Methods [Private] + /// Sets the delegate and dataSource of the messagesCollectionView property. private func setupDelegates() { messagesCollectionView.delegate = self messagesCollectionView.dataSource = self } + /// Registers all cells and supplementary views of the messagesCollectionView property. private func registerReusableViews() { messagesCollectionView.register(TextMessageCell.self) @@ -108,10 +121,12 @@ open class MessagesViewController: UIViewController { } + /// Adds the messagesCollectionView to the controllers root view. private func setupSubviews() { view.addSubview(messagesCollectionView) } + /// Sets the constraints of the `MessagesCollectionView`. private func setupConstraints() { messagesCollectionView.translatesAutoresizingMaskIntoConstraints = false @@ -235,14 +250,14 @@ extension MessagesViewController: UICollectionViewDataSource { // MARK: - Keyboard Handling -extension MessagesViewController { +fileprivate extension MessagesViewController { - fileprivate func addKeyboardObservers() { + func addKeyboardObservers() { NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardDidChangeState), name: .UIKeyboardWillChangeFrame, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handleTextViewDidBeginEditing), name: .UITextViewTextDidBeginEditing, object: messageInputBar.inputTextView) } - fileprivate func removeKeyboardObservers() { + func removeKeyboardObservers() { NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillChangeFrame, object: nil) NotificationCenter.default.removeObserver(self, name: .UITextViewTextDidBeginEditing, object: messageInputBar.inputTextView) } From 5b5acda98837b198103b262b624ab21c15566437 Mon Sep 17 00:00:00 2001 From: Steven Deutsch Date: Sat, 21 Oct 2017 07:02:49 -0500 Subject: [PATCH 3/9] Add Avatar documentation --- Sources/Models/Avatar.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Sources/Models/Avatar.swift b/Sources/Models/Avatar.swift index 3d05b1a5..a7db2354 100644 --- a/Sources/Models/Avatar.swift +++ b/Sources/Models/Avatar.swift @@ -24,11 +24,21 @@ import Foundation +/// An object used to group the information to be used by an `AvatarView`. public struct Avatar { + // MARK: - Properties + + /// The image to be used for an `AvatarView`. public let image: UIImage? + + /// The placeholder initials to be used in the case where no image is provided. + /// + /// The default value of this property is "?". public var initals: String = "?" + // MARK: - Initializer + public init(image: UIImage? = nil, initals: String = "?") { self.image = image self.initals = initals From 1e0cbd74eab2131bdc06f35acfd1e49709d9b484 Mon Sep 17 00:00:00 2001 From: Steven Deutsch Date: Sat, 21 Oct 2017 07:03:21 -0500 Subject: [PATCH 4/9] Add AvatarAlignment documentation --- Sources/Models/AvatarAlignment.swift | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Sources/Models/AvatarAlignment.swift b/Sources/Models/AvatarAlignment.swift index 8dba832d..b2a20656 100644 --- a/Sources/Models/AvatarAlignment.swift +++ b/Sources/Models/AvatarAlignment.swift @@ -24,12 +24,22 @@ import Foundation +/// An enum representing the verical alignment for an `AvatarView`. public enum AvatarAlignment { + /// Aligns the `AvatarView`'s top edge to the cell's top edge. case cellTop - case messageTop - case messageCenter - case messageBottom + + /// Aligns the `AvatarView`'s bottom edge to the cell's bottom edge. case cellBottom - + + /// Aligns the `AvatarView`'s top edge to the `MessageContainerView`'s top edge. + case messageTop + + /// Aligns the `AvatarView`'s bottom edge to the `MessageContainerView`s bottom edge. + case messageBottom + + /// Aligns the `AvatarView` center to the `MessageContainerView` center. + case messageCenter + } From 078bf010fcfc4fb855adc0e73435e3ed4dd182d8 Mon Sep 17 00:00:00 2001 From: Steven Deutsch Date: Sat, 21 Oct 2017 07:03:49 -0500 Subject: [PATCH 5/9] Add MessageType documentation --- Sources/Protocols/MessageType.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Sources/Protocols/MessageType.swift b/Sources/Protocols/MessageType.swift index f2537334..26aadd10 100644 --- a/Sources/Protocols/MessageType.swift +++ b/Sources/Protocols/MessageType.swift @@ -24,13 +24,23 @@ import Foundation +/// 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 } + } From 4dacbc73827c355f8cf78525790f22e03f12c08c Mon Sep 17 00:00:00 2001 From: Steven Deutsch Date: Sat, 21 Oct 2017 07:10:23 -0500 Subject: [PATCH 6/9] Add LabelAlignment documentation --- Sources/Models/AvatarHorizontalAlignment.swift | 6 ++++++ Sources/Models/LabelAlignment.swift | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/Sources/Models/AvatarHorizontalAlignment.swift b/Sources/Models/AvatarHorizontalAlignment.swift index 62a07525..51862de4 100644 --- a/Sources/Models/AvatarHorizontalAlignment.swift +++ b/Sources/Models/AvatarHorizontalAlignment.swift @@ -26,7 +26,13 @@ import Foundation // MARK: - AvatarVerticalAlignment +/// An enum representing the horizontal alignment of an `AvatarView`. internal enum AvatarHorizontalAlignment { + + /// Positions the `AvatarView` on the side closest to the cell's leading edge. case cellLeading + + /// Positions the `AvatarView` on the side closest to the cell's trailing edge. case cellTrailing + } diff --git a/Sources/Models/LabelAlignment.swift b/Sources/Models/LabelAlignment.swift index b834534c..202933a1 100644 --- a/Sources/Models/LabelAlignment.swift +++ b/Sources/Models/LabelAlignment.swift @@ -24,14 +24,30 @@ import UIKit +/// An enum represnting the horizontal alignment of a `MessageCollectionViewCell`'s top and bottom labels. public enum 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) + + /// 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 From 88c169ea4b14e4060ab4606d1bc5f0633ec047f9 Mon Sep 17 00:00:00 2001 From: Steven Deutsch Date: Sat, 21 Oct 2017 07:23:38 -0500 Subject: [PATCH 7/9] Add Sender and MessageData documentation --- Sources/Models/MessageData.swift | 18 ++++++++++++++++++ Sources/Models/Sender.swift | 12 ++++++++++++ 2 files changed, 30 insertions(+) diff --git a/Sources/Models/MessageData.swift b/Sources/Models/MessageData.swift index ee4ff102..1e80645c 100644 --- a/Sources/Models/MessageData.swift +++ b/Sources/Models/MessageData.swift @@ -25,13 +25,31 @@ import Foundation import class CoreLocation.CLLocation +/// An enum representing the kind of message and its underlying data. public enum MessageData { + /// A standard text message. + /// + /// 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 + /// to set this property and results in higher performance. case text(String) + + /// A message with attributed text. case attributedText(NSAttributedString) + + /// A photo message. case photo(UIImage) + + /// A video message. case video(file: URL, thumbnail: UIImage) + + /// A location message. case location(CLLocation) + + /// An emoji message. case emoji(String) // MARK: - Not supported yet diff --git a/Sources/Models/Sender.swift b/Sources/Models/Sender.swift index b8f4baec..575fe42b 100644 --- a/Sources/Models/Sender.swift +++ b/Sources/Models/Sender.swift @@ -24,12 +24,21 @@ import Foundation +/// An object that groups the metadata of a messages sender. public struct Sender { + /// MARK: - Properties + + /// The unique String identifier for the sender. + /// + /// Note: This value must be unique across all senders. public let id: String + /// The display name of a sender. public let displayName: String + // MARK: - Intializers + public init(id: String, displayName: String) { self.id = id self.displayName = displayName @@ -39,7 +48,10 @@ public struct Sender { // MARK: - Equatable Conformance extension Sender: Equatable { + + /// Two senders are considered equal if they have the same id. static public func == (left: Sender, right: Sender) -> Bool { return left.id == right.id } + } From da9a1a804a7c40199b934f7f7ed33252f4c52bf2 Mon Sep 17 00:00:00 2001 From: Steven Deutsch Date: Sat, 21 Oct 2017 08:06:35 -0500 Subject: [PATCH 8/9] Add documentation for some of the protocols --- Sources/Protocols/MessagesDataSource.swift | 41 +++++++++++ .../Protocols/MessagesDisplayDelegate.swift | 44 +++++++++++- .../Protocols/MessagesLayoutDelegate.swift | 72 ++++++++++++++++++- 3 files changed, 155 insertions(+), 2 deletions(-) diff --git a/Sources/Protocols/MessagesDataSource.swift b/Sources/Protocols/MessagesDataSource.swift index 4014c20c..bbccc7c0 100644 --- a/Sources/Protocols/MessagesDataSource.swift +++ b/Sources/Protocols/MessagesDataSource.swift @@ -26,18 +26,59 @@ import UIKit public protocol MessagesDataSource: class { + /// 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. + /// + /// - Parameters: + /// - 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. func isFromCurrentSender(message: MessageType) -> Bool + /// The message to be used for a `MessagesCollectionViewCell` at the given `IndexPath`. + /// + /// - Parameters: + /// - indexPath: The `IndexPath` of the cell. + /// - 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`. + /// + /// - Parameters: + /// - messagesCollectionView: The `MessagesCollectionView` in which the messages will be displayed. func numberOfMessages(in messagesCollectionView: MessagesCollectionView) -> Int + /// 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()`. func avatar(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> Avatar + /// The attributed text to be used for cell'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 cellTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? + /// The attributed text to be used for cell'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 `nil`. func cellBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? } diff --git a/Sources/Protocols/MessagesDisplayDelegate.swift b/Sources/Protocols/MessagesDisplayDelegate.swift index c6b16de4..55febcd1 100644 --- a/Sources/Protocols/MessagesDisplayDelegate.swift +++ b/Sources/Protocols/MessagesDisplayDelegate.swift @@ -24,10 +24,31 @@ import Foundation +/// A protocol used by the `MessagesViewController` to customize the appearance of a `TextMessageCell`. public protocol TextMessageDisplayDelegate: class { + /// 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. + /// - 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: UIColor.white + /// + /// 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. + /// - 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. func enabledDetectors(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> [DetectorType] } @@ -45,10 +66,31 @@ public extension TextMessageDisplayDelegate { } +/// A protocol used by the `MessagesViewController` to customize the appearance of a `MessagesCollectionViewCell`. public protocol MessagesDisplayDelegate: class { + /// Specifies the `MessageStyle` to be used for a `MessageContainerView`. + /// + /// - 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 `MessageStyle.bubble`. func messageStyle(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageStyle - + + /// Specifies the background color of the `MessageContainerView`. + /// + /// - 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 is `UIColor.clear` for emoji messages. For all other `MessageData` cases, the color depends on the `Sender`: + /// + /// Current Sender: Green + /// + /// All other Senders: Gray func backgroundColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor func messageHeaderView(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageHeaderView diff --git a/Sources/Protocols/MessagesLayoutDelegate.swift b/Sources/Protocols/MessagesLayoutDelegate.swift index 9277de5f..e4d0e166 100644 --- a/Sources/Protocols/MessagesLayoutDelegate.swift +++ b/Sources/Protocols/MessagesLayoutDelegate.swift @@ -24,18 +24,84 @@ import Foundation +/// A protocol used by the `MessagesCollectionViewFlowLayout` object to determine +// the size and layout of a `MessageCollectionViewCell` and its contents. public protocol MessagesLayoutDelegate: class { + /// Specifies the insets for the text rect of the `MessageLabel` in a `TextMessageCell`. + /// + /// - Parameters: + /// - message: A `MessageType` with a `MessageData` case of `.text` or `.attributedText` to which these insets 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`: + /// + /// 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 + /// 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 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`. func avatarAlignment(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> AvatarAlignment + /// 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 func headerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize @@ -48,7 +114,11 @@ public extension MessagesLayoutDelegate { func messageLabelInset(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets { guard let dataSource = messagesCollectionView.messagesDataSource else { return .zero } - return dataSource.isFromCurrentSender(message: message) ? UIEdgeInsets(top: 7, left: 14, bottom: 7, right: 18) : UIEdgeInsets(top: 7, left: 18, bottom: 7, right: 14) + 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 messagePadding(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets { From 14aeef08f8647b05b4a511e3af7f09476c81cbeb Mon Sep 17 00:00:00 2001 From: Steven Deutsch Date: Mon, 23 Oct 2017 22:51:42 -0500 Subject: [PATCH 9/9] Finish documenting protocols + a few more classes --- .../LocationMessageSnapshotOptions.swift | 16 +++++++++ .../LocationMessageLayoutDelegate.swift | 18 ++++++++++ .../MediaMessageLayoutDelegate.swift | 21 ++++++++++++ Sources/Protocols/MessageCellDelegate.swift | 33 +++++++++++++++++++ .../Protocols/MessagesDisplayDelegate.swift | 28 ++++++++++++++-- .../Protocols/MessagesLayoutDelegate.swift | 18 +++++++++- 6 files changed, 131 insertions(+), 3 deletions(-) diff --git a/Sources/Models/LocationMessageSnapshotOptions.swift b/Sources/Models/LocationMessageSnapshotOptions.swift index faa75dd5..98c60565 100644 --- a/Sources/Models/LocationMessageSnapshotOptions.swift +++ b/Sources/Models/LocationMessageSnapshotOptions.swift @@ -24,11 +24,27 @@ import MapKit +/// An object grouping the settings used by the `MKMapSnapshotter` through the `LocationMessageDisplayDelegate`. public struct LocationMessageSnapshotOptions { + /// A Boolean value indicating whether the snapshot image should display buildings. + /// + /// The default value of this property is `false`. var showsBuildings = false + + /// A Boolean value indicating whether the snapshot image should display points of interest. + /// + /// The default value of this property is `false`. var showsPointsOfInterest = false + + /// The span of the snapshot. + /// + /// The default value of this property uses a width of `0` and height of `0`. var span: MKCoordinateSpan = MKCoordinateSpan(latitudeDelta: 0, longitudeDelta: 0) + + /// The scale of the snapshot. + /// + /// The default value of this property uses the `UIScreen.main.scale`. var scale: CGFloat = UIScreen.main.scale } diff --git a/Sources/Protocols/LocationMessageLayoutDelegate.swift b/Sources/Protocols/LocationMessageLayoutDelegate.swift index ea21563f..8bd54b70 100644 --- a/Sources/Protocols/LocationMessageLayoutDelegate.swift +++ b/Sources/Protocols/LocationMessageLayoutDelegate.swift @@ -24,10 +24,28 @@ import Foundation +/// A protocol used by the `MessagesCollectionViewFlowLayout` object to determine +/// the size and layout of a `LocationMessageCell` and its contents. public protocol LocationMessageLayoutDelegate: MessagesLayoutDelegate { + /// 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 widthForLocation(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. func heightForLocation(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat } diff --git a/Sources/Protocols/MediaMessageLayoutDelegate.swift b/Sources/Protocols/MediaMessageLayoutDelegate.swift index 8ce990eb..4ec18af6 100644 --- a/Sources/Protocols/MediaMessageLayoutDelegate.swift +++ b/Sources/Protocols/MediaMessageLayoutDelegate.swift @@ -24,10 +24,31 @@ import AVFoundation +/// A protocol used by the `MessagesCollectionViewFlowLayout` object to determine +/// the size and layout of a `MediaMessageCell`s and its contents. public protocol MediaMessageLayoutDelegate: MessagesLayoutDelegate { + /// 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 } diff --git a/Sources/Protocols/MessageCellDelegate.swift b/Sources/Protocols/MessageCellDelegate.swift index b47c3d06..0366a458 100644 --- a/Sources/Protocols/MessageCellDelegate.swift +++ b/Sources/Protocols/MessageCellDelegate.swift @@ -24,14 +24,47 @@ import Foundation +/// A protocol used by `MessageCollectionViewCell` subclasses to detect taps in the cell's contents. public protocol MessageCellDelegate: class, MessageLabelDelegate { + /// Triggered when a touch occurs in the `MessageContainerView`. + /// + /// - Parameters: + /// - cell: The cell where 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 didTapMessage(in cell: MessageCollectionViewCell) + /// Triggered when a touch occurs in the `AvatarView`. + /// + /// - Parameters: + /// - cell: The cell where 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 didTapAvatar(in cell: MessageCollectionViewCell) + /// Triggered when a touch occurs in the cellBottomLabel. + /// + /// - Parameters: + /// - cell: The cell where 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) + /// Triggered when a touch occurs in the cellTopLabel. + /// + /// - Parameters: + /// - cell: The cell where 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 didTapTopLabel(in cell: MessageCollectionViewCell) } diff --git a/Sources/Protocols/MessagesDisplayDelegate.swift b/Sources/Protocols/MessagesDisplayDelegate.swift index 55febcd1..df7c52be 100644 --- a/Sources/Protocols/MessagesDisplayDelegate.swift +++ b/Sources/Protocols/MessagesDisplayDelegate.swift @@ -92,11 +92,35 @@ public protocol MessagesDisplayDelegate: class { /// /// 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`. + /// + /// - 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 - + + /// The section footer to use for a given `MessageType`. + /// + /// - 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 } diff --git a/Sources/Protocols/MessagesLayoutDelegate.swift b/Sources/Protocols/MessagesLayoutDelegate.swift index e4d0e166..0f3cd31a 100644 --- a/Sources/Protocols/MessagesLayoutDelegate.swift +++ b/Sources/Protocols/MessagesLayoutDelegate.swift @@ -25,7 +25,7 @@ import Foundation /// A protocol used by the `MessagesCollectionViewFlowLayout` object to determine -// the size and layout of a `MessageCollectionViewCell` and its contents. +/// the size and layout of a `MessageCollectionViewCell` and its contents. public protocol MessagesLayoutDelegate: class { /// Specifies the insets for the text rect of the `MessageLabel` in a `TextMessageCell`. @@ -104,8 +104,24 @@ public protocol MessagesLayoutDelegate: class { /// 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`. + /// + /// - 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 the width of the `MessagesCollectionView` and a height of 12. func headerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize + /// Specifies the size to use for a `MessageFooterView`. + /// + /// - 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 size of `GGSize.zero`. func footerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize }