mirror of
https://github.com/MessageKit/MessageKit.git
synced 2026-02-06 19:03:19 +00:00
Merge remote-tracking branch 'origin/3.0.0-beta' into typingIndicatorView
This commit is contained in:
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 |
@@ -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 */ = {
|
||||
|
||||
@@ -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] = []
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user