From 880cf8c67d2a5f2048d73c842bd60af7d74e903e Mon Sep 17 00:00:00 2001 From: Steven Deutsch Date: Wed, 21 Feb 2018 06:49:46 -0600 Subject: [PATCH 1/2] Move delegate methods to allow override --- .../MessagesViewController+DataSource.swift | 101 ------------ .../MessagesViewController+Delegate.swift | 102 ------------ .../Controllers/MessagesViewController.swift | 154 +++++++++++++++++- 3 files changed, 153 insertions(+), 204 deletions(-) delete mode 100644 Sources/Controllers/MessagesViewController+DataSource.swift delete mode 100644 Sources/Controllers/MessagesViewController+Delegate.swift diff --git a/Sources/Controllers/MessagesViewController+DataSource.swift b/Sources/Controllers/MessagesViewController+DataSource.swift deleted file mode 100644 index b1cf8286..00000000 --- a/Sources/Controllers/MessagesViewController+DataSource.swift +++ /dev/null @@ -1,101 +0,0 @@ -/* - MIT License - - Copyright (c) 2017-2018 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 - -extension MessagesViewController: UICollectionViewDataSource { - - open func numberOfSections(in collectionView: UICollectionView) -> Int { - guard let collectionView = collectionView as? MessagesCollectionView else { - fatalError(MessageKitError.notMessagesCollectionView) - } - // Each message is its own section - return collectionView.messagesDataSource?.numberOfMessages(in: collectionView) ?? 0 - } - - open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - guard let collectionView = collectionView as? MessagesCollectionView else { - fatalError(MessageKitError.notMessagesCollectionView) - } - let messageCount = collectionView.messagesDataSource?.numberOfMessages(in: collectionView) ?? 0 - // There will only ever be 1 message per section - return messageCount > 0 ? 1 : 0 - } - - open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - - guard let messagesCollectionView = collectionView as? MessagesCollectionView else { - fatalError(MessageKitError.notMessagesCollectionView) - } - - guard let messagesDataSource = messagesCollectionView.messagesDataSource else { - fatalError(MessageKitError.nilMessagesDataSource) - } - - let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView) - - switch message.data { - case .text, .attributedText, .emoji: - let cell = messagesCollectionView.dequeueReusableCell(TextMessageCell.self, for: indexPath) - cell.configure(with: message, at: indexPath, and: messagesCollectionView) - return cell - case .photo, .video: - let cell = messagesCollectionView.dequeueReusableCell(MediaMessageCell.self, for: indexPath) - cell.configure(with: message, at: indexPath, and: messagesCollectionView) - return cell - case .location: - let cell = messagesCollectionView.dequeueReusableCell(LocationMessageCell.self, for: indexPath) - cell.configure(with: message, at: indexPath, and: messagesCollectionView) - return cell - case .custom: - fatalError(MessageKitError.customDataUnresolvedCell) - } - } - - open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { - - guard let messagesCollectionView = collectionView as? MessagesCollectionView else { - fatalError(MessageKitError.notMessagesCollectionView) - } - - guard let dataSource = messagesCollectionView.messagesDataSource else { - fatalError(MessageKitError.nilMessagesDataSource) - } - - guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else { - fatalError(MessageKitError.nilMessagesDisplayDelegate) - } - - let message = dataSource.messageForItem(at: indexPath, in: messagesCollectionView) - - switch kind { - case UICollectionElementKindSectionHeader: - return displayDelegate.messageHeaderView(for: message, at: indexPath, in: messagesCollectionView) - case UICollectionElementKindSectionFooter: - return displayDelegate.messageFooterView(for: message, at: indexPath, in: messagesCollectionView) - default: - fatalError(MessageKitError.unrecognizedSectionKind) - } - } -} diff --git a/Sources/Controllers/MessagesViewController+Delegate.swift b/Sources/Controllers/MessagesViewController+Delegate.swift deleted file mode 100644 index cd0d27a1..00000000 --- a/Sources/Controllers/MessagesViewController+Delegate.swift +++ /dev/null @@ -1,102 +0,0 @@ -/* - MIT License - - Copyright (c) 2017-2018 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 - -extension MessagesViewController: UICollectionViewDelegateFlowLayout { - - open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { - guard let messagesFlowLayout = collectionViewLayout as? MessagesCollectionViewFlowLayout else { return .zero } - return messagesFlowLayout.sizeForItem(at: indexPath) - } - - open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { - - guard let messagesCollectionView = collectionView as? MessagesCollectionView else { - fatalError(MessageKitError.notMessagesCollectionView) - } - guard let dataSource = messagesCollectionView.messagesDataSource else { - fatalError(MessageKitError.nilMessagesDataSource) - } - guard let layoutDelegate = messagesCollectionView.messagesLayoutDelegate else { - fatalError(MessageKitError.nilMessagesLayoutDeleagte) - } - // Could pose a problem if subclass behaviors allows more than one item per section - let indexPath = IndexPath(item: 0, section: section) - let message = dataSource.messageForItem(at: indexPath, in: messagesCollectionView) - return layoutDelegate.headerViewSize(for: message, at: indexPath, in: messagesCollectionView) - } - - open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { - guard let messagesCollectionView = collectionView as? MessagesCollectionView else { - fatalError(MessageKitError.notMessagesCollectionView) - } - guard let dataSource = messagesCollectionView.messagesDataSource else { - fatalError(MessageKitError.nilMessagesDataSource) - } - guard let layoutDelegate = messagesCollectionView.messagesLayoutDelegate else { - fatalError(MessageKitError.nilMessagesLayoutDeleagte) - } - // Could pose a problem if subclass behaviors allows more than one item per section - let indexPath = IndexPath(item: 0, section: section) - let message = dataSource.messageForItem(at: indexPath, in: messagesCollectionView) - return layoutDelegate.footerViewSize(for: message, at: indexPath, in: messagesCollectionView) - } - - open func collectionView(_ collectionView: UICollectionView, shouldShowMenuForItemAt indexPath: IndexPath) -> Bool { - guard let messagesDataSource = messagesCollectionView.messagesDataSource else { return false } - let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView) - - switch message.data { - case .text, .attributedText, .emoji, .photo: - selectedIndexPathForMenu = indexPath - return true - default: - return false - } - } - - open func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool { - return (action == NSSelectorFromString("copy:")) - } - - open func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) { - guard let messagesDataSource = messagesCollectionView.messagesDataSource else { - fatalError(MessageKitError.nilMessagesDataSource) - } - let pasteBoard = UIPasteboard.general - let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView) - - switch message.data { - case .text(let text), .emoji(let text): - pasteBoard.string = text - case .attributedText(let attributedText): - pasteBoard.string = attributedText.string - case .photo(let image): - pasteBoard.image = image - default: - break - } - } -} diff --git a/Sources/Controllers/MessagesViewController.swift b/Sources/Controllers/MessagesViewController.swift index ed0728ac..8931753b 100644 --- a/Sources/Controllers/MessagesViewController.swift +++ b/Sources/Controllers/MessagesViewController.swift @@ -24,7 +24,8 @@ import UIKit -open class MessagesViewController: UIViewController { +open class MessagesViewController: UIViewController, +UICollectionViewDelegateFlowLayout, UICollectionViewDataSource { // MARK: - Properties [Public] @@ -149,4 +150,155 @@ open class MessagesViewController: UIViewController { NSLayoutConstraint.activate([top, bottom, trailing, leading]) } } + + // MARK: - UICollectionViewDataSource + + open func numberOfSections(in collectionView: UICollectionView) -> Int { + guard let collectionView = collectionView as? MessagesCollectionView else { + fatalError(MessageKitError.notMessagesCollectionView) + } + // Each message is its own section + return collectionView.messagesDataSource?.numberOfMessages(in: collectionView) ?? 0 + } + + open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + guard let collectionView = collectionView as? MessagesCollectionView else { + fatalError(MessageKitError.notMessagesCollectionView) + } + let messageCount = collectionView.messagesDataSource?.numberOfMessages(in: collectionView) ?? 0 + // There will only ever be 1 message per section + return messageCount > 0 ? 1 : 0 + } + + open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + + guard let messagesCollectionView = collectionView as? MessagesCollectionView else { + fatalError(MessageKitError.notMessagesCollectionView) + } + + guard let messagesDataSource = messagesCollectionView.messagesDataSource else { + fatalError(MessageKitError.nilMessagesDataSource) + } + + let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView) + + switch message.data { + case .text, .attributedText, .emoji: + let cell = messagesCollectionView.dequeueReusableCell(TextMessageCell.self, for: indexPath) + cell.configure(with: message, at: indexPath, and: messagesCollectionView) + return cell + case .photo, .video: + let cell = messagesCollectionView.dequeueReusableCell(MediaMessageCell.self, for: indexPath) + cell.configure(with: message, at: indexPath, and: messagesCollectionView) + return cell + case .location: + let cell = messagesCollectionView.dequeueReusableCell(LocationMessageCell.self, for: indexPath) + cell.configure(with: message, at: indexPath, and: messagesCollectionView) + return cell + case .custom: + fatalError(MessageKitError.customDataUnresolvedCell) + } + } + + open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { + + guard let messagesCollectionView = collectionView as? MessagesCollectionView else { + fatalError(MessageKitError.notMessagesCollectionView) + } + + guard let dataSource = messagesCollectionView.messagesDataSource else { + fatalError(MessageKitError.nilMessagesDataSource) + } + + guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else { + fatalError(MessageKitError.nilMessagesDisplayDelegate) + } + + let message = dataSource.messageForItem(at: indexPath, in: messagesCollectionView) + + switch kind { + case UICollectionElementKindSectionHeader: + return displayDelegate.messageHeaderView(for: message, at: indexPath, in: messagesCollectionView) + case UICollectionElementKindSectionFooter: + return displayDelegate.messageFooterView(for: message, at: indexPath, in: messagesCollectionView) + default: + fatalError(MessageKitError.unrecognizedSectionKind) + } + } + + // MARK: - UICollectionViewDelegateFlowLayout + + open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + guard let messagesFlowLayout = collectionViewLayout as? MessagesCollectionViewFlowLayout else { return .zero } + return messagesFlowLayout.sizeForItem(at: indexPath) + } + + open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { + + guard let messagesCollectionView = collectionView as? MessagesCollectionView else { + fatalError(MessageKitError.notMessagesCollectionView) + } + guard let dataSource = messagesCollectionView.messagesDataSource else { + fatalError(MessageKitError.nilMessagesDataSource) + } + guard let layoutDelegate = messagesCollectionView.messagesLayoutDelegate else { + fatalError(MessageKitError.nilMessagesLayoutDeleagte) + } + // Could pose a problem if subclass behaviors allows more than one item per section + let indexPath = IndexPath(item: 0, section: section) + let message = dataSource.messageForItem(at: indexPath, in: messagesCollectionView) + return layoutDelegate.headerViewSize(for: message, at: indexPath, in: messagesCollectionView) + } + + open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { + guard let messagesCollectionView = collectionView as? MessagesCollectionView else { + fatalError(MessageKitError.notMessagesCollectionView) + } + guard let dataSource = messagesCollectionView.messagesDataSource else { + fatalError(MessageKitError.nilMessagesDataSource) + } + guard let layoutDelegate = messagesCollectionView.messagesLayoutDelegate else { + fatalError(MessageKitError.nilMessagesLayoutDeleagte) + } + // Could pose a problem if subclass behaviors allows more than one item per section + let indexPath = IndexPath(item: 0, section: section) + let message = dataSource.messageForItem(at: indexPath, in: messagesCollectionView) + return layoutDelegate.footerViewSize(for: message, at: indexPath, in: messagesCollectionView) + } + + open func collectionView(_ collectionView: UICollectionView, shouldShowMenuForItemAt indexPath: IndexPath) -> Bool { + guard let messagesDataSource = messagesCollectionView.messagesDataSource else { return false } + let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView) + + switch message.data { + case .text, .attributedText, .emoji, .photo: + selectedIndexPathForMenu = indexPath + return true + default: + return false + } + } + + open func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool { + return (action == NSSelectorFromString("copy:")) + } + + open func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) { + guard let messagesDataSource = messagesCollectionView.messagesDataSource else { + fatalError(MessageKitError.nilMessagesDataSource) + } + let pasteBoard = UIPasteboard.general + let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView) + + switch message.data { + case .text(let text), .emoji(let text): + pasteBoard.string = text + case .attributedText(let attributedText): + pasteBoard.string = attributedText.string + case .photo(let image): + pasteBoard.image = image + default: + break + } + } } From 8314e69d1bc2a208720b69d475e17aeb8731050a Mon Sep 17 00:00:00 2001 From: Steven Deutsch Date: Thu, 22 Feb 2018 23:32:49 -0600 Subject: [PATCH 2/2] Fix xcproj --- MessageKit.xcodeproj/project.pbxproj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/MessageKit.xcodeproj/project.pbxproj b/MessageKit.xcodeproj/project.pbxproj index 9b4df0d6..6c9f1752 100644 --- a/MessageKit.xcodeproj/project.pbxproj +++ b/MessageKit.xcodeproj/project.pbxproj @@ -25,8 +25,6 @@ 1FAC3492201E5346000A1504 /* MessagesCollectionViewFlowLayout+CellSizing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FAC3491201E5346000A1504 /* MessagesCollectionViewFlowLayout+CellSizing.swift */; }; 1FCA6D30201C1CC900BC3480 /* UIEdgeInsets+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FCA6D2F201C1CC900BC3480 /* UIEdgeInsets+Extensions.swift */; }; 1FF377A420087C82004FD648 /* MessageKitError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FF377A320087C82004FD648 /* MessageKitError.swift */; }; - 1FF377A620087D20004FD648 /* MessagesViewController+DataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FF377A520087D20004FD648 /* MessagesViewController+DataSource.swift */; }; - 1FF377A820087D56004FD648 /* MessagesViewController+Delegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FF377A720087D56004FD648 /* MessagesViewController+Delegate.swift */; }; 1FF377AA20087D78004FD648 /* MessagesViewController+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FF377A920087D78004FD648 /* MessagesViewController+Menu.swift */; }; 1FF377AC20087DA2004FD648 /* MessagesViewController+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FF377AB20087DA2004FD648 /* MessagesViewController+Keyboard.swift */; }; 38C57C791F9AE3E50043CC03 /* SeparatorLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38C57C781F9AE3E50043CC03 /* SeparatorLine.swift */; }; @@ -132,8 +130,6 @@ 1FAC3491201E5346000A1504 /* MessagesCollectionViewFlowLayout+CellSizing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessagesCollectionViewFlowLayout+CellSizing.swift"; sourceTree = ""; }; 1FCA6D2F201C1CC900BC3480 /* UIEdgeInsets+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIEdgeInsets+Extensions.swift"; sourceTree = ""; }; 1FF377A320087C82004FD648 /* MessageKitError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageKitError.swift; sourceTree = ""; }; - 1FF377A520087D20004FD648 /* MessagesViewController+DataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessagesViewController+DataSource.swift"; sourceTree = ""; }; - 1FF377A720087D56004FD648 /* MessagesViewController+Delegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessagesViewController+Delegate.swift"; sourceTree = ""; }; 1FF377A920087D78004FD648 /* MessagesViewController+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessagesViewController+Menu.swift"; sourceTree = ""; }; 1FF377AB20087DA2004FD648 /* MessagesViewController+Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessagesViewController+Keyboard.swift"; sourceTree = ""; }; 38C57C781F9AE3E50043CC03 /* SeparatorLine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeparatorLine.swift; sourceTree = ""; }; @@ -440,8 +436,6 @@ isa = PBXGroup; children = ( B7A03F4E1F86697C006AEF79 /* MessagesViewController.swift */, - 1FF377A520087D20004FD648 /* MessagesViewController+DataSource.swift */, - 1FF377A720087D56004FD648 /* MessagesViewController+Delegate.swift */, 1FF377A920087D78004FD648 /* MessagesViewController+Menu.swift */, 1FF377AB20087DA2004FD648 /* MessagesViewController+Keyboard.swift */, ); @@ -646,14 +640,12 @@ 0EE91E661FDEC888005420A2 /* CGRect+Extensions.swift in Sources */, B7A03F181F86682C006AEF79 /* MessagesCollectionViewFlowLayout.swift in Sources */, B7A03F2A1F866895006AEF79 /* MessageStyle.swift in Sources */, - 1FF377A620087D20004FD648 /* MessagesViewController+DataSource.swift in Sources */, B7A03F4D1F86694F006AEF79 /* MessagesCollectionView.swift in Sources */, B7A03F351F866940006AEF79 /* MessageHeaderView.swift in Sources */, B7A03F731F866A06006AEF79 /* MessageKit+Availability.swift in Sources */, B7A03F2D1F866895006AEF79 /* LabelAlignment.swift in Sources */, 38C57C791F9AE3E50043CC03 /* SeparatorLine.swift in Sources */, B7A03F2C1F866895006AEF79 /* DetectorType.swift in Sources */, - 1FF377A820087D56004FD648 /* MessagesViewController+Delegate.swift in Sources */, B7A03F271F866895006AEF79 /* Avatar.swift in Sources */, 1FAC348C201E4F88000A1504 /* MessagesCollectionViewFlowLayout+MessageContainerView.swift in Sources */, 1F82D1431FB1B75B00B81A88 /* AvatarPosition.swift in Sources */,