diff --git a/Example/ChatExample.xcodeproj/project.pbxproj b/Example/ChatExample.xcodeproj/project.pbxproj index 2b7dc8da..5074c186 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 */; }; @@ -67,6 +68,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 = ""; }; @@ -146,6 +148,7 @@ children = ( 385C2926211FF33B0010B4BA /* MockMessage.swift */, 385C2925211FF33A0010B4BA /* MockSocket.swift */, + 383B9EB22172A1C4008AB91A /* MockUser.swift */, ); path = Models; sourceTree = ""; @@ -512,6 +515,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 07b47218..75f25036 100644 --- a/Example/Sources/Data Generation/SampleData.swift +++ b/Example/Sources/Data Generation/SampleData.swift @@ -51,14 +51,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 } @@ -150,7 +150,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() { @@ -206,7 +206,7 @@ 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") @@ -217,18 +217,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 8a320373..24aaf5bf 100644 --- a/Example/Sources/Models/MockMessage.swift +++ b/Example/Sources/Models/MockMessage.swift @@ -56,46 +56,50 @@ private struct ImageMediaItem: MediaItem { 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) } } 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 d55b07cd..c5037afe 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 a8de9166..1426ea11 100644 --- a/Example/Sources/View Controllers/ChatViewController.swift +++ b/Example/Sources/View Controllers/ChatViewController.swift @@ -138,7 +138,7 @@ class ChatViewController: MessagesViewController, MessagesDataSource { // MARK: - MessagesDataSource - func currentSender() -> Sender { + func currentSender() -> SenderType { return SampleData.shared.currentSender } @@ -233,12 +233,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 8e056eb6..5b08411a 100644 --- a/MessageKit.xcodeproj/project.pbxproj +++ b/MessageKit.xcodeproj/project.pbxproj @@ -35,6 +35,7 @@ 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 */; }; 88916B2D1CF0DF2F00469F91 /* MessageKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88916B221CF0DF2F00469F91 /* MessageKit.framework */; }; 8962AC8A1F87AB7D0030B058 /* MessagesCollectionViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8962AC831F87AB230030B058 /* MessagesCollectionViewTests.swift */; }; @@ -130,6 +131,7 @@ 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 = ""; }; 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; }; @@ -403,6 +405,7 @@ B7A03F561F8669C9006AEF79 /* MessagesDisplayDelegate.swift */, B7A03F541F8669C9006AEF79 /* MessagesLayoutDelegate.swift */, B7A03F511F8669C9006AEF79 /* MessageType.swift */, + 383B9EB021728BAD008AB91A /* SenderType.swift */, 1FD5895F2064E08A004B5081 /* MediaItem.swift */, 1FD5896320660C1C004B5081 /* LocationItem.swift */, ); @@ -583,6 +586,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 */, diff --git a/Sources/Models/Sender.swift b/Sources/Models/Sender.swift index 8fc5e944..537a74a5 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: 2.0, message: "`Sender` has been replaced with the `SenderType` protocol in 2.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 3caba08b..a26d896b 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`. @@ -108,7 +108,7 @@ public protocol MessagesDataSource: AnyObject { public extension MessagesDataSource { func isFromCurrentSender(message: MessageType) -> Bool { - return message.sender == currentSender() + return message.sender.isEqualTo(currentSender()) } func numberOfItems(inSection section: Int, in messagesCollectionView: MessagesCollectionView) -> Int { diff --git a/Sources/Protocols/MessagesDisplayDelegate.swift b/Sources/Protocols/MessagesDisplayDelegate.swift index 2af2eac5..74698759 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..2950f7b0 --- /dev/null +++ b/Sources/Protocols/SenderType.swift @@ -0,0 +1,47 @@ +/* + 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 } + + /// Equatable conformance + func isEqualTo(_ sender: SenderType) -> Bool +} + +public extension SenderType { + func isEqualTo(_ sender: SenderType) -> Bool { + return self.id == sender.id + } +}