diff --git a/CHANGELOG.md b/CHANGELOG.md index ad339742..c28db709 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,18 +4,22 @@ The changelog for `MessageKit`. Also see the [releases](https://github.com/Messa -------------------------------------- -## [2.0.0](https://github.com/MessageKit/MessageKit/releases/tag/2.0.0-beta.1) +## Upcoming Release ### Changed - Change acl of `handleGesture(touchLocation:)` in `MessageLabel` from internal to open. [#912](https://github.com/MessageKit/MessageKit/pull/912) by [@julienkode](https://github.com/JulienKode) -- Fixed the way that the Strings and UIImages are parsed in the `InputTextView` to prevent crashes in `parseForComponents()`. -[#791](https://github.com/MessageKit/MessageKit/pull/791) by [@nathantannar4](https://github.com/nathantannar4) +## [2.0.0-beta.1](https://github.com/MessageKit/MessageKit/releases/tag/2.0.0-beta.1) + +### Changed - **Breaking Change** Updated codebase to Swift 4.2 [#883](https://github.com/MessageKit/MessageKit/pull/883) by [@nathantannar4](https://github.com/nathantannar4) +- Fixed the way that the Strings and UIImages are parsed in the `InputTextView` to prevent crashes in `parseForComponents()`. +[#791](https://github.com/MessageKit/MessageKit/pull/791) by [@nathantannar4](https://github.com/nathantannar4) + ### Added - Added support for detection and handling of `NSLink`s inside of messages. @@ -30,15 +34,17 @@ The changelog for `MessageKit`. Also see the [releases](https://github.com/Messa - Added `additionalBottomInset` property that allows to adjust the bottom content inset automatically set on the messages collection view by the view controller. [#787](https://github.com/MessageKit/MessageKit/pull/787) by [@andreyvit](https://github.com/andreyvit) +- Added new methods to simplify using of custom messages: `customCellSizeCalculator(for:at:in:)` for `MessagesLayoutDelegate` and `customCell(for:at:in:)` for `MessagesDataSource`. +[#879](https://github.com/MessageKit/MessageKit/pull/879) by [@realbonus](https://github.com/RealBonus) + ### Fixed -- Fixed a bug that prevented `MessageLabel` from laying out properly when contained by superviews using autolayout. -[#889](https://github.com/MessageKit/MessageKit/pull/889) by [@marius-serban](https://github.com/marius-serban). - - - **Breaking Change** Fixed typo of `scrollsToBottomOnKeybordBeginsEditing` to `scrollsToBottomOnKeyboardBeginsEditing`. [#856](https://github.com/MessageKit/MessageKit/pull/856) by [@p-petrenko](https://github.com/p-petrenko) +- Fixed a bug that prevented `MessageLabel` from laying out properly when contained by superviews using autolayout. +[#889](https://github.com/MessageKit/MessageKit/pull/889) by [@marius-serban](https://github.com/marius-serban). + - Fixed bottom content inset adjustment when using an undocked keyboard on iPad, or when `edgesForExtendedLayout` does not include `.top`, or when a parent container view controller adds extra views at the top of the screen. [#787](https://github.com/MessageKit/MessageKit/pull/787) by [@andreyvit](https://github.com/andreyvit) @@ -49,7 +55,9 @@ The changelog for `MessageKit`. Also see the [releases](https://github.com/Messa - Fixed `MessagesCollectionView` to allow to use nibs with `MessageReusableView`. [#832](https://github.com/MessageKit/MessageKit/pull/832) by [@maxxx777](https://github.com/maxxx777). -- Fixed multiple crashes at views, when views are being called from another XIB. [#905](https://github.com/MessageKit/MessageKit/pull/905) by [@talanov](https://github.com/talanov). + +- Fixed multiple crashes at views, when views are being called from another XIB. +[#905](https://github.com/MessageKit/MessageKit/pull/905) by [@talanov](https://github.com/talanov). ## [1.0.0](https://github.com/MessageKit/MessageKit/releases/tag/1.0.0) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6b37d5ae..eb2c5b40 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ ### Code of Conduct -Please read our [Code of Conduct](https://github.com/MessageKit/MessageKit/blob/master/Code_of_Conduct.md). +Please read our [Code of Conduct](https://github.com/MessageKit/MessageKit/blob/master/CODE_OF_CONDUCT.md). The MessageKit maintainers take this Code of Conduct very seriously. Intolerance, disrespect, harassment, and any form of negativity will not be tolerated. ### Ways to Contribute diff --git a/Example/Sources/AppDelegate.swift b/Example/Sources/AppDelegate.swift index 5f31cfe2..ea28caaa 100644 --- a/Example/Sources/AppDelegate.swift +++ b/Example/Sources/AppDelegate.swift @@ -35,6 +35,11 @@ final internal class AppDelegate: UIResponder, UIApplicationDelegate { window?.rootViewController = NavigationController(rootViewController: LaunchViewController()) window?.makeKeyAndVisible() + if UserDefaults.isFirstLaunch() { + // Enable Text Messages + UserDefaults.standard.set(true, forKey: "Text Messages") + } + return true } diff --git a/Example/Sources/Data Generation/SampleData.swift b/Example/Sources/Data Generation/SampleData.swift index 63614a73..07b47218 100644 --- a/Example/Sources/Data Generation/SampleData.swift +++ b/Example/Sources/Data Generation/SampleData.swift @@ -30,6 +30,26 @@ final internal class SampleData { static let shared = SampleData() private init() {} + + enum MessageTypes: UInt32, CaseIterable { + case Text = 0 + case AttributedText = 1 + case Photo = 2 + case Video = 3 + case Emoji = 4 + case Location = 5 + case Url = 6 + case Phone = 7 + case Custom = 8 + + static func random() -> MessageTypes { + // Update as new enumerations are added + let maxValue = Custom.rawValue + + let rand = arc4random_uniform(maxValue+1) + return MessageTypes(rawValue: rand)! + } + } let system = Sender(id: "000000", displayName: "System") let nathan = Sender(id: "000001", displayName: "Nathan Tannar") @@ -46,8 +66,6 @@ final internal class SampleData { let messageImages: [UIImage] = [#imageLiteral(resourceName: "img1"), #imageLiteral(resourceName: "img2")] - let messageTypes = ["Text", "Text", "Text", "AttributedText", "Location", "Photo", "Emoji", "Video", "URL", "Phone", "Custom"] - let emojis = [ "👍", "😂😂😂", @@ -116,51 +134,62 @@ final internal class SampleData { return date } } + + func randomMessageType() -> MessageTypes { + let messageType = MessageTypes.random() - func randomMessage(isCustomEnabled: Bool, allowedSenders: [Sender]) -> MockMessage { + if !UserDefaults.standard.bool(forKey: "\(messageType)" + " Messages") { + return randomMessageType() + } + + return messageType + } + + func randomMessage(allowedSenders: [Sender]) -> MockMessage { let randomNumberSender = Int(arc4random_uniform(UInt32(allowedSenders.count))) - let randomNumberImage = Int(arc4random_uniform(UInt32(messageImages.count))) - let randomMessageType = Int(arc4random_uniform(UInt32(messageTypes.count - (isCustomEnabled ? 0 : 1)))) - let randomNumberLocation = Int(arc4random_uniform(UInt32(locations.count))) - let randomNumberEmoji = Int(arc4random_uniform(UInt32(emojis.count))) - let randomSentance = Lorem.sentence() let uniqueID = NSUUID().uuidString let sender = allowedSenders[randomNumberSender] let date = dateAddingRandomTime() - switch messageTypes[randomMessageType] { - case "Text": - return MockMessage(text: randomSentance, sender: sender, messageId: uniqueID, date: date) - case "AttributedText": - let attributedText = attributedString(with: randomSentance) + switch randomMessageType() { + case .Text: + let randomSentence = Lorem.sentence() + return MockMessage(text: randomSentence, sender: sender, messageId: uniqueID, date: date) + case .AttributedText: + let randomSentence = Lorem.sentence() + let attributedText = attributedString(with: randomSentence) return MockMessage(attributedText: attributedText, sender: senders[randomNumberSender], messageId: uniqueID, date: date) - case "Photo": + case .Photo: + let randomNumberImage = Int(arc4random_uniform(UInt32(messageImages.count))) let image = messageImages[randomNumberImage] return MockMessage(image: image, sender: sender, messageId: uniqueID, date: date) - case "Video": + case .Video: + let randomNumberImage = Int(arc4random_uniform(UInt32(messageImages.count))) let image = messageImages[randomNumberImage] return MockMessage(thumbnail: image, sender: sender, messageId: uniqueID, date: date) - case "Emoji": + case .Emoji: + let randomNumberEmoji = Int(arc4random_uniform(UInt32(emojis.count))) return MockMessage(emoji: emojis[randomNumberEmoji], sender: sender, messageId: uniqueID, date: date) - case "Location": + case .Location: + let randomNumberLocation = Int(arc4random_uniform(UInt32(locations.count))) return MockMessage(location: locations[randomNumberLocation], sender: sender, messageId: uniqueID, date: date) - case "URL": + case .Url: return MockMessage(text: "https://github.com/MessageKit", sender: sender, messageId: uniqueID, date: date) - case "Phone": + case .Phone: return MockMessage(text: "123-456-7890", sender: sender, messageId: uniqueID, date: date) - case "Custom": + case .Custom: return MockMessage(custom: "Someone left the conversation", sender: system, messageId: uniqueID, date: date) - default: - fatalError("Unrecognized mock message type") } } func getMessages(count: Int, completion: ([MockMessage]) -> Void) { var messages: [MockMessage] = [] + // Disable Custom Messages + UserDefaults.standard.set(false, forKey: "Custom Messages") for _ in 0.. Void) { var messages: [MockMessage] = [] + // Enable Custom Messages + UserDefaults.standard.set(true, forKey: "Custom Messages") for _ in 0.. Void) { var messages: [MockMessage] = [] + // Disable Custom Messages + UserDefaults.standard.set(false, forKey: "Custom Messages") for _ in 0.. Bool { + let hasBeenLaunchedBeforeFlag = "hasBeenLaunchedBeforeFlag" + let isFirstLaunch = !UserDefaults.standard.bool(forKey: hasBeenLaunchedBeforeFlag) + if isFirstLaunch { + UserDefaults.standard.set(true, forKey: hasBeenLaunchedBeforeFlag) + UserDefaults.standard.synchronize() + } + return isFirstLaunch + } } diff --git a/Example/Sources/View Controllers/SettingsViewController.swift b/Example/Sources/View Controllers/SettingsViewController.swift index f1c6a214..882e0f9e 100644 --- a/Example/Sources/View Controllers/SettingsViewController.swift +++ b/Example/Sources/View Controllers/SettingsViewController.swift @@ -30,12 +30,12 @@ final internal class SettingsViewController: UITableViewController { // MARK: - Properties - var selectedMockMessagesCount: Int = 20 - override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } + let cells = ["Mock messages count", "Text Messages", "AttributedText Messages", "Photo Messages", "Video Messages", "Emoji Messages", "Location Messages", "Url Messages", "Phone Messages"] + // MARK: - Picker var messagesPicker = UIPickerView() @@ -55,6 +55,8 @@ final internal class SettingsViewController: UITableViewController { messagesPicker.dataSource = self messagesPicker.delegate = self messagesPicker.backgroundColor = .white + + messagesPicker.selectRow(UserDefaults.standard.mockMessagesCount(), inComponent: 0, animated: false) } // MARK: - Toolbar @@ -82,12 +84,25 @@ final internal class SettingsViewController: UITableViewController { // MARK: - TableViewDelegate & TableViewDataSource override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return 1 + return cells.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cellValue = cells[indexPath.row] + let cell = tableView.dequeueReusableCell(withIdentifier: "cell") ?? UITableViewCell() + cell.textLabel?.text = cells[indexPath.row] - return indexPath.row == 0 ? configureTextFieldTableViewCell(at: indexPath) : UITableViewCell() + switch cellValue { + case "Mock messages count": + return configureTextFieldTableViewCell(at: indexPath) + default: + let switchView = UISwitch(frame: .zero) + switchView.isOn = UserDefaults.standard.bool(forKey: cellValue) + switchView.tag = indexPath.row + switchView.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged) + cell.accessoryView = switchView + } + return cell } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { @@ -118,6 +133,12 @@ final internal class SettingsViewController: UITableViewController { } return TextFieldTableViewCell() } + + @objc func switchChanged(_ sender: UISwitch!) { + let cell = cells[sender.tag] + + UserDefaults.standard.set(sender.isOn, forKey: cell) + } } // MARK: - UIPickerViewDelegate, UIPickerViewDataSource @@ -134,8 +155,4 @@ extension SettingsViewController: UIPickerViewDelegate, UIPickerViewDataSource { func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { return "\(row)" } - - func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { - selectedMockMessagesCount = row - } } diff --git a/README.md b/README.md index da37ba31..55b22a7b 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ github "MessageKit/MessageKit" ## Contributing Great! Look over these things first. -- Please read our [Code of Conduct](https://github.com/MessageKit/MessageKit/blob/master/Code_of_Conduct.md) +- Please read our [Code of Conduct](https://github.com/MessageKit/MessageKit/blob/master/CODE_OF_CONDUCT.md) - Check the [Contributing Guide Lines](https://github.com/MessageKit/MessageKit/blob/master/CONTRIBUTING.md). - Come join us on [Slack](https://join.slack.com/t/messagekit/shared_invite/MjI4NzIzNzMyMzU0LTE1MDMwODIzMDUtYzllYzIyNTU4MA) and 🗣 don't be a stranger. - Check out the [current issues](https://github.com/MessageKit/MessageKit/issues) and see if you can tackle any of those. diff --git a/Sources/Controllers/MessagesViewController.swift b/Sources/Controllers/MessagesViewController.swift index 545fedda..ff43ffeb 100644 --- a/Sources/Controllers/MessagesViewController.swift +++ b/Sources/Controllers/MessagesViewController.swift @@ -181,6 +181,8 @@ UICollectionViewDelegateFlowLayout, UICollectionViewDataSource { return collectionView.messagesDataSource?.numberOfItems(inSection: section, in: collectionView) ?? 0 } + /// Note: + /// If you override this method, remember to call MessagesDataSource's customCell(for:at:in:) for MessageKind.custom messages, if necessary open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let messagesCollectionView = collectionView as? MessagesCollectionView else { @@ -207,7 +209,7 @@ UICollectionViewDelegateFlowLayout, UICollectionViewDataSource { cell.configure(with: message, at: indexPath, and: messagesCollectionView) return cell case .custom: - fatalError(MessageKitError.customDataUnresolvedCell) + return messagesDataSource.customCell(for: message, at: indexPath, in: messagesCollectionView) } } diff --git a/Sources/Layout/MessageSizeCalculator.swift b/Sources/Layout/MessageSizeCalculator.swift index 02b12b75..f83f826e 100644 --- a/Sources/Layout/MessageSizeCalculator.swift +++ b/Sources/Layout/MessageSizeCalculator.swift @@ -132,7 +132,7 @@ open class MessageSizeCalculator: CellSizeCalculator { // MARK: - Avatar - public func avatarPosition(for message: MessageType) -> AvatarPosition { + open func avatarPosition(for message: MessageType) -> AvatarPosition { let dataSource = messagesLayout.messagesDataSource let isFromCurrentSender = dataSource.isFromCurrentSender(message: message) var position = isFromCurrentSender ? outgoingAvatarPosition : incomingAvatarPosition @@ -146,7 +146,7 @@ open class MessageSizeCalculator: CellSizeCalculator { return position } - public func avatarSize(for message: MessageType) -> CGSize { + open func avatarSize(for message: MessageType) -> CGSize { let dataSource = messagesLayout.messagesDataSource let isFromCurrentSender = dataSource.isFromCurrentSender(message: message) return isFromCurrentSender ? outgoingAvatarSize : incomingAvatarSize @@ -154,14 +154,14 @@ open class MessageSizeCalculator: CellSizeCalculator { // MARK: - Top cell Label - public func cellTopLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize { + open func cellTopLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize { let layoutDelegate = messagesLayout.messagesLayoutDelegate let collectionView = messagesLayout.messagesCollectionView let height = layoutDelegate.cellTopLabelHeight(for: message, at: indexPath, in: collectionView) return CGSize(width: messagesLayout.itemWidth, height: height) } - public func cellTopLabelAlignment(for message: MessageType) -> LabelAlignment { + open func cellTopLabelAlignment(for message: MessageType) -> LabelAlignment { let dataSource = messagesLayout.messagesDataSource let isFromCurrentSender = dataSource.isFromCurrentSender(message: message) return isFromCurrentSender ? outgoingCellTopLabelAlignment : incomingCellTopLabelAlignment @@ -169,14 +169,14 @@ open class MessageSizeCalculator: CellSizeCalculator { // MARK: - Top message Label - public func messageTopLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize { + open func messageTopLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize { let layoutDelegate = messagesLayout.messagesLayoutDelegate let collectionView = messagesLayout.messagesCollectionView let height = layoutDelegate.messageTopLabelHeight(for: message, at: indexPath, in: collectionView) return CGSize(width: messagesLayout.itemWidth, height: height) } - public func messageTopLabelAlignment(for message: MessageType) -> LabelAlignment { + open func messageTopLabelAlignment(for message: MessageType) -> LabelAlignment { let dataSource = messagesLayout.messagesDataSource let isFromCurrentSender = dataSource.isFromCurrentSender(message: message) return isFromCurrentSender ? outgoingMessageTopLabelAlignment : incomingMessageTopLabelAlignment @@ -184,14 +184,14 @@ open class MessageSizeCalculator: CellSizeCalculator { // MARK: - Bottom Label - public func messageBottomLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize { + open func messageBottomLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize { let layoutDelegate = messagesLayout.messagesLayoutDelegate let collectionView = messagesLayout.messagesCollectionView let height = layoutDelegate.messageBottomLabelHeight(for: message, at: indexPath, in: collectionView) return CGSize(width: messagesLayout.itemWidth, height: height) } - public func messageBottomLabelAlignment(for message: MessageType) -> LabelAlignment { + open func messageBottomLabelAlignment(for message: MessageType) -> LabelAlignment { let dataSource = messagesLayout.messagesDataSource let isFromCurrentSender = dataSource.isFromCurrentSender(message: message) return isFromCurrentSender ? outgoingMessageBottomLabelAlignment : incomingMessageBottomLabelAlignment @@ -213,7 +213,7 @@ open class MessageSizeCalculator: CellSizeCalculator { // MARK: - MessageContainer - public func messageContainerPadding(for message: MessageType) -> UIEdgeInsets { + open func messageContainerPadding(for message: MessageType) -> UIEdgeInsets { let dataSource = messagesLayout.messagesDataSource let isFromCurrentSender = dataSource.isFromCurrentSender(message: message) return isFromCurrentSender ? outgoingMessagePadding : incomingMessagePadding diff --git a/Sources/Layout/MessagesCollectionViewFlowLayout.swift b/Sources/Layout/MessagesCollectionViewFlowLayout.swift index 8ed6be1b..cd5fe5af 100644 --- a/Sources/Layout/MessagesCollectionViewFlowLayout.swift +++ b/Sources/Layout/MessagesCollectionViewFlowLayout.swift @@ -147,6 +147,8 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout { lazy open var videoMessageSizeCalculator = MediaMessageSizeCalculator(layout: self) lazy open var locationMessageSizeCalculator = LocationMessageSizeCalculator(layout: self) + /// - Note: + /// If you override this method, remember to call MessageLayoutDelegate's customCellSizeCalculator(for:at:in:) method for MessageKind.custom messages, if necessary open func cellSizeCalculatorForItem(at indexPath: IndexPath) -> CellSizeCalculator { let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView) switch message.kind { @@ -163,7 +165,7 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout { case .location: return locationMessageSizeCalculator case .custom: - fatalError("Must return a CellSizeCalculator for MessageKind.custom(Any?)") + return messagesLayoutDelegate.customCellSizeCalculator(for: message, at: indexPath, in: messagesCollectionView) } } diff --git a/Sources/Models/MessageKind.swift b/Sources/Models/MessageKind.swift index fc130f52..a29d76d5 100644 --- a/Sources/Models/MessageKind.swift +++ b/Sources/Models/MessageKind.swift @@ -52,9 +52,9 @@ public enum MessageKind { case emoji(String) /// A custom message. - /// - Note: Using this case requires that you override the following methods and handle this case: - /// - `collectionView(_:cellForItemAt indexPath: IndexPath) -> UICollectionViewCell` - /// - `cellSizeCalculatorForItem(at indexPath: IndexPath) -> CellSizeCalculator` + /// - Note: Using this case requires that you implement the following methods and handle this case: + /// - MessagesDataSource: customCell(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UICollectionViewCell + /// - MessagesLayoutDelegate: customCellSizeCalculator(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CellSizeCalculator case custom(Any?) // MARK: - Not supported yet diff --git a/Sources/Protocols/MessagesDataSource.swift b/Sources/Protocols/MessagesDataSource.swift index 1763a8c8..3caba08b 100644 --- a/Sources/Protocols/MessagesDataSource.swift +++ b/Sources/Protocols/MessagesDataSource.swift @@ -92,6 +92,17 @@ public protocol MessagesDataSource: AnyObject { /// /// The default value returned by this method is `nil`. func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? + + /// Custom collectionView cell for message with `custom` message type. + /// + /// - Parameters: + /// - message: The `custom` message type + /// - indexPath: The `IndexPath` of the cell. + /// - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed. + /// + /// - Note: + /// This method will call fatalError() on default. You must override this method if you are using MessageType.custom messages. + func customCell(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UICollectionViewCell } public extension MessagesDataSource { @@ -115,4 +126,8 @@ public extension MessagesDataSource { func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? { return nil } + + func customCell(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UICollectionViewCell { + fatalError(MessageKitError.customDataUnresolvedCell) + } } diff --git a/Sources/Protocols/MessagesLayoutDelegate.swift b/Sources/Protocols/MessagesLayoutDelegate.swift index 24a13c7a..4dd75743 100644 --- a/Sources/Protocols/MessagesLayoutDelegate.swift +++ b/Sources/Protocols/MessagesLayoutDelegate.swift @@ -80,6 +80,17 @@ public protocol MessagesLayoutDelegate: AnyObject { /// - Note: /// The default value returned by this method is zero. func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat + + /// Custom cell size calculator for messages with MessageType.custom. + /// + /// - Parameters: + /// - message: The custom message + /// - indexPath: The `IndexPath` of the cell. + /// - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed. + /// + /// - Note: + /// The default implementation will throw fatalError(). You must override this method if you are using messages with MessageType.custom. + func customCellSizeCalculator(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CellSizeCalculator } public extension MessagesLayoutDelegate { @@ -103,4 +114,8 @@ public extension MessagesLayoutDelegate { func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat { return 0 } + + func customCellSizeCalculator(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CellSizeCalculator { + fatalError("Must return a CellSizeCalculator for MessageKind.custom(Any?)") + } }