diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 150ea00f..cbce23e4 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - MessageKit (0.10.1) + - MessageKit (0.10.2) DEPENDENCIES: - MessageKit (from `../MessageKit.podspec`) @@ -9,7 +9,7 @@ EXTERNAL SOURCES: :path: ../MessageKit.podspec SPEC CHECKSUMS: - MessageKit: b0cd905fa1872952f25ff5ea8e67d7135fe7e176 + MessageKit: a1e8d0f1d7785891e4b37f6252898f23cd8f8b6a PODFILE CHECKSUM: 9ac65b8dedf0e1b63fea245b089b6645c4e66309 diff --git a/Example/Sources/ConversationViewController.swift b/Example/Sources/ConversationViewController.swift index c6a58c8c..894a1e31 100644 --- a/Example/Sources/ConversationViewController.swift +++ b/Example/Sources/ConversationViewController.swift @@ -234,7 +234,9 @@ extension ConversationViewController: MessagesDataSource { // MARK: - MessagesDisplayDelegate -extension ConversationViewController: MessagesDisplayDelegate, TextMessageDisplayDelegate { +extension ConversationViewController: MessagesDisplayDelegate { + + // MARK: - All Messages func backgroundColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor { return isFromCurrentSender(message: message) ? UIColor(red: 69/255, green: 193/255, blue: 89/255, alpha: 1) : UIColor(red: 230/255, green: 230/255, blue: 230/255, alpha: 1) @@ -251,6 +253,28 @@ extension ConversationViewController: MessagesDisplayDelegate, TextMessageDispla // return .custom(configurationClosure) } + // MARK: - Location Messages + + func annotationViewForLocation(message: MessageType, at indexPath: IndexPath, in messageCollectionView: MessagesCollectionView) -> MKAnnotationView? { + let annotationView = MKAnnotationView(annotation: nil, reuseIdentifier: nil) + let pinImage = #imageLiteral(resourceName: "pin") + annotationView.image = pinImage + annotationView.centerOffset = CGPoint(x: 0, y: -pinImage.size.height / 2) + return annotationView + } + + func animationBlockForLocation(message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> ((UIImageView) -> Void)? { + return { view in + view.layer.transform = CATransform3DMakeScale(0, 0, 0) + view.alpha = 0.0 + UIView.animate(withDuration: 0.6, delay: 0, usingSpringWithDamping: 0.9, initialSpringVelocity: 0, options: [], animations: { + view.layer.transform = CATransform3DIdentity + view.alpha = 1.0 + }, completion: nil) + } + } + + } // MARK: - MessagesLayoutDelegate @@ -286,11 +310,7 @@ extension ConversationViewController: MessagesLayoutDelegate { return CGSize(width: messagesCollectionView.bounds.width, height: 10) } -} - -// MARK: - LocationMessageLayoutDelegate - -extension ConversationViewController: LocationMessageLayoutDelegate { + // MARK: - Location Messages func heightForLocation(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat { return 200 @@ -298,10 +318,6 @@ extension ConversationViewController: LocationMessageLayoutDelegate { } -// MARK: - MediaMessageLayoutDelegate - -extension ConversationViewController: MediaMessageLayoutDelegate {} - // MARK: - MessageCellDelegate extension ConversationViewController: MessageCellDelegate { @@ -346,31 +362,6 @@ extension ConversationViewController: MessageLabelDelegate { } -// MARK: - LocationMessageDisplayDelegate - -extension ConversationViewController: LocationMessageDisplayDelegate { - - func annotationViewForLocation(message: MessageType, at indexPath: IndexPath, in messageCollectionView: MessagesCollectionView) -> MKAnnotationView? { - let annotationView = MKAnnotationView(annotation: nil, reuseIdentifier: nil) - let pinImage = #imageLiteral(resourceName: "pin") - annotationView.image = pinImage - annotationView.centerOffset = CGPoint(x: 0, y: -pinImage.size.height / 2) - return annotationView - } - - func animationBlockForLocation(message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> ((UIImageView) -> Void)? { - return { view in - view.layer.transform = CATransform3DMakeScale(0, 0, 0) - view.alpha = 0.0 - UIView.animate(withDuration: 0.6, delay: 0, usingSpringWithDamping: 0.9, initialSpringVelocity: 0, options: [], animations: { - view.layer.transform = CATransform3DIdentity - view.alpha = 1.0 - }, completion: nil) - } - } - -} - // MARK: - MessageInputBarDelegate extension ConversationViewController: MessageInputBarDelegate { diff --git a/MessageKit.xcodeproj/project.pbxproj b/MessageKit.xcodeproj/project.pbxproj index 9eac4004..f97fd29a 100644 --- a/MessageKit.xcodeproj/project.pbxproj +++ b/MessageKit.xcodeproj/project.pbxproj @@ -55,16 +55,13 @@ B7A03F4C1F86694F006AEF79 /* PlayButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7A03F441F86694F006AEF79 /* PlayButtonView.swift */; }; B7A03F4D1F86694F006AEF79 /* MessagesCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7A03F451F86694F006AEF79 /* MessagesCollectionView.swift */; }; B7A03F4F1F86697C006AEF79 /* MessagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7A03F4E1F86697C006AEF79 /* MessagesViewController.swift */; }; - B7A03F5A1F8669CA006AEF79 /* MediaMessageLayoutDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7A03F501F8669C9006AEF79 /* MediaMessageLayoutDelegate.swift */; }; B7A03F5B1F8669CA006AEF79 /* MessageType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7A03F511F8669C9006AEF79 /* MessageType.swift */; }; B7A03F5C1F8669CA006AEF79 /* MessageCellDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7A03F521F8669C9006AEF79 /* MessageCellDelegate.swift */; }; - B7A03F5D1F8669CA006AEF79 /* LocationMessageDisplayDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7A03F531F8669C9006AEF79 /* LocationMessageDisplayDelegate.swift */; }; B7A03F5E1F8669CA006AEF79 /* MessagesLayoutDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7A03F541F8669C9006AEF79 /* MessagesLayoutDelegate.swift */; }; B7A03F5F1F8669CA006AEF79 /* MessageLabelDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7A03F551F8669C9006AEF79 /* MessageLabelDelegate.swift */; }; B7A03F601F8669CA006AEF79 /* MessagesDisplayDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7A03F561F8669C9006AEF79 /* MessagesDisplayDelegate.swift */; }; B7A03F611F8669CA006AEF79 /* MessagesDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7A03F571F8669CA006AEF79 /* MessagesDataSource.swift */; }; B7A03F621F8669CA006AEF79 /* MessageInputBarDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7A03F581F8669CA006AEF79 /* MessageInputBarDelegate.swift */; }; - B7A03F631F8669CA006AEF79 /* LocationMessageLayoutDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7A03F591F8669CA006AEF79 /* LocationMessageLayoutDelegate.swift */; }; B7A03F6A1F8669EB006AEF79 /* UICollectionView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7A03F641F8669EB006AEF79 /* UICollectionView+Extensions.swift */; }; B7A03F6B1F8669EB006AEF79 /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7A03F651F8669EB006AEF79 /* UIColor+Extensions.swift */; }; B7A03F6C1F8669EB006AEF79 /* UIView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7A03F661F8669EB006AEF79 /* UIView+Extensions.swift */; }; @@ -137,16 +134,13 @@ B7A03F441F86694F006AEF79 /* PlayButtonView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlayButtonView.swift; sourceTree = ""; }; B7A03F451F86694F006AEF79 /* MessagesCollectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagesCollectionView.swift; sourceTree = ""; }; B7A03F4E1F86697C006AEF79 /* MessagesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagesViewController.swift; sourceTree = ""; }; - B7A03F501F8669C9006AEF79 /* MediaMessageLayoutDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaMessageLayoutDelegate.swift; sourceTree = ""; }; B7A03F511F8669C9006AEF79 /* MessageType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageType.swift; sourceTree = ""; }; B7A03F521F8669C9006AEF79 /* MessageCellDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageCellDelegate.swift; sourceTree = ""; }; - B7A03F531F8669C9006AEF79 /* LocationMessageDisplayDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationMessageDisplayDelegate.swift; sourceTree = ""; }; B7A03F541F8669C9006AEF79 /* MessagesLayoutDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagesLayoutDelegate.swift; sourceTree = ""; }; B7A03F551F8669C9006AEF79 /* MessageLabelDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageLabelDelegate.swift; sourceTree = ""; }; B7A03F561F8669C9006AEF79 /* MessagesDisplayDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagesDisplayDelegate.swift; sourceTree = ""; }; B7A03F571F8669CA006AEF79 /* MessagesDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagesDataSource.swift; sourceTree = ""; }; B7A03F581F8669CA006AEF79 /* MessageInputBarDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageInputBarDelegate.swift; sourceTree = ""; }; - B7A03F591F8669CA006AEF79 /* LocationMessageLayoutDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationMessageLayoutDelegate.swift; sourceTree = ""; }; B7A03F641F8669EB006AEF79 /* UICollectionView+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UICollectionView+Extensions.swift"; sourceTree = ""; }; B7A03F651F8669EB006AEF79 /* UIColor+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Extensions.swift"; sourceTree = ""; }; B7A03F661F8669EB006AEF79 /* UIView+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Extensions.swift"; sourceTree = ""; }; @@ -366,9 +360,6 @@ B096439B1F295D82004D0129 /* Protocols */ = { isa = PBXGroup; children = ( - B7A03F531F8669C9006AEF79 /* LocationMessageDisplayDelegate.swift */, - B7A03F591F8669CA006AEF79 /* LocationMessageLayoutDelegate.swift */, - B7A03F501F8669C9006AEF79 /* MediaMessageLayoutDelegate.swift */, B7A03F521F8669C9006AEF79 /* MessageCellDelegate.swift */, B7A03F581F8669CA006AEF79 /* MessageInputBarDelegate.swift */, B7A03F551F8669C9006AEF79 /* MessageLabelDelegate.swift */, @@ -546,10 +537,8 @@ B006FA021F99DE2100509C46 /* MessageIntermediateLayoutAttributes.swift in Sources */, B7A03F4B1F86694F006AEF79 /* MessageContainerView.swift in Sources */, B7A03F281F866895006AEF79 /* LocationMessageSnapshotOptions.swift in Sources */, - B7A03F5D1F8669CA006AEF79 /* LocationMessageDisplayDelegate.swift in Sources */, B7A03F481F86694F006AEF79 /* InputTextView.swift in Sources */, B7A03F6C1F8669EB006AEF79 /* UIView+Extensions.swift in Sources */, - B7A03F631F8669CA006AEF79 /* LocationMessageLayoutDelegate.swift in Sources */, B7A03F3A1F866946006AEF79 /* TextMessageCell.swift in Sources */, B7A03F191F86682C006AEF79 /* MessagesCollectionViewLayoutAttributes.swift in Sources */, B7A03F461F86694F006AEF79 /* AvatarView.swift in Sources */, @@ -569,7 +558,6 @@ B7A03F471F86694F006AEF79 /* MessageLabel.swift in Sources */, B7A03F5F1F8669CA006AEF79 /* MessageLabelDelegate.swift in Sources */, B7A03F4C1F86694F006AEF79 /* PlayButtonView.swift in Sources */, - B7A03F5A1F8669CA006AEF79 /* MediaMessageLayoutDelegate.swift in Sources */, B7A03F291F866895006AEF79 /* Sender.swift in Sources */, B7A03F4F1F86697C006AEF79 /* MessagesViewController.swift in Sources */, B7A03F251F866895006AEF79 /* NSConstraintLayoutSet.swift in Sources */, diff --git a/Sources/Layout/MessagesCollectionViewFlowLayout.swift b/Sources/Layout/MessagesCollectionViewFlowLayout.swift index 07988470..f8a9371c 100644 --- a/Sources/Layout/MessagesCollectionViewFlowLayout.swift +++ b/Sources/Layout/MessagesCollectionViewFlowLayout.swift @@ -429,18 +429,12 @@ private extension MessagesCollectionViewFlowLayout { messageContainerSize.width += attributes.messageLabelHorizontalInsets messageContainerSize.height += attributes.messageLabelVerticalInsets case .photo, .video: - guard let layoutDelegate = messagesLayoutDelegate as? MediaMessageLayoutDelegate else { - fatalError("Layout object attempting to size media message type and MediaMessageLayoutDelegate is not set.") - } - let width = layoutDelegate.widthForMedia(message: message, at: indexPath, with: maxWidth, in: messagesCollectionView) - let height = layoutDelegate.heightForMedia(message: message, at: indexPath, with: maxWidth, in: messagesCollectionView) + 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: - guard let layoutDelegate = messagesLayoutDelegate as? LocationMessageLayoutDelegate else { - fatalError("Layout object attempting to size location message type and LocationMessageLayoutDelegate is not set.") - } - let width = layoutDelegate.widthForLocation(message: message, at: indexPath, with: maxWidth, in: messagesCollectionView) - let height = layoutDelegate.heightForLocation(message: message, at: indexPath, with: maxWidth, in: messagesCollectionView) + 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) } diff --git a/Sources/Protocols/LocationMessageDisplayDelegate.swift b/Sources/Protocols/LocationMessageDisplayDelegate.swift deleted file mode 100644 index 54cdb6a9..00000000 --- a/Sources/Protocols/LocationMessageDisplayDelegate.swift +++ /dev/null @@ -1,80 +0,0 @@ -/* - MIT License - - Copyright (c) 2017 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 -import MapKit - -/// Conform to this protocol to customize location messages's style -public protocol LocationMessageDisplayDelegate: MessagesDisplayDelegate { - - /// Ask the delegate for a LocationMessageSnapshotOptions instance to customize the MapView on the given 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 - 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 - /// - /// - 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. - 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 - /// - /// - 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. - func animationBlockForLocation(message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> ((UIImageView) -> Void)? - -} - -public extension LocationMessageDisplayDelegate { - - func snapshotOptionsForLocation(message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> LocationMessageSnapshotOptions { - return LocationMessageSnapshotOptions() - } - - func annotationViewForLocation(message: MessageType, at indexPath: IndexPath, in messageCollectionView: MessagesCollectionView) -> MKAnnotationView? { - return MKPinAnnotationView(annotation: nil, reuseIdentifier: nil) - } - - func animationBlockForLocation(message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> ((UIImageView) -> Void)? { - return nil - } - -} diff --git a/Sources/Protocols/LocationMessageLayoutDelegate.swift b/Sources/Protocols/LocationMessageLayoutDelegate.swift deleted file mode 100644 index 8bd54b70..00000000 --- a/Sources/Protocols/LocationMessageLayoutDelegate.swift +++ /dev/null @@ -1,59 +0,0 @@ -/* - MIT License - - Copyright (c) 2017 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 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 - -} - -public extension LocationMessageLayoutDelegate { - - func widthForLocation(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat { - return maxWidth - } - -} diff --git a/Sources/Protocols/MediaMessageLayoutDelegate.swift b/Sources/Protocols/MediaMessageLayoutDelegate.swift deleted file mode 100644 index 4ec18af6..00000000 --- a/Sources/Protocols/MediaMessageLayoutDelegate.swift +++ /dev/null @@ -1,72 +0,0 @@ -/* - MIT License - - Copyright (c) 2017 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 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 - -} - -public extension MediaMessageLayoutDelegate { - - 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 - } - } - -} diff --git a/Sources/Protocols/MessageInputBarDelegate.swift b/Sources/Protocols/MessageInputBarDelegate.swift index 6c1e57a0..013846f6 100644 --- a/Sources/Protocols/MessageInputBarDelegate.swift +++ b/Sources/Protocols/MessageInputBarDelegate.swift @@ -23,7 +23,6 @@ */ import Foundation -import UIKit /// MessageInputBarDelegate is a protocol that can recieve notifications from the MessageInputBar public protocol MessageInputBarDelegate: AnyObject { diff --git a/Sources/Protocols/MessagesDisplayDelegate.swift b/Sources/Protocols/MessagesDisplayDelegate.swift index ed314071..e53ecb61 100644 --- a/Sources/Protocols/MessagesDisplayDelegate.swift +++ b/Sources/Protocols/MessagesDisplayDelegate.swift @@ -23,52 +23,13 @@ */ import Foundation - -/// A protocol used by the `MessagesViewController` to customize the appearance of a `TextMessageCell`. -public protocol TextMessageDisplayDelegate: 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. - /// - 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] - -} - -public extension TextMessageDisplayDelegate { - - func textColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor { - guard let dataSource = messagesCollectionView.messagesDataSource else { return .darkText } - return dataSource.isFromCurrentSender(message: message) ? .white : .darkText - } - - func enabledDetectors(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> [DetectorType] { - return [] - } - -} +import MapKit /// A protocol used by the `MessagesViewController` to customize the appearance of a `MessagesCollectionViewCell`. public protocol MessagesDisplayDelegate: AnyObject { + // MARK: - All Messages + /// Specifies the `MessageStyle` to be used for a `MessageContainerView`. /// /// - Parameters: @@ -123,10 +84,74 @@ public protocol MessagesDisplayDelegate: AnyObject { /// The default value returned by this method is a `MessageFooterView`. func messageFooterView(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageFooterView + // MARK: - Text Messages + + /// 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] + + // MARK: - Location Messages + + /// Ask the delegate for a LocationMessageSnapshotOptions instance to customize the MapView on the given 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 + 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 + /// + /// - 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. + 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 + /// + /// - 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. + func animationBlockForLocation(message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> ((UIImageView) -> Void)? + + } public extension MessagesDisplayDelegate { + // MARK: - All Messages Defaults + func messageStyle(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageStyle { return .bubble } @@ -162,4 +187,29 @@ public extension MessagesDisplayDelegate { return messagesCollectionView.dequeueReusableFooterView(MessageFooterView.self, for: indexPath) } + // MARK: - Text Messages Defaults + + func textColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor { + guard let dataSource = messagesCollectionView.messagesDataSource else { return .darkText } + return dataSource.isFromCurrentSender(message: message) ? .white : .darkText + } + + func enabledDetectors(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> [DetectorType] { + return [] + } + + // MARK: - Location Messages Defaults + + func snapshotOptionsForLocation(message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> LocationMessageSnapshotOptions { + return LocationMessageSnapshotOptions() + } + + func annotationViewForLocation(message: MessageType, at indexPath: IndexPath, in messageCollectionView: MessagesCollectionView) -> MKAnnotationView? { + return MKPinAnnotationView(annotation: nil, reuseIdentifier: nil) + } + + func animationBlockForLocation(message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> ((UIImageView) -> Void)? { + return nil + } + } diff --git a/Sources/Protocols/MessagesLayoutDelegate.swift b/Sources/Protocols/MessagesLayoutDelegate.swift index 5c9ed957..ad3922a3 100644 --- a/Sources/Protocols/MessagesLayoutDelegate.swift +++ b/Sources/Protocols/MessagesLayoutDelegate.swift @@ -23,24 +23,13 @@ */ 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 { - /// 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 + // MARK: - All Messages /// Specifies the padding around the `MessageContainerView` in a `MessageCollectionViewCell`. /// @@ -125,18 +114,75 @@ public protocol MessagesLayoutDelegate: AnyObject { /// 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 + + /// 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 + + // 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`. + /// + /// - 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 + } public extension MessagesLayoutDelegate { - func messageLabelInset(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets { - guard let dataSource = messagesCollectionView.messagesDataSource else { return .zero } - 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) - } - } + // MARK: - All Messages Defaults func messagePadding(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets { guard let dataSource = messagesCollectionView.messagesDataSource else { return .zero } @@ -175,6 +221,39 @@ public extension MessagesLayoutDelegate { return .zero } + // MARK: - Text Messages Defaults + + func messageLabelInset(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets { + guard let dataSource = messagesCollectionView.messagesDataSource else { return .zero } + 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) + } + } + + // 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 + } + } + + // MARK: - Location Messages Defaults + + func widthForLocation(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat { + return maxWidth + } + } diff --git a/Sources/Supporting/MessageKit+Availability.swift b/Sources/Supporting/MessageKit+Availability.swift index d26ff3df..c1fba830 100644 --- a/Sources/Supporting/MessageKit+Availability.swift +++ b/Sources/Supporting/MessageKit+Availability.swift @@ -24,6 +24,20 @@ import Foundation +// MARK: - Deprecated Protocols + +@available(*, deprecated: 0.11.0, message: "Now typealias for MessagesDisplayDelegate") +typealias LocationMessageDisplayDelegate = MessagesDisplayDelegate + +@available(*, deprecated: 0.11.0, message: "Now typealias for MessagesDisplayDelegate") +typealias TextMessageDisplayDelegate = MessagesDisplayDelegate + +@available(*, deprecated: 0.11.0, message: "Now typealias for MessagesLayoutDelegate") +typealias LocationMessageLayoutDelegate = MessagesLayoutDelegate + +@available(*, deprecated: 0.11.0, message: "Now typealias for MessagesLayoutDelegate") +typealias MediaMessageLayoutDelegate = MessagesLayoutDelegate + // MARK: - AvatarAlignment @available(*, deprecated: 0.11.0, message: "Removed in MessageKit 0.11.0. Please use AvatarPosition instead.") diff --git a/Sources/Views/Cells/LocationMessageCell.swift b/Sources/Views/Cells/LocationMessageCell.swift index 401fbe56..ef1b52e4 100644 --- a/Sources/Views/Cells/LocationMessageCell.swift +++ b/Sources/Views/Cells/LocationMessageCell.swift @@ -37,7 +37,7 @@ open class LocationMessageCell: MessageCollectionViewCell { switch message.data { case .location(let location): - guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate as? LocationMessageDisplayDelegate else { return } + guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else { return } let options = displayDelegate.snapshotOptionsForLocation(message: message, at: indexPath, in: messagesCollectionView) let annotationView = displayDelegate.annotationViewForLocation(message: message, at: indexPath, in: messagesCollectionView) let animationBlock = displayDelegate.animationBlockForLocation(message: message, at: indexPath, in: messagesCollectionView) diff --git a/Sources/Views/Cells/TextMessageCell.swift b/Sources/Views/Cells/TextMessageCell.swift index 15a796c5..d1d6d3ec 100644 --- a/Sources/Views/Cells/TextMessageCell.swift +++ b/Sources/Views/Cells/TextMessageCell.swift @@ -64,7 +64,7 @@ open class TextMessageCell: MessageCollectionViewCell { open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) { super.configure(with: message, at: indexPath, and: messagesCollectionView) - if let displayDelegate = messagesCollectionView.messagesDisplayDelegate as? TextMessageDisplayDelegate { + if let displayDelegate = messagesCollectionView.messagesDisplayDelegate { let textColor = displayDelegate.textColor(for: message, at: indexPath, in: messagesCollectionView) let detectors = displayDelegate.enabledDetectors(for: message, at: indexPath, in: messagesCollectionView) @@ -72,7 +72,6 @@ open class TextMessageCell: MessageCollectionViewCell { messageContentView.textColor = textColor messageContentView.enabledDetectors = detectors } - } switch message.data {