diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b4fcd45..6a8d4c1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ The changelog for `MessageKit`. Also see the [releases](https://github.com/MessageKit/MessageKit/releases) on GitHub. +## Upcoming Release + +### Changed + +- **Breaking Change** Deprecated the Sender struct in favor of the `SenderType` protocol. + -------------------------------------- diff --git a/Example/ChatExample.xcodeproj/project.pbxproj b/Example/ChatExample.xcodeproj/project.pbxproj index 010c2846..9e37a166 100644 --- a/Example/ChatExample.xcodeproj/project.pbxproj +++ b/Example/ChatExample.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 383B9EB32172A1C4008AB91A /* MockUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383B9EB22172A1C4008AB91A /* MockUser.swift */; }; 385C2922211FF32E0010B4BA /* CustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 385C2920211FF32E0010B4BA /* CustomCell.swift */; }; 385C2923211FF32E0010B4BA /* TableViewCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = 385C2921211FF32E0010B4BA /* TableViewCells.swift */; }; 385C2927211FF33B0010B4BA /* MockSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 385C2925211FF33A0010B4BA /* MockSocket.swift */; }; @@ -70,6 +71,7 @@ /* Begin PBXFileReference section */ 0364943D08CDBE656E6F6DF8 /* Pods-ChatExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChatExampleTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ChatExampleTests/Pods-ChatExampleTests.debug.xcconfig"; sourceTree = ""; }; 2AC6E3F5C11E39F57598DBE6 /* Pods_ChatExampleUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ChatExampleUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 383B9EB22172A1C4008AB91A /* MockUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUser.swift; sourceTree = ""; }; 385C2920211FF32E0010B4BA /* CustomCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomCell.swift; sourceTree = ""; }; 385C2921211FF32E0010B4BA /* TableViewCells.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewCells.swift; sourceTree = ""; }; 385C2925211FF33A0010B4BA /* MockSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockSocket.swift; sourceTree = ""; }; @@ -152,6 +154,7 @@ children = ( 385C2926211FF33B0010B4BA /* MockMessage.swift */, 385C2925211FF33A0010B4BA /* MockSocket.swift */, + 383B9EB22172A1C4008AB91A /* MockUser.swift */, ); path = Models; sourceTree = ""; @@ -540,6 +543,7 @@ 385C2945211FF38F0010B4BA /* NavigationController.swift in Sources */, 385C2948211FF38F0010B4BA /* ChatViewController.swift in Sources */, 385C2944211FF38F0010B4BA /* MessageContainerController.swift in Sources */, + 383B9EB32172A1C4008AB91A /* MockUser.swift in Sources */, 385C2943211FF38F0010B4BA /* SettingsViewController.swift in Sources */, 385C2927211FF33B0010B4BA /* MockSocket.swift in Sources */, 385C2947211FF38F0010B4BA /* BasicExampleViewController.swift in Sources */, diff --git a/Example/Sources/Data Generation/SampleData.swift b/Example/Sources/Data Generation/SampleData.swift index 9f666bbf..18c561d3 100644 --- a/Example/Sources/Data Generation/SampleData.swift +++ b/Example/Sources/Data Generation/SampleData.swift @@ -53,14 +53,14 @@ final internal class SampleData { } } - let system = Sender(id: "000000", displayName: "System") - let nathan = Sender(id: "000001", displayName: "Nathan Tannar") - let steven = Sender(id: "000002", displayName: "Steven Deutsch") - let wu = Sender(id: "000003", displayName: "Wu Zhong") + let system = MockUser(id: "000000", displayName: "System") + let nathan = MockUser(id: "000001", displayName: "Nathan Tannar") + let steven = MockUser(id: "000002", displayName: "Steven Deutsch") + let wu = MockUser(id: "000003", displayName: "Wu Zhong") lazy var senders = [nathan, steven, wu] - var currentSender: Sender { + var currentSender: MockUser { return nathan } @@ -155,7 +155,7 @@ final internal class SampleData { let randomNumberSender = Int(arc4random_uniform(UInt32(allowedSenders.count))) let uniqueID = NSUUID().uuidString - let sender = allowedSenders[randomNumberSender] + let user = allowedSenders[randomNumberSender] let date = dateAddingRandomTime() switch randomMessageType() { @@ -214,8 +214,8 @@ final internal class SampleData { } completion(messages) } - - func getMessages(count: Int, allowedSenders: [Sender], completion: ([MockMessage]) -> Void) { + + func getMessages(count: Int, allowedSenders: [MockUser], completion: ([MockMessage]) -> Void) { var messages: [MockMessage] = [] // Disable Custom Messages UserDefaults.standard.set(false, forKey: "Custom Messages") @@ -226,18 +226,18 @@ final internal class SampleData { completion(messages) } - func getAvatarFor(sender: Sender) -> Avatar { + func getAvatarFor(sender: SenderType) -> Avatar { let firstName = sender.displayName.components(separatedBy: " ").first let lastName = sender.displayName.components(separatedBy: " ").first let initials = "\(firstName?.first ?? "A")\(lastName?.first ?? "A")" - switch sender { - case nathan: + switch sender.id { + case "000001": return Avatar(image: #imageLiteral(resourceName: "Nathan-Tannar"), initials: initials) - case steven: + case "000002": return Avatar(image: #imageLiteral(resourceName: "Steven-Deutsch"), initials: initials) - case wu: + case "000003": return Avatar(image: #imageLiteral(resourceName: "Wu-Zhong"), initials: initials) - case system: + case "000000": return Avatar(image: nil, initials: "SS") default: return Avatar(image: nil, initials: initials) diff --git a/Example/Sources/Models/MockMessage.swift b/Example/Sources/Models/MockMessage.swift index c730d33b..d4e5722a 100644 --- a/Example/Sources/Models/MockMessage.swift +++ b/Example/Sources/Models/MockMessage.swift @@ -73,46 +73,50 @@ private struct MockAudiotem: AudioItem { internal struct MockMessage: MessageType { var messageId: String - var sender: Sender + var sender: SenderType { + return user + } var sentDate: Date var kind: MessageKind - private init(kind: MessageKind, sender: Sender, messageId: String, date: Date) { + var user: MockUser + + private init(kind: MessageKind, user: MockUser, messageId: String, date: Date) { self.kind = kind - self.sender = sender + self.user = user self.messageId = messageId self.sentDate = date } - init(custom: Any?, sender: Sender, messageId: String, date: Date) { - self.init(kind: .custom(custom), sender: sender, messageId: messageId, date: date) + init(custom: Any?, user: MockUser, messageId: String, date: Date) { + self.init(kind: .custom(custom), user: user, messageId: messageId, date: date) } - init(text: String, sender: Sender, messageId: String, date: Date) { - self.init(kind: .text(text), sender: sender, messageId: messageId, date: date) + init(text: String, user: MockUser, messageId: String, date: Date) { + self.init(kind: .text(text), user: user, messageId: messageId, date: date) } - init(attributedText: NSAttributedString, sender: Sender, messageId: String, date: Date) { - self.init(kind: .attributedText(attributedText), sender: sender, messageId: messageId, date: date) + init(attributedText: NSAttributedString, user: MockUser, messageId: String, date: Date) { + self.init(kind: .attributedText(attributedText), user: user, messageId: messageId, date: date) } - init(image: UIImage, sender: Sender, messageId: String, date: Date) { + init(image: UIImage, user: MockUser, messageId: String, date: Date) { let mediaItem = ImageMediaItem(image: image) - self.init(kind: .photo(mediaItem), sender: sender, messageId: messageId, date: date) + self.init(kind: .photo(mediaItem), user: user, messageId: messageId, date: date) } - init(thumbnail: UIImage, sender: Sender, messageId: String, date: Date) { + init(thumbnail: UIImage, user: MockUser, messageId: String, date: Date) { let mediaItem = ImageMediaItem(image: thumbnail) - self.init(kind: .video(mediaItem), sender: sender, messageId: messageId, date: date) + self.init(kind: .video(mediaItem), user: user, messageId: messageId, date: date) } - init(location: CLLocation, sender: Sender, messageId: String, date: Date) { + init(location: CLLocation, user: MockUser, messageId: String, date: Date) { let locationItem = CoordinateItem(location: location) - self.init(kind: .location(locationItem), sender: sender, messageId: messageId, date: date) + self.init(kind: .location(locationItem), user: user, messageId: messageId, date: date) } - init(emoji: String, sender: Sender, messageId: String, date: Date) { - self.init(kind: .emoji(emoji), sender: sender, messageId: messageId, date: date) + init(emoji: String, user: MockUser, messageId: String, date: Date) { + self.init(kind: .emoji(emoji), user: user, messageId: messageId, date: date) } init(audioURL: URL, sender: Sender, messageId: String, date: Date) { diff --git a/Example/Sources/Models/MockSocket.swift b/Example/Sources/Models/MockSocket.swift index 0585d9dc..c3bc2996 100644 --- a/Example/Sources/Models/MockSocket.swift +++ b/Example/Sources/Models/MockSocket.swift @@ -37,12 +37,12 @@ final class MockSocket { private var onTypingStatusCode: (() -> Void)? - private var connectedUsers: [Sender] = [] + private var connectedUsers: [MockUser] = [] private init() {} @discardableResult - func connect(with senders: [Sender]) -> Self { + func connect(with senders: [MockUser]) -> Self { disconnect() connectedUsers = senders timer = Timer.scheduledTimer(timeInterval: 2.5, target: self, selector: #selector(handleTimer), userInfo: nil, repeats: true) diff --git a/Example/Sources/Models/MockUser.swift b/Example/Sources/Models/MockUser.swift new file mode 100644 index 00000000..de17c097 --- /dev/null +++ b/Example/Sources/Models/MockUser.swift @@ -0,0 +1,31 @@ +/* + 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 Foundation +import MessageKit + +struct MockUser: SenderType, Equatable { + var id: String + var displayName: String +} diff --git a/Example/Sources/View Controllers/AdvancedExampleViewController.swift b/Example/Sources/View Controllers/AdvancedExampleViewController.swift index b8d1c4fd..6e902fc2 100644 --- a/Example/Sources/View Controllers/AdvancedExampleViewController.swift +++ b/Example/Sources/View Controllers/AdvancedExampleViewController.swift @@ -176,12 +176,12 @@ final class AdvancedExampleViewController: ChatViewController { func isPreviousMessageSameSender(at indexPath: IndexPath) -> Bool { guard indexPath.section - 1 >= 0 else { return false } - return messageList[indexPath.section].sender == messageList[indexPath.section - 1].sender + return messageList[indexPath.section].user == messageList[indexPath.section - 1].user } func isNextMessageSameSender(at indexPath: IndexPath) -> Bool { guard indexPath.section + 1 < messageList.count else { return false } - return messageList[indexPath.section].sender == messageList[indexPath.section + 1].sender + return messageList[indexPath.section].user == messageList[indexPath.section + 1].user } func setTypingIndicatorHidden(_ isHidden: Bool, performUpdates updates: (() -> Void)? = nil) { diff --git a/Example/Sources/View Controllers/ChatViewController.swift b/Example/Sources/View Controllers/ChatViewController.swift index af107d10..36c78c8e 100644 --- a/Example/Sources/View Controllers/ChatViewController.swift +++ b/Example/Sources/View Controllers/ChatViewController.swift @@ -142,7 +142,7 @@ class ChatViewController: MessagesViewController, MessagesDataSource { // MARK: - MessagesDataSource - func currentSender() -> Sender { + func currentSender() -> SenderType { return SampleData.shared.currentSender } @@ -283,12 +283,13 @@ extension ChatViewController: MessageInputBarDelegate { func messageInputBar(_ inputBar: MessageInputBar, didPressSendButtonWith text: String) { for component in inputBar.inputTextView.components { - + + let user = SampleData.shared.currentSender if let str = component as? String { - let message = MockMessage(text: str, sender: currentSender(), messageId: UUID().uuidString, date: Date()) + let message = MockMessage(text: str, user: user, messageId: UUID().uuidString, date: Date()) insertMessage(message) } else if let img = component as? UIImage { - let message = MockMessage(image: img, sender: currentSender(), messageId: UUID().uuidString, date: Date()) + let message = MockMessage(image: img, user: user, messageId: UUID().uuidString, date: Date()) insertMessage(message) } diff --git a/MessageKit.xcodeproj/project.pbxproj b/MessageKit.xcodeproj/project.pbxproj index 0579ea9c..760bc1f9 100644 --- a/MessageKit.xcodeproj/project.pbxproj +++ b/MessageKit.xcodeproj/project.pbxproj @@ -35,11 +35,13 @@ 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 */; }; 382C794221705D2000F4FAF5 /* HorizontalEdgeInsets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382C794121705D2000F4FAF5 /* HorizontalEdgeInsets.swift */; }; + 383B9EB121728BAD008AB91A /* SenderType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383B9EB021728BAD008AB91A /* SenderType.swift */; }; 38C2AE7C20D4878D00F8079E /* MessageInputBar.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38C2AE7B20D4878D00F8079E /* MessageInputBar.framework */; }; 5073C1152175BE750040EAD5 /* AudioItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5073C1142175BE750040EAD5 /* AudioItem.swift */; }; 5073C1192175BE960040EAD5 /* AudioMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5073C1182175BE950040EAD5 /* AudioMessageCell.swift */; }; 5073C11D2175BEC60040EAD5 /* AudioMessageSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5073C11C2175BEC60040EAD5 /* AudioMessageSizeCalculator.swift */; }; 5073C1232175C1980040EAD5 /* sound1.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 5073C1222175C1980040EAD5 /* sound1.m4a */; }; + 38F8062F2173CD8F00CDB9DB /* MockUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38F8062D2173CD4300CDB9DB /* MockUser.swift */; }; 88916B2D1CF0DF2F00469F91 /* MessageKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88916B221CF0DF2F00469F91 /* MessageKit.framework */; }; 8962AC8A1F87AB7D0030B058 /* MessagesCollectionViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8962AC831F87AB230030B058 /* MessagesCollectionViewTests.swift */; }; 8962AC8C1F87AB7D0030B058 /* AvatarViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8962AC851F87AB230030B058 /* AvatarViewTests.swift */; }; @@ -134,11 +136,13 @@ 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 = ""; }; 382C794121705D2000F4FAF5 /* HorizontalEdgeInsets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalEdgeInsets.swift; sourceTree = ""; }; + 383B9EB021728BAD008AB91A /* SenderType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SenderType.swift; sourceTree = ""; }; 38C2AE7B20D4878D00F8079E /* MessageInputBar.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageInputBar.framework; path = Carthage/Build/iOS/MessageInputBar.framework; sourceTree = ""; }; 5073C1142175BE750040EAD5 /* AudioItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioItem.swift; sourceTree = ""; }; 5073C1182175BE950040EAD5 /* AudioMessageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioMessageCell.swift; sourceTree = ""; }; 5073C11C2175BEC60040EAD5 /* AudioMessageSizeCalculator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioMessageSizeCalculator.swift; sourceTree = ""; }; 5073C1222175C1980040EAD5 /* sound1.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = sound1.m4a; sourceTree = ""; }; + 38F8062D2173CD4300CDB9DB /* MockUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUser.swift; sourceTree = ""; }; 88916B221CF0DF2F00469F91 /* MessageKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MessageKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 88916B2C1CF0DF2F00469F91 /* MessageKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MessageKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 8962AC741F87AB230030B058 /* MessageKitDateFormatterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageKitDateFormatterTests.swift; sourceTree = ""; }; @@ -316,6 +320,7 @@ children = ( 8962AC7B1F87AB230030B058 /* MockMessage.swift */, 8962AC7A1F87AB230030B058 /* MockMessagesDataSource.swift */, + 38F8062D2173CD4300CDB9DB /* MockUser.swift */, ); path = Mocks; sourceTree = ""; @@ -421,6 +426,7 @@ B7A03F561F8669C9006AEF79 /* MessagesDisplayDelegate.swift */, B7A03F541F8669C9006AEF79 /* MessagesLayoutDelegate.swift */, B7A03F511F8669C9006AEF79 /* MessageType.swift */, + 383B9EB021728BAD008AB91A /* SenderType.swift */, 1FD5895F2064E08A004B5081 /* MediaItem.swift */, 1FD5896320660C1C004B5081 /* LocationItem.swift */, 5073C1142175BE750040EAD5 /* AudioItem.swift */, @@ -605,6 +611,7 @@ B7A03F4B1F86694F006AEF79 /* MessageContainerView.swift in Sources */, B7A03F281F866895006AEF79 /* LocationMessageSnapshotOptions.swift in Sources */, B7A03F6C1F8669EB006AEF79 /* UIView+Extensions.swift in Sources */, + 383B9EB121728BAD008AB91A /* SenderType.swift in Sources */, B7A03F3A1F866946006AEF79 /* TextMessageCell.swift in Sources */, B7A03F191F86682C006AEF79 /* MessagesCollectionViewLayoutAttributes.swift in Sources */, B7A03F461F86694F006AEF79 /* AvatarView.swift in Sources */, @@ -661,6 +668,7 @@ 1F066E131FD90BB600E11013 /* MessagesViewControllerSpec.swift in Sources */, 1F066E1D1FDA3C1700E11013 /* SenderSpec.swift in Sources */, 8962AC8A1F87AB7D0030B058 /* MessagesCollectionViewTests.swift in Sources */, + 38F8062F2173CD8F00CDB9DB /* MockUser.swift in Sources */, 8962AC8D1F87AB7D0030B058 /* MessageCollectionViewCellTests.swift in Sources */, 8962AC991F87AB860030B058 /* MessagesDisplayDelegateTests.swift in Sources */, 1FD589622064E1B9004B5081 /* MockMessage.swift in Sources */, diff --git a/Sources/Models/Sender.swift b/Sources/Models/Sender.swift index 8fc5e944..914dc8f8 100644 --- a/Sources/Models/Sender.swift +++ b/Sources/Models/Sender.swift @@ -25,7 +25,8 @@ import Foundation /// An object that groups the metadata of a messages sender. -public struct Sender { +@available(*, deprecated: 3.0.0, message: "`Sender` has been replaced with the `SenderType` protocol in 3.0.0") +public struct Sender: SenderType { /// MARK: - Properties @@ -44,14 +45,3 @@ public struct Sender { self.displayName = displayName } } - -// MARK: - Equatable Conformance - -extension Sender: Equatable { - - /// Two senders are considered equal if they have the same id. - public static func == (left: Sender, right: Sender) -> Bool { - return left.id == right.id - } - -} diff --git a/Sources/Protocols/MessageType.swift b/Sources/Protocols/MessageType.swift index 627b7f50..6c17f00f 100644 --- a/Sources/Protocols/MessageType.swift +++ b/Sources/Protocols/MessageType.swift @@ -29,7 +29,7 @@ import Foundation public protocol MessageType { /// The sender of the message. - var sender: Sender { get } + var sender: SenderType { get } /// The unique identifier for the message. var messageId: String { get } diff --git a/Sources/Protocols/MessagesDataSource.swift b/Sources/Protocols/MessagesDataSource.swift index 939a4ad4..1d02e330 100644 --- a/Sources/Protocols/MessagesDataSource.swift +++ b/Sources/Protocols/MessagesDataSource.swift @@ -28,17 +28,17 @@ import UIKit /// the data required by a `MessagesCollectionView`. public protocol MessagesDataSource: AnyObject { - /// The `Sender` of new messages in the `MessagesCollectionView`. - func currentSender() -> Sender + /// The `SenderType` of new messages in the `MessagesCollectionView`. + func currentSender() -> SenderType - /// A helper method to determine if a given message is from the current `Sender`. + /// A helper method to determine if a given message is from the current `SenderType`. /// /// - Parameters: - /// - message: The message to check if it was sent by the current `Sender`. + /// - message: The message to check if it was sent by the current `SenderType`. /// /// - Note: /// The default implementation of this method checks for equality between - /// the message's `Sender` and the current `Sender`. + /// the message's `SenderType` and the current `SenderType`. func isFromCurrentSender(message: MessageType) -> Bool /// The message to be used for a `MessageCollectionViewCell` at the given `IndexPath`. @@ -118,7 +118,7 @@ public protocol MessagesDataSource: AnyObject { public extension MessagesDataSource { func isFromCurrentSender(message: MessageType) -> Bool { - return message.sender == currentSender() + return message.sender.id == currentSender().id } func numberOfItems(inSection section: Int, in messagesCollectionView: MessagesCollectionView) -> Int { diff --git a/Sources/Protocols/MessagesDisplayDelegate.swift b/Sources/Protocols/MessagesDisplayDelegate.swift index 334042c4..81c2e701 100644 --- a/Sources/Protocols/MessagesDisplayDelegate.swift +++ b/Sources/Protocols/MessagesDisplayDelegate.swift @@ -50,7 +50,7 @@ public protocol MessagesDisplayDelegate: AnyObject { /// /// - Note: /// The default value is `UIColor.clear` for emoji messages. - /// For all other `MessageKind` cases, the color depends on the `Sender`. + /// For all other `MessageKind` cases, the color depends on the `SenderType`. /// /// Current sender: Green /// @@ -106,7 +106,7 @@ public protocol MessagesDisplayDelegate: AnyObject { /// - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed. /// /// - Note: - /// The default value returned by this method is determined by the messages `Sender`. + /// The default value returned by this method is determined by the messages `SenderType`. /// /// Current sender: UIColor.white /// diff --git a/Sources/Protocols/SenderType.swift b/Sources/Protocols/SenderType.swift new file mode 100644 index 00000000..3774f19f --- /dev/null +++ b/Sources/Protocols/SenderType.swift @@ -0,0 +1,38 @@ +/* + 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 Foundation + +/// A standard protocol representing a sender. +/// Use this protocol to adhere a object as the sender of a MessageType +public protocol SenderType { + + /// The unique String identifier for the sender. + /// + /// Note: This value must be unique across all senders. + var id: String { get } + + /// The display name of a sender. + var displayName: String { get } +} diff --git a/Tests/ControllersTest/MessagesViewControllerTests.swift b/Tests/ControllersTest/MessagesViewControllerTests.swift index 9b72a759..9dbaf381 100644 --- a/Tests/ControllersTest/MessagesViewControllerTests.swift +++ b/Tests/ControllersTest/MessagesViewControllerTests.swift @@ -90,7 +90,7 @@ class MessagesViewControllerTests: XCTestCase { let messagesDataSource = MockMessagesDataSource() sut.messagesCollectionView.messagesDataSource = messagesDataSource messagesDataSource.messages.append(MockMessage(text: "Test", - sender: messagesDataSource.senders[0], + user: messagesDataSource.senders[0], messageId: "test_id")) sut.messagesCollectionView.reloadData() @@ -108,7 +108,7 @@ class MessagesViewControllerTests: XCTestCase { let attributes = [NSAttributedString.Key.foregroundColor: UIColor.black] let attriutedString = NSAttributedString(string: "Test", attributes: attributes) messagesDataSource.messages.append(MockMessage(attributedText: attriutedString, - sender: messagesDataSource.senders[0], + user: messagesDataSource.senders[0], messageId: "test_id")) sut.messagesCollectionView.reloadData() @@ -124,7 +124,7 @@ class MessagesViewControllerTests: XCTestCase { let messagesDataSource = MockMessagesDataSource() sut.messagesCollectionView.messagesDataSource = messagesDataSource messagesDataSource.messages.append(MockMessage(image: UIImage(), - sender: messagesDataSource.senders[0], + user: messagesDataSource.senders[0], messageId: "test_id")) sut.messagesCollectionView.reloadData() @@ -140,7 +140,7 @@ class MessagesViewControllerTests: XCTestCase { let messagesDataSource = MockMessagesDataSource() sut.messagesCollectionView.messagesDataSource = messagesDataSource messagesDataSource.messages.append(MockMessage(thumbnail: UIImage(), - sender: messagesDataSource.senders[0], + user: messagesDataSource.senders[0], messageId: "test_id")) sut.messagesCollectionView.reloadData() @@ -156,7 +156,7 @@ class MessagesViewControllerTests: XCTestCase { let messagesDataSource = MockMessagesDataSource() sut.messagesCollectionView.messagesDataSource = messagesDataSource messagesDataSource.messages.append(MockMessage(location: CLLocation(latitude: 60.0, longitude: 70.0), - sender: messagesDataSource.senders[0], + user: messagesDataSource.senders[0], messageId: "test_id")) sut.messagesCollectionView.reloadData() @@ -187,9 +187,9 @@ class MessagesViewControllerTests: XCTestCase { // MARK: - Assistants - private func makeMessages(for senders: [Sender]) -> [MessageType] { - return [MockMessage(text: "Text 1", sender: senders[0], messageId: "test_id_1"), - MockMessage(text: "Text 2", sender: senders[1], messageId: "test_id_2")] + private func makeMessages(for senders: [MockUser]) -> [MessageType] { + return [MockMessage(text: "Text 1", user: senders[0], messageId: "test_id_1"), + MockMessage(text: "Text 2", user: senders[1], messageId: "test_id_2")] } } diff --git a/Tests/Mocks/MockMessage.swift b/Tests/Mocks/MockMessage.swift index 812852a7..5b4fcceb 100644 --- a/Tests/Mocks/MockMessage.swift +++ b/Tests/Mocks/MockMessage.swift @@ -72,42 +72,45 @@ private struct MockAudiotem: AudioItem { struct MockMessage: MessageType { var messageId: String - var sender: Sender + var sender: SenderType { + return user + } var sentDate: Date var kind: MessageKind + var user: MockUser - private init(kind: MessageKind, sender: Sender, messageId: String) { + private init(kind: MessageKind, user: MockUser, messageId: String) { self.kind = kind - self.sender = sender + self.user = user self.messageId = messageId self.sentDate = Date() } - init(text: String, sender: Sender, messageId: String) { - self.init(kind: .text(text), sender: sender, messageId: messageId) + init(text: String, user: MockUser, messageId: String) { + self.init(kind: .text(text), user: user, messageId: messageId) } - init(attributedText: NSAttributedString, sender: Sender, messageId: String) { - self.init(kind: .attributedText(attributedText), sender: sender, messageId: messageId) + init(attributedText: NSAttributedString, user: MockUser, messageId: String) { + self.init(kind: .attributedText(attributedText), user: user, messageId: messageId) } - init(image: UIImage, sender: Sender, messageId: String) { + init(image: UIImage, user: MockUser, messageId: String) { let mediaItem = MockMediaItem(image: image) - self.init(kind: .photo(mediaItem), sender: sender, messageId: messageId) + self.init(kind: .photo(mediaItem), user: user, messageId: messageId) } - init(thumbnail: UIImage, sender: Sender, messageId: String) { + init(thumbnail: UIImage, user: MockUser, messageId: String) { let mediaItem = MockMediaItem(image: thumbnail) - self.init(kind: .video(mediaItem), sender: sender, messageId: messageId) + self.init(kind: .video(mediaItem), user: user, messageId: messageId) } - init(location: CLLocation, sender: Sender, messageId: String) { + init(location: CLLocation, user: MockUser, messageId: String) { let locationItem = MockLocationItem(location: location) - self.init(kind: .location(locationItem), sender: sender, messageId: messageId) + self.init(kind: .location(locationItem), user: user, messageId: messageId) } - init(emoji: String, sender: Sender, messageId: String) { - self.init(kind: .emoji(emoji), sender: sender, messageId: messageId) + init(emoji: String, user: MockUser, messageId: String) { + self.init(kind: .emoji(emoji), user: user, messageId: messageId) } init(audioURL: URL, duration: Float, sender: Sender, messageId: String) { diff --git a/Tests/Mocks/MockMessagesDataSource.swift b/Tests/Mocks/MockMessagesDataSource.swift index 566d8d27..59ff06f3 100644 --- a/Tests/Mocks/MockMessagesDataSource.swift +++ b/Tests/Mocks/MockMessagesDataSource.swift @@ -28,13 +28,17 @@ import Foundation class MockMessagesDataSource: MessagesDataSource { var messages: [MessageType] = [] - let senders: [Sender] = [Sender(id: "sender_1", displayName: "Sender 1"), - Sender(id: "sender_2", displayName: "Sender 2")] + let senders: [MockUser] = [MockUser(id: "sender_1", displayName: "Sender 1"), + MockUser(id: "sender_2", displayName: "Sender 2")] - func currentSender() -> Sender { + var currentUser: MockUser { return senders[0] } + func currentSender() -> SenderType { + return currentUser + } + func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int { return messages.count } diff --git a/Tests/Mocks/MockUser.swift b/Tests/Mocks/MockUser.swift new file mode 100644 index 00000000..cfeb6a76 --- /dev/null +++ b/Tests/Mocks/MockUser.swift @@ -0,0 +1,31 @@ +/* + 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 Foundation +@testable import MessageKit + +struct MockUser: SenderType { + var id: String + var displayName: String +} diff --git a/Tests/ProtocolsTests/MessagesDisplayDelegateTests.swift b/Tests/ProtocolsTests/MessagesDisplayDelegateTests.swift index 4d2dae9d..7d0db3a7 100644 --- a/Tests/ProtocolsTests/MessagesDisplayDelegateTests.swift +++ b/Tests/ProtocolsTests/MessagesDisplayDelegateTests.swift @@ -76,7 +76,7 @@ class MessagesDisplayDelegateTests: XCTestCase { func testBackgroundColorForMessageWithEmoji_returnsClearForDefault() { sut.dataProvider.messages.append(MockMessage(emoji: "🤔", - sender: sut.dataProvider.currentSender(), + user: sut.dataProvider.currentUser, messageId: "003")) let backgroundColor = sut.backgroundColor(for: sut.dataProvider.messages[2], at: IndexPath(item: 0, section: 0), @@ -196,10 +196,10 @@ private class MockMessagesViewController: MessagesViewController, MessagesDispla fileprivate func makeDataSource() -> MockMessagesDataSource { let dataSource = MockMessagesDataSource() dataSource.messages.append(MockMessage(text: "Text 1", - sender: dataSource.senders[0], + user: dataSource.senders[0], messageId: "001")) dataSource.messages.append(MockMessage(text: "Text 2", - sender: dataSource.senders[1], + user: dataSource.senders[1], messageId: "002")) return dataSource diff --git a/Tests/SenderSpec.swift b/Tests/SenderSpec.swift index 56910a3d..2f587dd4 100644 --- a/Tests/SenderSpec.swift +++ b/Tests/SenderSpec.swift @@ -32,16 +32,16 @@ final class SenderSpec: QuickSpec { describe("equality between two Senders") { context("they have the same id ") { it("should be equal") { - let sender1 = Sender(id: "1", displayName: "Steven") - let sender2 = Sender(id: "1", displayName: "Nathan") - expect(sender1).to(equal(sender2)) + let sender1 = MockUser(id: "1", displayName: "Steven") + let sender2 = MockUser(id: "1", displayName: "Nathan") + expect(sender1.id == sender2.id).to(equal(true)) } } context("they have a different id") { it("should not be equal") { - let sender1 = Sender(id: "1", displayName: "Steven") - let sender2 = Sender(id: "2", displayName: "Nathan") - expect(sender1).toNot(equal(sender2)) + let sender1 = MockUser(id: "1", displayName: "Steven") + let sender2 = MockUser(id: "2", displayName: "Nathan") + expect(sender1.id == sender2.id).to(equal(false)) } } }