From 7788a1e231b720a1bb91eddebbeb0c61aab0153d Mon Sep 17 00:00:00 2001 From: Steven Deutsch Date: Sat, 16 Sep 2017 17:59:39 -0500 Subject: [PATCH] Add MediaMessageCell --- Example/Sources/MockMessage.swift | 4 ++ Example/Sources/SampleData.swift | 2 +- MessageKit.xcodeproj/project.pbxproj | 4 ++ Sources/MediaMessageCell.swift | 39 +++++++++++++++++++ Sources/MessageCollectionViewCell.swift | 11 +++++- Sources/MessageData.swift | 7 ++-- .../MessagesCollectionViewFlowLayout.swift | 4 ++ Sources/MessagesViewController.swift | 11 ++++++ Sources/TextMessageCell.swift | 20 ++-------- 9 files changed, 79 insertions(+), 23 deletions(-) create mode 100644 Sources/MediaMessageCell.swift diff --git a/Example/Sources/MockMessage.swift b/Example/Sources/MockMessage.swift index d8d36c62..15767d80 100644 --- a/Example/Sources/MockMessage.swift +++ b/Example/Sources/MockMessage.swift @@ -46,5 +46,9 @@ struct MockMessage: MessageType { init(attributedText: NSAttributedString, sender: Sender, messageId: String) { self.init(data: .attributedText(attributedText), sender: sender, messageId: messageId) } + + init(image: UIImage, sender: Sender, messageId: String) { + self.init(data: .photo(image), sender: sender, messageId: messageId) + } } diff --git a/Example/Sources/SampleData.swift b/Example/Sources/SampleData.swift index 3ab63229..4d566dc9 100644 --- a/Example/Sources/SampleData.swift +++ b/Example/Sources/SampleData.swift @@ -34,7 +34,7 @@ struct SampleData { let msg1 = MockMessage(text: "Check out this awesome UI library for Chat", sender: Dan, messageId: UUID().uuidString) var msg2 = MockMessage(text: "This is insane.", sender: Steven, messageId: UUID().uuidString) - var msg3 = MockMessage(text: "Companies that get confused, that think their goal is revenue or stock price or something. You have to focus on the things that lead to those.", sender: Dan, messageId: UUID().uuidString) + var msg3 = MockMessage(image: #imageLiteral(resourceName: "Steve-Jobs"), sender: Jobs, messageId: UUID().uuidString) var msg4 = MockMessage(text: "My favorite things in life don’t cost any money. It’s really clear that the most precious resource we all have is time.", sender: Jobs, messageId: UUID().uuidString) var msg5 = MockMessage(text: "You know, this iPhone, as a matter of fact, the engine in here is made in America. And not only are the engines in here made in America, but engines are made in America and are exported. The glass on this phone is made in Kentucky. And so we've been working for years on doing more and more in the United States.", sender: Dan, messageId: UUID().uuidString) var msg6 = MockMessage(text: "I think if you do something and it turns out pretty good, then you should go do something else wonderful, not dwell on it for too long. Just figure out what’s next.", sender: Jobs, messageId: UUID().uuidString) diff --git a/MessageKit.xcodeproj/project.pbxproj b/MessageKit.xcodeproj/project.pbxproj index 844ff41c..458aacfe 100644 --- a/MessageKit.xcodeproj/project.pbxproj +++ b/MessageKit.xcodeproj/project.pbxproj @@ -68,6 +68,7 @@ B09643901F289142004D0129 /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B096438F1F289142004D0129 /* UIColor+Extensions.swift */; }; B0AA1F511F42E91A00BAE583 /* AvatarAlignment.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0AA1F501F42E91A00BAE583 /* AvatarAlignment.swift */; }; B0AA1F531F44388C00BAE583 /* NSAttributedString+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0AA1F521F44388900BAE583 /* NSAttributedString+Extensions.swift */; }; + B0D943BE1F6DC9AB008B7BFD /* MediaMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0D943BD1F6DC9AB008B7BFD /* MediaMessageCell.swift */; }; B0E1756F1F655A1600F0DEF6 /* AvatarHorizontalAlignment.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0E1756E1F655A1600F0DEF6 /* AvatarHorizontalAlignment.swift */; }; E8586DB51F59A1C300C9BE9D /* MessageContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8586DB41F59A1C300C9BE9D /* MessageContainerView.swift */; }; /* End PBXBuildFile section */ @@ -147,6 +148,7 @@ B096438F1F289142004D0129 /* UIColor+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Extensions.swift"; sourceTree = ""; }; B0AA1F501F42E91A00BAE583 /* AvatarAlignment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarAlignment.swift; sourceTree = ""; }; B0AA1F521F44388900BAE583 /* NSAttributedString+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+Extensions.swift"; sourceTree = ""; }; + B0D943BD1F6DC9AB008B7BFD /* MediaMessageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaMessageCell.swift; sourceTree = ""; }; B0E1756E1F655A1600F0DEF6 /* AvatarHorizontalAlignment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarHorizontalAlignment.swift; sourceTree = ""; }; E8586DB41F59A1C300C9BE9D /* MessageContainerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageContainerView.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -302,6 +304,7 @@ E8586DB41F59A1C300C9BE9D /* MessageContainerView.swift */, B0147C8F1F5ED0810035B36E /* MessageDateHeaderView.swift */, B0291DA81F6DBB9F00BEDF03 /* TextMessageCell.swift */, + B0D943BD1F6DC9AB008B7BFD /* MediaMessageCell.swift */, ); name = Views; sourceTree = ""; @@ -525,6 +528,7 @@ B05530B51F493CFA008BB420 /* DetectorType.swift in Sources */, B01E2DD81F5BBDB800E4FA1C /* MessageStyle.swift in Sources */, 88916B471CF0DFE600469F91 /* MessageType.swift in Sources */, + B0D943BE1F6DC9AB008B7BFD /* MediaMessageCell.swift in Sources */, B0291DA91F6DBB9F00BEDF03 /* TextMessageCell.swift in Sources */, B0AA1F511F42E91A00BAE583 /* AvatarAlignment.swift in Sources */, B03FF9AF1F31BB1200754FE5 /* MessageCellDelegate.swift in Sources */, diff --git a/Sources/MediaMessageCell.swift b/Sources/MediaMessageCell.swift new file mode 100644 index 00000000..b00c3af7 --- /dev/null +++ b/Sources/MediaMessageCell.swift @@ -0,0 +1,39 @@ +/* + 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 UIKit + +open class MediaMessageCell: MessageCollectionViewCell { + + override open func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) { + super.configure(with: message, at: indexPath, and: messagesCollectionView) + switch message.data { + case .photo(let image): + messageContentView.image = image + default: + break + } + } + +} diff --git a/Sources/MessageCollectionViewCell.swift b/Sources/MessageCollectionViewCell.swift index ed36bfe3..55bb9a3f 100644 --- a/Sources/MessageCollectionViewCell.swift +++ b/Sources/MessageCollectionViewCell.swift @@ -38,7 +38,13 @@ open class MessageCollectionViewCell: UICollectionViewCell return topLabel }() - open var messageContentView = ContentView() + open var messageContentView: ContentView = { + let contentView = ContentView() + contentView.clipsToBounds = true + contentView.layer.masksToBounds = true + contentView.isUserInteractionEnabled = true + return contentView + }() open var cellBottomLabel: MessageLabel = { let bottomLabel = MessageLabel() @@ -56,6 +62,7 @@ open class MessageCollectionViewCell: UICollectionViewCell super.init(frame: frame) setupSubviews() setupGestureRecognizers() + contentView.backgroundColor = .purple contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] } @@ -69,7 +76,7 @@ open class MessageCollectionViewCell: UICollectionViewCell contentView.addSubview(cellTopLabel) contentView.addSubview(messageContainerView) - messageContainerView.addSubview(messageContentView) + //messageContainerView.addSubview(messageContentView) contentView.addSubview(avatarView) contentView.addSubview(cellBottomLabel) diff --git a/Sources/MessageData.swift b/Sources/MessageData.swift index 4aa448c2..0bd9f0c3 100644 --- a/Sources/MessageData.swift +++ b/Sources/MessageData.swift @@ -29,16 +29,15 @@ public enum MessageData { case text(String) case attributedText(NSAttributedString) + case photo(UIImage) + // case video(file: NSURL, thumbnail: UIImage) // MARK: - Not supported yet // case audio(Data) // // case location(CLLocation) -// -// case photo(UIImage) -// -// case video(file: NSURL, thumbnail: UIImage) +// // // case system(String) // diff --git a/Sources/MessagesCollectionViewFlowLayout.swift b/Sources/MessagesCollectionViewFlowLayout.swift index 3a23b8f1..ec648a72 100644 --- a/Sources/MessagesCollectionViewFlowLayout.swift +++ b/Sources/MessagesCollectionViewFlowLayout.swift @@ -23,6 +23,7 @@ */ import UIKit +import AVFoundation open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout { @@ -294,6 +295,9 @@ extension MessagesCollectionViewFlowLayout { messageContainerSize = labelSize(for: text, considering: maxWidth, and: messageLabelFont) case .attributedText(let text): messageContainerSize = labelSize(for: text, considering: maxWidth) + case .photo(let image): + let boundingRect = CGRect(origin: .zero, size: CGSize(width: maxWidth, height: .greatestFiniteMagnitude)) + messageContainerSize = AVMakeRect(aspectRatio: image.size, insideRect: boundingRect).size } messageContainerSize.width += messageHorizontalInsets diff --git a/Sources/MessagesViewController.swift b/Sources/MessagesViewController.swift index ebf090ee..192a3204 100644 --- a/Sources/MessagesViewController.swift +++ b/Sources/MessagesViewController.swift @@ -91,9 +91,13 @@ open class MessagesViewController: UIViewController { } private func registerReusableViews() { + messagesCollectionView.register(TextMessageCell.self, forCellWithReuseIdentifier: "TextMessageCell") + messagesCollectionView.register(MediaMessageCell.self, + forCellWithReuseIdentifier: "MediaMessageCell") + messagesCollectionView.register(MessageFooterView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: "MessageFooterView") @@ -105,6 +109,7 @@ open class MessagesViewController: UIViewController { messagesCollectionView.register(MessageDateHeaderView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "MessageDateHeaderView") + } private func setupSubviews() { @@ -195,6 +200,12 @@ extension MessagesViewController: UICollectionViewDataSource { } cell.configure(with: message, at: indexPath, and: messagesCollectionView) return cell + case .photo: + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MediaMessageCell", for: indexPath) as? MediaMessageCell else { + fatalError("Unable to dequeue MediaMessageCell") + } + cell.configure(with: message, at: indexPath, and: messagesCollectionView) + return cell } } diff --git a/Sources/TextMessageCell.swift b/Sources/TextMessageCell.swift index 13977147..18e0aa63 100644 --- a/Sources/TextMessageCell.swift +++ b/Sources/TextMessageCell.swift @@ -46,27 +46,13 @@ open class TextMessageCell: MessageCollectionViewCell { super.apply(layoutAttributes) guard let attributes = layoutAttributes as? MessagesCollectionViewLayoutAttributes else { return } - - avatarView.frame = attributes.avatarFrame - - messageContainerView.frame = attributes.messageContainerFrame - messageContentView.frame = CGRect(origin: .zero, size: attributes.messageContainerFrame.size) messageContentView.textInsets = attributes.messageLabelInsets - - cellTopLabel.frame = attributes.cellTopLabelFrame - cellTopLabel.textInsets = attributes.cellTopLabelInsets - - cellBottomLabel.frame = attributes.cellBottomLabelFrame - cellBottomLabel.textInsets = attributes.cellBottomLabelInsets - } override open func prepareForReuse() { super.prepareForReuse() - cellTopLabel.text = nil - cellTopLabel.attributedText = nil - cellBottomLabel.text = nil - cellBottomLabel.attributedText = nil + messageContentView.attributedText = nil + messageContentView.text = nil } override public func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) { @@ -82,6 +68,8 @@ open class TextMessageCell: MessageCollectionViewCell { messageContentView.text = text case .attributedText(let text): messageContentView.attributedText = text + default: + break } }