diff --git a/Documentation/FAQs.md b/Documentation/FAQs.md index b2db901a..328ec18f 100644 --- a/Documentation/FAQs.md +++ b/Documentation/FAQs.md @@ -23,6 +23,14 @@ class ParentVC: UIViewController { **How can I remove the `AvatarView` from the cell?** +You can set the `AvatarView` to hidden through the `configureAvatarView(_:AvatarView,for:MessageType,at:IndexPath,in:MessagesCollectionView)` method of `MessagesDisplayDelegate`. + +```Swift +func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) { + avatarView.isHidden = true +} +``` + If you return `CGSize.zero` from the `MessagesLayoutDelegate` method `avatarSize(for:MessageType,at:IndexPath,in:MessagesCollectionView)`, the `AvatarView` will not be visible for that cell. diff --git a/Documentation/MessagesDataSource.md b/Documentation/MessagesDataSource.md deleted file mode 100644 index 232fdd0e..00000000 --- a/Documentation/MessagesDataSource.md +++ /dev/null @@ -1,42 +0,0 @@ -# MessagesDataSource - -The `MessagesDataSource` is responsible for returning all forms of data for the `MessageCollectionViewCell`. This includes the number of cells in the `MessageCollectionView`, the `MessageType` for each cell, the `Avatar` to be used for the `AvatarView`, the current `Sender` of each message, and finally the `NSAttributedString` text for the `cellTopLabel` and `cellBottomLabel` of each cell. - -The `MessagesDataSource` requires that you implement the following 3 methods: - -```Swift - func currentSender() -> Sender - - func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType - - func numberOfMessages(in messagesCollectionView: MessagesCollectionView) -> Int -``` - -### Providing an avatar image for AvatarView - -```Swift - func avatar(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> Avatar -``` -You can use the `avatar` method to return an `Avatar` object containing the image you want to display in the `AvatarView`. -The `Avatar` type has the following 2 properties: - -### Avatar -```Swift -public struct Avatar { - public let image: UIImage? - public var initials: String = "?" -} -``` - -If no image is provided then the `AvatarView` will generate a placeholder image using the specified initials of the `Avatar`. The default value of this method returns an `Avatar` with initials of "?". - - -### Providing cellTopLabel text & cellBottomLabelText -```Swift - func cellTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? - - func cellBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? -``` -The `cellTopLabelAttributedText` & `cellBottomLabelAttributedText` methods both default to `nil`. If these methods return `nil` the label will have a size of `.zero` in the `MessageCollectionViewCell`. - - diff --git a/Documentation/MessagesDisplayDelegate.md b/Documentation/MessagesDisplayDelegate.md deleted file mode 100644 index 93f30dfb..00000000 --- a/Documentation/MessagesDisplayDelegate.md +++ /dev/null @@ -1,99 +0,0 @@ -# MessagesDisplayDelegate -The `MessagesDisplayDelegate` protocol allows you to customize the general appearance of `MessageCollectionViewCells`, `TextMessageCells`, and their accompanying `MessageHeaderView` or `MessageFooterView`. - -All of `MessagesDisplayDelegate`'s methods have default implementations. You can override their behavior by providing your own implementation. - -## Customizing MessageCollectionViewCell - -### Customizing the messageContainerView's background color - -```Swift - func backgroundColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor -``` - -The default implementation of this method uses the `isFromCurrentSender` method of `MessagesDataSource` to evaluate if the message is from the current sender. It returns backgroundColor of light green if the message is from the current sender and light gray otherwise. - - -### Customizing the messageContainerView's style - -```Swift - func messageStyle(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageStyle -``` - -This method allows you to customize the `MessageStyle` for the cell which is an enum containing the following 5 cases: -### MessageStyle -```Swift -public enum MessageStyle { - case none - case bubble - case bubbleOutline(UIColor) - case bubbleTail(TailCorner, TailStyle) - case bubbleTailOutline(UIColor, TailCorner, TailStyle) -} -``` -- `none` Use this case if you want now style applied to the `messageContainerView` - - -- `bubble` Use this case if you want message bubbles - - -- `bubbleOutline(UIColor)` Use this case if you want message bubbles with an outline. The associated value `UIColor` is the color to use for the outline of the bubble. - - -- `bubbleTail(TailCorner, TailStyle)` Use this case if you want message bubbles with a tail. You must specify the corner where the tail will be located and which tail style you'd like the bubble to have. - - -- `bubbleTailOutline(UIColor, TailCorner, TailStyle)` Use this case if you want message bubbles with both a tail and outline. You must specify where the tail will be located and which tail style you'd like the bubble to have. - -The default `MessageStyle` for a `MessageCollectionViewCell` is `.bubble`. - -### TailStyle -**MessageKit** currently supports 2 types of `TailStyle`: -```Swift -public enum TailStyle { - case curved - case pointedEdge -} -``` -The `curved` style is the type of tail that **iMessage** uses and the `pointedEdge` style is like **Google Hangouts**. - - -### TailCorner -The `TailCorner` is just a simple enum representing the 4 corners of the `messageContainerView`: -```Swift -public enum TailStyle { - case topLeft - case bottomRight - case topRight - case bottomRight -} -``` - -### Customizing MessageHeaderView & MessageFooterView - -Since **MessageKit** puts each `MessageType` in its own section in the `MessagesCollectionView`, this allows each message to have its own section `MessageHeaderView` and `MessageFooterView`. You can use the following 2 methods to provide custom section headers and footers for your messages: - -```Swift - func messageHeaderView(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageHeaderView? - - func messageFooterView(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageFooterView? -``` - -By default, `messageHeaderView` uses the method `shouldDisplayHeader(for:_:_)` of `MessagesDisplayDelegate` to determine if it should return a `MessageHeaderView` subclass called `MessageDateHeaderView` or `nil`. The `shouldDisplayHeader(for:_:_)` method checks the `showsDateHeaderAfterTimeInterval` property of `MessagesCollectionView` and returns `true` if the the last message was sent after the specified time interval. The default value of this `TimeInterval` is **1 hour**. - -By default, `messageFooterView` returns `nil`. - -In order to return a custom subclass for the header or footer you will need to register the custom cell via `messagesCollectionView.register` and optionally customise `headerViewSize` or `footerViewSize` within the assigned `MessagesLayoutDelegate`. - -### Customizing a TextMessageCell's text color - -```Swift - func textColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor -``` - -The default implementation of this method uses the `isFromCurrentSender` method of `MessagesDataSource` to evaluate if the message is from the current sender. It returns a text color of `UIColor.white` if the message is from the current sender and `UIColor.darkText` otherwise. - -**NOTE:** This method only applies to `TextMessageCell` - - - diff --git a/Documentation/MessagesLayoutDelegate.md b/Documentation/MessagesLayoutDelegate.md deleted file mode 100644 index 01b5fefb..00000000 --- a/Documentation/MessagesLayoutDelegate.md +++ /dev/null @@ -1,65 +0,0 @@ -# MessagesLayoutDelegate - -The `MessagesLayoutDelegate` protocol is responsible for sizing all the content inside a `MessageCollectionViewCell` and adjusting the cell's subviews position in relation to each other. All of `MessagesLayoutDelegate` methods have default implementations. You can provide your own implementation to override their behavior. - -### Adjusting the Size of the Avatar - -```Swift - func avatarSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize -``` - -You can use the `avatarSize` method to adjust the size of the `AvatarView` for each `MessageCollectionView` cell. The default size is `30 x 30`. If you don't want an `AvatarView` in your cell, just return a value of `.zero`. - -### Adjusting the position of the Avatar - -```Swift - func avatarAlignment(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> AvatarAlignment -``` - -You can use the `avatarAlignment` method to adjust the position of the `AvatarView` in the cell relative to the `MessageCollectionViewCell` or the `MessageContainerView`. This method requires you return a value from the `AvatarAlignment` enum which has the following 5 cases: - -### AvatarAlignment -```Swift -public enum AvatarAlignment { - case cellTop - case messageTop - case messageCenter - case messageBottom - case cellBottom -} -``` -The default value for this method is `.cellBottom`. - - -### Adjusting the cellTopLabel & cellBottomLabel positions -```Swift - func cellTopLabelAlignment(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> LabelAlignment - - func cellBottomLabelAlignment(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> LabelAlignment -``` - -You can use the `cellTopLabelAlignment` and `cellBottomLabelAlignment` methods to adjust the position of the labels relative to the `MessageCollectionViewCell` or the `MessageContainerView`. This method requires you return a value from the `LabelAlignment` enum which has the following 5 cases: - -```Swift -public enum LabelAlignment { - case cellTrailing - case cellLeading - case cellCenter - case messageTrailing - case messageLeading -} -``` - -By default, the `cellTopLabel` is aligned `.messageTrailing` if the message is from the current sender and `.messageLeading` otherwise. - -By default, the `cellBottomLabel` is aligned `.messageLeading` if the message is from the current sender and `.messageTrailing` otherwise. - -### Adjusting the size of the MessageHeaderView and MessageFooterView - -```Swift - func headerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize - - func footerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize -``` - -You can use the `headerViewSize` and `footerViewSize` methods to adjust the size of the header or footer views for each `MessageCollectionViewCell`. If you don't want to display a `MessageHeaderView` or `MessageFooterView` just return a size of `.zero` respectively. diff --git a/Documentation/QuickStart.md b/Documentation/QuickStart.md index 1704399e..eb33a196 100644 --- a/Documentation/QuickStart.md +++ b/Documentation/QuickStart.md @@ -12,7 +12,7 @@ public protocol MessageType { var sentDate: Date { get } - var data: MessageData { get } + var kind: MessageKind { get } } ``` First, each `MessageType` is required to have a `Sender` which contains two properties, `id` and `displayName`: @@ -31,33 +31,36 @@ Second, each message must have its own `messageId` which is a unique `String` id Third, each message must have a `sentDate` which represents the `Date` that each message was sent. -Fourth, each message must specify what type of data this message contains through the `data: MessageData` property: -### MessageData +Fourth, each message must specify what kind of message it is through the `kind: MessageKind` property: +### MessageKind ```Swift -public enum MessageData { +public enum MessageKind { case text(String) case attributedText(NSAttributedString) - case photo(UIImage) - case video(file: URL, thumbnail: UIImage) - case location(CLLocation) + case emoji(String) + case photo(MediaItem) + case video(MediaItem) + case location(LocationItem) + case custom(Any?) } ``` -`MessageData` has 5 different cases representing the types of messages that **MessageKit** can display. +`MessageData` has 7 different cases representing the types of messages that **MessageKit** can display. - `text(String)` - Use this case if you just want to display a normal text message without any attributes. -- **NOTE**: You must also specify the `UIFont` you want to use for this text by setting the `messageLabelFont` property of `MessagesCollectionViewFlowLayout`. +- **NOTE**: You must also specify the `UIFont` you want to use for this text by setting the `messageLabelFont` property of the `textMessageSizeCalculator` in `MessagesCollectionViewFlowLayout`. -- `attributedText(NSAttributedString)` - Use this case if you want to display a text message with attributes -- **NOTE**: It is recommended that you use `attributedText` regardless of the complexity of your text's attributes. When using this method you do not need to set the `messageLabelFont` property of `MessagesCollectionViewFlowLayout` and generally this method will decrease the probability of programmer error and increase performance. +- `emoji(String)` - Use this case to display a message that only contains emoji. +- **NOTE**: You must also specify the `UIFont` you want to use for this text by setting the `messageLabelFont` property of the `emojiMessageSizeCalculator` in `MessagesCollectionViewFlowLayout`. -- `photo(UIImage)` - Use this case to display a photo message. +- `attributedText(NSAttributedString)` - Use this case if you want to display a text message with attributes. +- **NOTE**: It is recommended that you use `attributedText` for text messages. +- `photo(MediaItem)` - Use this case to display a photo message. -- `video(file: URL, thumbnail: UIImage)` - Use this case to display a video message. +- `video(MediaItem)` - Use this case to display a video message. - -- `location(CLLocation)` - Use this case to display a location message. +- `location(LocationItem)` - Use this case to display a location message. # MessagesViewController @@ -105,7 +108,7 @@ extension ChatViewController: MessagesDataSource { return Sender(id: "any_unique_id", displayName: "Steven") } - func numberOfMessages(in messagesCollectionView: MessagesCollectionView) -> Int { + func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int { return messages.count } @@ -114,7 +117,9 @@ extension ChatViewController: MessagesDataSource { } } ``` -**NOTE**: If you look closely at the implementation of the `messageForItem` method you'll see that we use the `indexPath.section` to retrieve our `MessageType` from the array as opposed to the traditional `indexPath.row` property. This is because in **MessageKit** each `MessageType` is in its own section of the `MessagesCollectionView`. +**NOTE**: If you look closely at the implementation of the `messageForItem` method you'll see that we use the `indexPath.section` to retrieve our `MessageType` from the array as opposed to the traditional `indexPath.row` property. This is because the default behavior of **MessageKit** is to put each `MessageType` is in its own section of the `MessagesCollectionView`. + +If you want to override this behavior, you can specify the number of items in each section through the `numberOfItems` method of `MessagesDataSource`. As you can see **MessageKit** does not require you to return a `MessagesCollectionViewCell` like the traditional `UITableView` or `UICollectionView` API. All that is required is for you to return your `MessageType` model object. We take care of applying the model to the cell for you.