Merge remote-tracking branch 'origin/3.0.0-beta' into typingIndicatorView

This commit is contained in:
Nathan Tannar
2019-04-05 00:11:14 -07:00
19 changed files with 376 additions and 24 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

+4
View File
@@ -13,6 +13,8 @@ The changelog for `MessageKit`. Also see the [releases](https://github.com/Messa
- **Breaking Change** Deprecated the Sender struct in favor of the `SenderType` protocol.
[#909](https://github.com/MessageKit/MessageKit/pull/909) by [@nathantannar4](https://github.com/nathantannar4)
- **Breaking Change** Deprecated the Sender struct in favor of the `SenderType` protocol. [#909](https://github.com/MessageKit/MessageKit/pull/909) by [@nathantannar4](https://github.com/nathantannar4)
- **Breaking Change** Add support for audio messages. Added new protocols `AudioControllerDelegate`, `AudioItem` a new cell `AudioMessageCell` and a new controller `BasicAudioController`.
[#892](https://github.com/MessageKit/MessageKit/pull/892) by [@moldovaniosif](https://github.com/moldovaniosif).
@@ -24,6 +26,8 @@ The changelog for `MessageKit`. Also see the [releases](https://github.com/Messa
### Added
- **Breaking Change** Add support for share contact. [#1013](https://github.com/MessageKit/MessageKit/pull/1013) by [@moldovaniosif](https://github.com/moldovaniosif)
- Added typing indicator support, `func setTypingIndicatorViewHidden(_ isHidden: Bool, animated: Bool, whilePerforming updates: (() -> Void)? = nil, completion: ((Bool) -> Void)? = nil)`. Return a custom typing view by conforming to `MessagesDisplayDelegate` or use the [default appearance](https://github.com/nathantannar4/TypingIndicator). Customize the size with `MessagesLayoutDelegate` .
[#989](https://github.com/MessageKit/MessageKit/pull/911) by [@nathantannar4](https://github.com/nathantannar4)
@@ -477,7 +477,7 @@
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ChatExample/Pods-ChatExample-frameworks.sh",
"${SRCROOT}/Pods/Target Support Files/Pods-ChatExample/Pods-ChatExample-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/InputBarAccessoryView/InputBarAccessoryView.framework",
"${BUILT_PRODUCTS_DIR}/MessageKit/MessageKit.framework",
);
@@ -488,7 +488,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ChatExample/Pods-ChatExample-frameworks.sh\"\n";
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ChatExample/Pods-ChatExample-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
52AB594E03799821A66AFF18 /* [CP] Check Pods Manifest.lock */ = {
+4 -4
View File
@@ -1,5 +1,5 @@
PODS:
- InputBarAccessoryView (4.2.1)
- InputBarAccessoryView (4.2.2)
- MessageKit (3.0.0-beta):
- InputBarAccessoryView
@@ -15,9 +15,9 @@ EXTERNAL SOURCES:
:path: "../"
SPEC CHECKSUMS:
InputBarAccessoryView: 37175becdced159cd9ea335f47ae001b1e112909
MessageKit: 4226995f0811d3a51b8e80b56d2e95c97fa879e8
InputBarAccessoryView: 2b937602598e2fab3149f37f51dd7ad795653812
MessageKit: 30a1e0b112c44361904016e7add631a78c5128e0
PODFILE CHECKSUM: cecdb7bc8129cf99f66de9f68eea3256fec30c3d
COCOAPODS: 1.6.1
COCOAPODS: 1.5.3
@@ -43,6 +43,7 @@ final internal class SampleData {
case Url
case Phone
case Custom
case ShareContact
}
let system = MockUser(senderId: "000000", displayName: "System")
@@ -51,6 +52,15 @@ final internal class SampleData {
let wu = MockUser(senderId: "000003", displayName: "Wu Zhong")
lazy var senders = [nathan, steven, wu]
lazy var contactsToShare = [
MockContactItem(name: "System", initials: "S"),
MockContactItem(name: "Nathan Tannar", initials: "NT", emails: ["test@test.com"]),
MockContactItem(name: "Steven Deutsch", initials: "SD", phoneNumbers: ["+1-202-555-0114", "+1-202-555-0145"]),
MockContactItem(name: "Wu Zhong", initials: "WZ", phoneNumbers: ["202-555-0158"]),
MockContactItem(name:"+40 123 123", initials: "#", phoneNumbers: ["+40 123 123"]),
MockContactItem(name:"test@test.com", initials: "#", emails: ["test@test.com"])
]
var currentSender: MockUser {
return nathan
@@ -142,8 +152,8 @@ final internal class SampleData {
return messageTypes.random()!
}
// swiftlint:disable cyclomatic_complexity
func randomMessage(allowedSenders: [MockUser]) -> MockMessage {
let randomNumberSender = Int(arc4random_uniform(UInt32(allowedSenders.count)))
let uniqueID = NSUUID().uuidString
@@ -182,8 +192,12 @@ final internal class SampleData {
return MockMessage(text: "123-456-7890", user: user, messageId: uniqueID, date: date)
case .Custom:
return MockMessage(custom: "Someone left the conversation", user: system, messageId: uniqueID, date: date)
case .ShareContact:
let randomContact = Int(arc4random_uniform(UInt32(contactsToShare.count)))
return MockMessage(contact: contactsToShare[randomContact], user: user, messageId: uniqueID, date: date)
}
}
// swiftlint:enable cyclomatic_complexity
func getMessages(count: Int, completion: ([MockMessage]) -> Void) {
var messages: [MockMessage] = []
+19
View File
@@ -70,6 +70,22 @@ private struct MockAudiotem: AudioItem {
}
struct MockContactItem: ContactItem {
var displayName: String
var initials: String
var phoneNumbers: [String]
var emails: [String]
init(name: String, initials: String, phoneNumbers: [String] = [], emails: [String] = []) {
self.displayName = name
self.initials = initials
self.phoneNumbers = phoneNumbers
self.emails = emails
}
}
internal struct MockMessage: MessageType {
var messageId: String
@@ -124,4 +140,7 @@ internal struct MockMessage: MessageType {
self.init(kind: .audio(audioItem), user: user, messageId: messageId, date: date)
}
init(contact: MockContactItem, user: MockUser, messageId: String, date: Date) {
self.init(kind: .contact(contact), user: user, messageId: messageId, date: date)
}
}
@@ -33,7 +33,7 @@ final internal class SettingsViewController: UITableViewController {
return .lightContent
}
let cells = ["Mock messages count", "Text Messages", "AttributedText Messages", "Photo Messages", "Video Messages", "Audio Messages", "Emoji Messages", "Location Messages", "Url Messages", "Phone Messages"]
let cells = ["Mock messages count", "Text Messages", "AttributedText Messages", "Photo Messages", "Video Messages", "Audio Messages", "Emoji Messages", "Location Messages", "Url Messages", "Phone Messages", "ShareContact Messages"]
// MARK: - Picker
@@ -137,6 +137,7 @@ final internal class SettingsViewController: UITableViewController {
let cell = cells[sender.tag]
UserDefaults.standard.set(sender.isOn, forKey: cell)
UserDefaults.standard.synchronize()
}
}
+16
View File
@@ -50,6 +50,10 @@
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 */; };
50FF34552237FE4C0004DCD7 /* ContactItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50FF34542237FE4C0004DCD7 /* ContactItem.swift */; };
50FF34572237FE6A0004DCD7 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50FF34562237FE6A0004DCD7 /* UIImage+Extension.swift */; };
50FF34592237FE850004DCD7 /* ContactMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50FF34582237FE840004DCD7 /* ContactMessageCell.swift */; };
50FF345B2237FE9C0004DCD7 /* ContactMessageSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50FF345A2237FE9C0004DCD7 /* ContactMessageSizeCalculator.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 */; };
@@ -161,6 +165,10 @@
5073C1182175BE950040EAD5 /* AudioMessageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioMessageCell.swift; sourceTree = "<group>"; };
5073C11C2175BEC60040EAD5 /* AudioMessageSizeCalculator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioMessageSizeCalculator.swift; sourceTree = "<group>"; };
5073C1222175C1980040EAD5 /* sound1.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = sound1.m4a; sourceTree = "<group>"; };
50FF34542237FE4C0004DCD7 /* ContactItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactItem.swift; sourceTree = "<group>"; };
50FF34562237FE6A0004DCD7 /* UIImage+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Extension.swift"; sourceTree = "<group>"; };
50FF34582237FE840004DCD7 /* ContactMessageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactMessageCell.swift; sourceTree = "<group>"; };
50FF345A2237FE9C0004DCD7 /* ContactMessageSizeCalculator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactMessageSizeCalculator.swift; sourceTree = "<group>"; };
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 = "<group>"; };
@@ -250,6 +258,7 @@
B7A03F381F866946006AEF79 /* LocationMessageCell.swift */,
B7A03F391F866946006AEF79 /* MediaMessageCell.swift */,
5073C1182175BE950040EAD5 /* AudioMessageCell.swift */,
50FF34582237FE840004DCD7 /* ContactMessageCell.swift */,
B7A03F7A1F866B85006AEF79 /* MessageCollectionViewCell.swift */,
1F6C040B206A2891007BDE44 /* MessageContentCell.swift */,
B7A03F361F866946006AEF79 /* TextMessageCell.swift */,
@@ -393,6 +402,7 @@
B09643981F295D43004D0129 /* Extensions */ = {
isa = PBXGroup;
children = (
50FF34562237FE6A0004DCD7 /* UIImage+Extension.swift */,
0EE91E651FDEC887005420A2 /* CGRect+Extensions.swift */,
B7A03F671F8669EB006AEF79 /* Bundle+Extensions.swift */,
B7A03F681F8669EB006AEF79 /* NSAttributedString+Extensions.swift */,
@@ -444,6 +454,7 @@
B096439B1F295D82004D0129 /* Protocols */ = {
isa = PBXGroup;
children = (
50FF34542237FE4C0004DCD7 /* ContactItem.swift */,
B7A03F521F8669C9006AEF79 /* MessageCellDelegate.swift */,
B7A03F551F8669C9006AEF79 /* MessageLabelDelegate.swift */,
B7A03F571F8669CA006AEF79 /* MessagesDataSource.swift */,
@@ -471,6 +482,7 @@
B096439D1F295DC3004D0129 /* Layout */ = {
isa = PBXGroup;
children = (
50FF345A2237FE9C0004DCD7 /* ContactMessageSizeCalculator.swift */,
B7A03F161F86682C006AEF79 /* MessagesCollectionViewFlowLayout.swift */,
B7A03F171F86682C006AEF79 /* MessagesCollectionViewLayoutAttributes.swift */,
1FE7839D20662835007FA024 /* MessageSizeCalculator.swift */,
@@ -641,6 +653,7 @@
B7A03F6C1F8669EB006AEF79 /* UIView+Extensions.swift in Sources */,
383B9EB121728BAD008AB91A /* SenderType.swift in Sources */,
B7A03F3A1F866946006AEF79 /* TextMessageCell.swift in Sources */,
50FF34552237FE4C0004DCD7 /* ContactItem.swift in Sources */,
B7A03F191F86682C006AEF79 /* MessagesCollectionViewLayoutAttributes.swift in Sources */,
38A2230F221FB8A300D14DAF /* MessageInputBar.swift in Sources */,
B7A03F461F86694F006AEF79 /* AvatarView.swift in Sources */,
@@ -656,10 +669,12 @@
B7A03F261F866895006AEF79 /* MessageKitDateFormatter.swift in Sources */,
B7A03F6D1F8669EB006AEF79 /* Bundle+Extensions.swift in Sources */,
5073C1192175BE960040EAD5 /* AudioMessageCell.swift in Sources */,
50FF34592237FE850004DCD7 /* ContactMessageCell.swift in Sources */,
1FD589602064E08A004B5081 /* MediaItem.swift in Sources */,
B7A03F611F8669CA006AEF79 /* MessagesDataSource.swift in Sources */,
B7A03F6E1F8669EB006AEF79 /* NSAttributedString+Extensions.swift in Sources */,
B7A03F471F86694F006AEF79 /* MessageLabel.swift in Sources */,
50FF345B2237FE9C0004DCD7 /* ContactMessageSizeCalculator.swift in Sources */,
B7A03F5F1F8669CA006AEF79 /* MessageLabelDelegate.swift in Sources */,
B7A03F4C1F86694F006AEF79 /* PlayButtonView.swift in Sources */,
1FD5896420660C1C004B5081 /* LocationItem.swift in Sources */,
@@ -682,6 +697,7 @@
1F6C040C206A2891007BDE44 /* MessageContentCell.swift in Sources */,
B7A03F2C1F866895006AEF79 /* DetectorType.swift in Sources */,
B7A03F271F866895006AEF79 /* Avatar.swift in Sources */,
50FF34572237FE6A0004DCD7 /* UIImage+Extension.swift in Sources */,
1F82D1431FB1B75B00B81A88 /* AvatarPosition.swift in Sources */,
1FF377AC20087DA2004FD648 /* MessagesViewController+Keyboard.swift in Sources */,
);
@@ -289,6 +289,10 @@ UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
let cell = messagesCollectionView.dequeueReusableCell(AudioMessageCell.self, for: indexPath)
cell.configure(with: message, at: indexPath, and: messagesCollectionView)
return cell
case .contact:
let cell = messagesCollectionView.dequeueReusableCell(ContactMessageCell.self, for: indexPath)
cell.configure(with: message, at: indexPath, and: messagesCollectionView)
return cell
case .custom:
return messagesDataSource.customCell(for: message, at: indexPath, in: messagesCollectionView)
}
@@ -0,0 +1,43 @@
/*
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.
*/
public enum ImageType: String {
case play
case pause
case disclouser
}
import UIKit
/// This extension provide a way to access image resources with in framework
public extension UIImage {
public class func messageKitImageWith(type: ImageType) -> UIImage? {
let assetBundle = Bundle.messageKitAssetBundle()
let imagePath = assetBundle.path(forResource: type.rawValue, ofType: "png", inDirectory: "Images")
let image = UIImage(contentsOfFile: imagePath ?? "")
return image
}
}
@@ -0,0 +1,73 @@
/*
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
open class ContactMessageSizeCalculator: MessageSizeCalculator {
public var incomingMessageNameLabelInsets = UIEdgeInsets(top: 7, left: 46, bottom: 7, right: 30)
public var outgoingMessageNameLabelInsets = UIEdgeInsets(top: 7, left: 41, bottom: 7, right: 35)
public var contactLabelFont = UIFont.preferredFont(forTextStyle: .body)
internal func contactLabelInsets(for message: MessageType) -> UIEdgeInsets {
let dataSource = messagesLayout.messagesDataSource
let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
return isFromCurrentSender ? outgoingMessageNameLabelInsets : incomingMessageNameLabelInsets
}
open override func messageContainerMaxWidth(for message: MessageType) -> CGFloat {
let maxWidth = super.messageContainerMaxWidth(for: message)
let textInsets = contactLabelInsets(for: message)
return maxWidth - textInsets.horizontal
}
open override func messageContainerSize(for message: MessageType) -> CGSize {
let maxWidth = messageContainerMaxWidth(for: message)
var messageContainerSize: CGSize
let attributedText: NSAttributedString
switch message.kind {
case .contact(let item):
attributedText = NSAttributedString(string: item.displayName, attributes: [.font: contactLabelFont])
default:
fatalError("messageContainerSize received unhandled MessageDataType: \(message.kind)")
}
messageContainerSize = labelSize(for: attributedText, considering: maxWidth)
let messageInsets = contactLabelInsets(for: message)
messageContainerSize.width += messageInsets.horizontal
messageContainerSize.height += messageInsets.vertical
return messageContainerSize
}
open override func configure(attributes: UICollectionViewLayoutAttributes) {
super.configure(attributes: attributes)
guard let attributes = attributes as? MessagesCollectionViewLayoutAttributes else { return }
attributes.messageLabelFont = contactLabelFont
}
}
@@ -167,6 +167,7 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
lazy open var videoMessageSizeCalculator = MediaMessageSizeCalculator(layout: self)
lazy open var locationMessageSizeCalculator = LocationMessageSizeCalculator(layout: self)
lazy open var audioMessageSizeCalculator = AudioMessageSizeCalculator(layout: self)
lazy open var contactMessageSizeCalculator = ContactMessageSizeCalculator(layout: self)
lazy open var typingIndicatorSizeCalculator = TypingCellSizeCalculator(layout: self)
/// Note:
@@ -194,6 +195,8 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
return locationMessageSizeCalculator
case .audio:
return audioMessageSizeCalculator
case .contact:
return contactMessageSizeCalculator
case .custom:
return messagesLayoutDelegate.customCellSizeCalculator(for: message, at: indexPath, in: messagesCollectionView)
}
@@ -317,7 +320,8 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
photoMessageSizeCalculator,
videoMessageSizeCalculator,
locationMessageSizeCalculator,
audioMessageSizeCalculator
audioMessageSizeCalculator,
contactMessageSizeCalculator
]
}
+3
View File
@@ -53,6 +53,9 @@ public enum MessageKind {
/// An audio message.
case audio(AudioItem)
/// A contact message.
case contact(ContactItem)
/// A custom message.
/// - Note: Using this case requires that you implement the following methods and handle this case:
+41
View File
@@ -0,0 +1,41 @@
/*
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 protocol used to represent the data for a contact message.
public protocol ContactItem {
/// contact displayed name
var displayName: String { get }
/// initials from contact first and last name
var initials: String { get }
/// contact phone numbers
var phoneNumbers: [String] { get }
/// contact emails
var emails: [String] { get }
}
+2 -15
View File
@@ -28,17 +28,11 @@ import AVFoundation
/// A subclass of `MessageContentCell` used to display video and audio messages.
open class AudioMessageCell: MessageContentCell {
/// The `ImageName` enum holds the names of default iamges used to decorate play button
public enum ImageName: String {
case play
case pause
}
/// The play button view to display on audio messages.
public lazy var playButton: UIButton = {
let playButton = UIButton(type: .custom)
let playImage = AudioMessageCell.getImageWithName(.play)
let pauseImage = AudioMessageCell.getImageWithName(.pause)
let playImage = UIImage.messageKitImageWith(type: .play)
let pauseImage = UIImage.messageKitImageWith(type: .pause)
playButton.setImage(playImage?.withRenderingMode(.alwaysTemplate), for: .normal)
playButton.setImage(pauseImage?.withRenderingMode(.alwaysTemplate), for: .selected)
return playButton
@@ -84,13 +78,6 @@ open class AudioMessageCell: MessageContentCell {
durationLabel.text = "0:00"
}
open class func getImageWithName(_ imageName: ImageName) -> UIImage? {
let assetBundle = Bundle.messageKitAssetBundle()
let imagePath = assetBundle.path(forResource: imageName.rawValue, ofType: "png", inDirectory: "Images")
let image = UIImage(contentsOfFile: imagePath ?? "")
return image
}
/// Handle tap gesture on contentView and its subviews.
open override func handleTapGesture(_ gesture: UIGestureRecognizer) {
let touchLocation = gesture.location(in: self)
@@ -0,0 +1,142 @@
/*
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
open class ContactMessageCell: MessageContentCell {
public enum ConstraintsID: String {
case initialsContainerLeftConstraint
case disclouserRigtConstraint
}
/// The view container that holds contact initials
public lazy var initialsContainerView: UIView = {
let initialsContainer = UIView(frame: CGRect.zero)
initialsContainer.backgroundColor = .white
return initialsContainer
}()
/// The label that display the contact initials
public lazy var initialsLabel: UILabel = {
let initialsLabel = UILabel(frame: CGRect.zero)
initialsLabel.textAlignment = .center
initialsLabel.textColor = .darkText
initialsLabel.font = UIFont.preferredFont(forTextStyle: .footnote)
return initialsLabel
}()
/// The label that display contact name
public lazy var nameLabel: UILabel = {
let nameLabel = UILabel(frame: CGRect.zero)
nameLabel.numberOfLines = 0
return nameLabel
}()
/// The disclouser image view
public lazy var disclosureImageView: UIImageView = {
let disclouserImage = UIImage.messageKitImageWith(type: .disclouser)?.withRenderingMode(.alwaysTemplate)
let disclouser = UIImageView(image: disclouserImage)
return disclouser
}()
// MARK: - Methods
open override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
super.apply(layoutAttributes)
guard let attributes = layoutAttributes as? MessagesCollectionViewLayoutAttributes else {
return
}
nameLabel.font = attributes.messageLabelFont
}
open override func setupSubviews() {
super.setupSubviews()
messageContainerView.addSubview(initialsContainerView)
messageContainerView.addSubview(nameLabel)
messageContainerView.addSubview(disclosureImageView)
initialsContainerView.addSubview(initialsLabel)
setupConstraints()
}
open override func prepareForReuse() {
super.prepareForReuse()
nameLabel.text = ""
initialsLabel.text = ""
}
open func setupConstraints() {
initialsContainerView.constraint(equalTo: CGSize(width: 26, height: 26))
let initialsConstraints = initialsContainerView.addConstraints(left: messageContainerView.leftAnchor, centerY: messageContainerView.centerYAnchor,
leftConstant: 5)
initialsConstraints.first?.identifier = ConstraintsID.initialsContainerLeftConstraint.rawValue
initialsContainerView.layer.cornerRadius = 13
initialsLabel.fillSuperview()
disclosureImageView.constraint(equalTo: CGSize(width: 20, height: 20))
let disclosureConstraints = disclosureImageView.addConstraints(right: messageContainerView.rightAnchor, centerY: messageContainerView.centerYAnchor,
rightConstant: -10)
disclosureConstraints.first?.identifier = ConstraintsID.disclouserRigtConstraint.rawValue
nameLabel.addConstraints(messageContainerView.topAnchor,
left: initialsContainerView.rightAnchor,
bottom: messageContainerView.bottomAnchor,
right: disclosureImageView.leftAnchor,
topConstant: 0,
leftConstant: 10,
bottomConstant: 0,
rightConstant: 5)
}
// MARK: - Configure Cell
open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
super.configure(with: message, at: indexPath, and: messagesCollectionView)
// setup data
guard case let .contact(contactItem) = message.kind else { fatalError("Failed decorate audio cell") }
nameLabel.text = contactItem.displayName
initialsLabel.text = contactItem.initials
// setup constraints
guard let dataSource = messagesCollectionView.messagesDataSource else {
fatalError(MessageKitError.nilMessagesDataSource)
}
let initialsContainerLeftConstraint = messageContainerView.constraints.filter { (constraint) -> Bool in
return constraint.identifier == ConstraintsID.initialsContainerLeftConstraint.rawValue
}.first
let disclouserRightConstraint = messageContainerView.constraints.filter { (constraint) -> Bool in
return constraint.identifier == ConstraintsID.disclouserRigtConstraint.rawValue
}.first
if dataSource.isFromCurrentSender(message: message) { // outgoing message
initialsContainerLeftConstraint?.constant = 5
disclouserRightConstraint?.constant = -10
} else { // incoming message
initialsContainerLeftConstraint?.constant = 10
disclouserRightConstraint?.constant = -5
}
// setup colors
guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
fatalError(MessageKitError.nilMessagesDisplayDelegate)
}
let textColor = displayDelegate.textColor(for: message, at: indexPath, in: messagesCollectionView)
nameLabel.textColor = textColor
disclosureImageView.tintColor = textColor
}
}
@@ -77,6 +77,7 @@ open class MessagesCollectionView: UICollectionView {
register(MediaMessageCell.self)
register(LocationMessageCell.self)
register(AudioMessageCell.self)
register(ContactMessageCell.self)
register(TypingIndicatorCell.self)
register(MessageReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader)
register(MessageReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter)