Compare commits
No commits in common. "master" and "develop-scrollviewperf" have entirely different histories.
master
...
develop-sc
@ -11,7 +11,7 @@
|
||||
77CC17A895E6E12BC9CB549A /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 97E6750B77E8A7042BA0754B /* libPods.a */; };
|
||||
88078A9D19D8FEB5005B4595 /* JSQMessagesMediaPlaceholderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 88078A9C19D8FEB5005B4595 /* JSQMessagesMediaPlaceholderView.m */; };
|
||||
88324C3419F6301C00BC732D /* JSQMessagesMediaViewBubbleImageMaskerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88324C3319F6301C00BC732D /* JSQMessagesMediaViewBubbleImageMaskerTests.m */; };
|
||||
883C11781A09FB100092A16D /* JSQMessagesCellTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 883C11771A09FB100092A16D /* JSQMessagesCellTextView.m */; };
|
||||
8841B88519F4988800EA16B6 /* JSQMessages.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8841B88719F4988800EA16B6 /* JSQMessages.strings */; };
|
||||
88445B3119E0AE3F0014F889 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88445B3019E0AE3F0014F889 /* UIKit.framework */; };
|
||||
88445B3319E0AE450014F889 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88445B3219E0AE450014F889 /* Foundation.framework */; };
|
||||
88445B3519E0AE4A0014F889 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88445B3419E0AE4A0014F889 /* CoreGraphics.framework */; };
|
||||
@ -51,14 +51,18 @@
|
||||
88A25FC119D8E01A00924534 /* JSQMessagesCollectionViewFlowLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F7119D8E01A00924534 /* JSQMessagesCollectionViewFlowLayout.m */; };
|
||||
88A25FC219D8E01A00924534 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F7319D8E01A00924534 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m */; };
|
||||
88A25FC319D8E01A00924534 /* JSQMessagesCollectionViewLayoutAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F7519D8E01A00924534 /* JSQMessagesCollectionViewLayoutAttributes.m */; };
|
||||
88A25FC419D8E01A00924534 /* JSQMediaMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F7819D8E01A00924534 /* JSQMediaMessage.m */; };
|
||||
88A25FC519D8E01A00924534 /* JSQMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F7A19D8E01A00924534 /* JSQMessage.m */; };
|
||||
88A25FC619D8E01A00924534 /* JSQMessagesAvatarImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8019D8E01A00924534 /* JSQMessagesAvatarImage.m */; };
|
||||
88A25FC719D8E01A00924534 /* JSQMessagesBubbleImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8219D8E01A00924534 /* JSQMessagesBubbleImage.m */; };
|
||||
88A25FC819D8E01A00924534 /* JSQPhotoMediaItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8619D8E01A00924534 /* JSQPhotoMediaItem.m */; };
|
||||
88A25FC919D8E01A00924534 /* JSQTextMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8819D8E01A00924534 /* JSQTextMessage.m */; };
|
||||
88A25FCA19D8E01A00924534 /* JSQMessagesCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8B19D8E01A00924534 /* JSQMessagesCollectionView.m */; };
|
||||
88A25FCB19D8E01A00924534 /* JSQMessagesCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8D19D8E01A00924534 /* JSQMessagesCollectionViewCell.m */; };
|
||||
88A25FCC19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8F19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.m */; };
|
||||
88A25FCD19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.xib in Resources */ = {isa = PBXBuildFile; fileRef = 88A25F9019D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.xib */; };
|
||||
88A25FCE19D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F9219D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.m */; };
|
||||
88A25FCF19D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.xib in Resources */ = {isa = PBXBuildFile; fileRef = 88A25F9319D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.xib */; };
|
||||
88A25FD019D8E01A00924534 /* JSQMessagesComposerTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F9519D8E01A00924534 /* JSQMessagesComposerTextView.m */; };
|
||||
88A25FD119D8E01A00924534 /* JSQMessagesInputToolbar.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F9719D8E01A00924534 /* JSQMessagesInputToolbar.m */; };
|
||||
88A25FD219D8E01A00924534 /* JSQMessagesLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F9919D8E01A00924534 /* JSQMessagesLabel.m */; };
|
||||
@ -83,10 +87,11 @@
|
||||
88A2600A19D8E18400924534 /* JSQMessagesToolbarButtonFactoryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FEE19D8E18400924534 /* JSQMessagesToolbarButtonFactoryTests.m */; };
|
||||
88A2600B19D8E18400924534 /* JSQMessagesCollectionViewFlowLayoutTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF019D8E18400924534 /* JSQMessagesCollectionViewFlowLayoutTests.m */; };
|
||||
88A2600C19D8E18400924534 /* JSQMessagesCollectionViewLayoutAttributesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF119D8E18400924534 /* JSQMessagesCollectionViewLayoutAttributesTests.m */; };
|
||||
88A2600D19D8E18400924534 /* JSQMessageMediaTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF319D8E18400924534 /* JSQMessageMediaTests.m */; };
|
||||
88A2600D19D8E18400924534 /* JSQMediaMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF319D8E18400924534 /* JSQMediaMessageTests.m */; };
|
||||
88A2600E19D8E18400924534 /* JSQMessagesAvatarImageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF419D8E18400924534 /* JSQMessagesAvatarImageTests.m */; };
|
||||
88A2600F19D8E18400924534 /* JSQMessagesBubbleImageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF519D8E18400924534 /* JSQMessagesBubbleImageTests.m */; };
|
||||
88A2601019D8E18400924534 /* JSQMessageTextTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF619D8E18400924534 /* JSQMessageTextTests.m */; };
|
||||
88A2601019D8E18400924534 /* JSQMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF619D8E18400924534 /* JSQMessageTests.m */; };
|
||||
88A2601119D8E18400924534 /* JSQTextMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF719D8E18400924534 /* JSQTextMessageTests.m */; };
|
||||
88A2601219D8E18400924534 /* JSQMessagesCollectionViewCellTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF919D8E18400924534 /* JSQMessagesCollectionViewCellTests.m */; };
|
||||
88A2601319D8E18400924534 /* JSQMessagesCollectionViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FFA19D8E18400924534 /* JSQMessagesCollectionViewTests.m */; };
|
||||
88A2601419D8E18400924534 /* JSQMessagesComposerTextViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FFB19D8E18400924534 /* JSQMessagesComposerTextViewTests.m */; };
|
||||
@ -97,29 +102,8 @@
|
||||
88A2601919D8E18400924534 /* JSQMessagesTypingIndicatorFooterViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A2600019D8E18400924534 /* JSQMessagesTypingIndicatorFooterViewTests.m */; };
|
||||
88A2601B19D8E45600924534 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 88A2601A19D8E45600924534 /* Info.plist */; };
|
||||
88A901B619F618B100F99777 /* JSQMediaItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A901B519F618B100F99777 /* JSQMediaItem.m */; };
|
||||
88C00A4E1A44D4C600B004B3 /* JSQLocationMediaItemTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C00A4D1A44D4C600B004B3 /* JSQLocationMediaItemTests.m */; };
|
||||
88C00A501A44D4D800B004B3 /* JSQPhotoMediaItemTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C00A4F1A44D4D800B004B3 /* JSQPhotoMediaItemTests.m */; };
|
||||
88C00A521A44D4E500B004B3 /* JSQVideoMediaItemTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C00A511A44D4E500B004B3 /* JSQVideoMediaItemTests.m */; };
|
||||
88C4583019F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C4582F19F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.m */; };
|
||||
88E4D7131A0DBD6B000CC061 /* JSQMessages.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8841B88719F4988800EA16B6 /* JSQMessages.strings */; };
|
||||
94A4FA20C2FBD0D62614D5A8 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 97E6750B77E8A7042BA0754B /* libPods.a */; };
|
||||
FC15B7A91A1E880900F59801 /* JSQCallCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = FC15B7A81A1E880900F59801 /* JSQCallCollectionViewCell.xib */; };
|
||||
FC15B7B01A1F6AC800F59801 /* JSQMessagesCollectionViewCellIncoming.xib in Resources */ = {isa = PBXBuildFile; fileRef = FC15B7AE1A1F6AC800F59801 /* JSQMessagesCollectionViewCellIncoming.xib */; };
|
||||
FC15B7B11A1F6AC800F59801 /* JSQMessagesCollectionViewCellOutgoing.xib in Resources */ = {isa = PBXBuildFile; fileRef = FC15B7AF1A1F6AC800F59801 /* JSQMessagesCollectionViewCellOutgoing.xib */; };
|
||||
FC4FA03A1A1E1BD100DA100A /* JSQCall.m in Sources */ = {isa = PBXBuildFile; fileRef = FC4FA0391A1E1BD100DA100A /* JSQCall.m */; };
|
||||
FC4FA03D1A1E81AF00DA100A /* JSQCallCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FC4FA03C1A1E81AF00DA100A /* JSQCallCollectionViewCell.m */; };
|
||||
FCA52AEF1A2B6ECE00CCADFA /* call_missed@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FCA52AEE1A2B6ECE00CCADFA /* call_missed@2x.png */; };
|
||||
FCA52AF51A2B6FAE00CCADFA /* call_canceled@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FCA52AF11A2B6FAE00CCADFA /* call_canceled@2x.png */; };
|
||||
FCA52AF61A2B6FAE00CCADFA /* call_failed@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FCA52AF21A2B6FAE00CCADFA /* call_failed@2x.png */; };
|
||||
FCA52AF71A2B6FAE00CCADFA /* call_incoming@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FCA52AF31A2B6FAE00CCADFA /* call_incoming@2x.png */; };
|
||||
FCA52AF81A2B6FAE00CCADFA /* call_outgoing@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FCA52AF41A2B6FAE00CCADFA /* call_outgoing@2x.png */; };
|
||||
FCA52B021A2B9F0E00CCADFA /* warning_white@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FCA52B001A2B9F0E00CCADFA /* warning_white@2x.png */; };
|
||||
FCA52B031A2B9F0E00CCADFA /* error_white@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FCA52B011A2B9F0E00CCADFA /* error_white@2x.png */; };
|
||||
FCFA5E131A29FC1000C8E32E /* JSQDisplayedMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = FCFA5E121A29FC1000C8E32E /* JSQDisplayedMessage.m */; };
|
||||
FCFA5E161A29FE3B00C8E32E /* JSQInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = FCFA5E151A29FE3B00C8E32E /* JSQInfoMessage.m */; };
|
||||
FCFA5E191A2A044500C8E32E /* JSQErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = FCFA5E181A2A044500C8E32E /* JSQErrorMessage.m */; };
|
||||
FCFA5E1D1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FCFA5E1B1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.m */; };
|
||||
FCFA5E1E1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = FCFA5E1C1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.xib */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -140,8 +124,6 @@
|
||||
88078A9B19D8FEB5005B4595 /* JSQMessagesMediaPlaceholderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesMediaPlaceholderView.h; sourceTree = "<group>"; };
|
||||
88078A9C19D8FEB5005B4595 /* JSQMessagesMediaPlaceholderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesMediaPlaceholderView.m; sourceTree = "<group>"; };
|
||||
88324C3319F6301C00BC732D /* JSQMessagesMediaViewBubbleImageMaskerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesMediaViewBubbleImageMaskerTests.m; sourceTree = "<group>"; };
|
||||
883C11761A09FB100092A16D /* JSQMessagesCellTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesCellTextView.h; sourceTree = "<group>"; };
|
||||
883C11771A09FB100092A16D /* JSQMessagesCellTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesCellTextView.m; sourceTree = "<group>"; };
|
||||
8841B88619F4988800EA16B6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/JSQMessages.strings; sourceTree = "<group>"; };
|
||||
8841B88819F4988900EA16B6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/JSQMessages.strings; sourceTree = "<group>"; };
|
||||
8841B88919F4988A00EA16B6 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/JSQMessages.strings; sourceTree = "<group>"; };
|
||||
@ -214,6 +196,8 @@
|
||||
88A25F7319D8E01A00924534 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesCollectionViewFlowLayoutInvalidationContext.m; sourceTree = "<group>"; };
|
||||
88A25F7419D8E01A00924534 /* JSQMessagesCollectionViewLayoutAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesCollectionViewLayoutAttributes.h; sourceTree = "<group>"; };
|
||||
88A25F7519D8E01A00924534 /* JSQMessagesCollectionViewLayoutAttributes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesCollectionViewLayoutAttributes.m; sourceTree = "<group>"; };
|
||||
88A25F7719D8E01A00924534 /* JSQMediaMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMediaMessage.h; sourceTree = "<group>"; };
|
||||
88A25F7819D8E01A00924534 /* JSQMediaMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMediaMessage.m; sourceTree = "<group>"; };
|
||||
88A25F7919D8E01A00924534 /* JSQMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessage.h; sourceTree = "<group>"; };
|
||||
88A25F7A19D8E01A00924534 /* JSQMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessage.m; sourceTree = "<group>"; };
|
||||
88A25F7B19D8E01A00924534 /* JSQMessageAvatarImageDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessageAvatarImageDataSource.h; sourceTree = "<group>"; };
|
||||
@ -228,14 +212,18 @@
|
||||
88A25F8419D8E01A00924534 /* JSQMessagesCollectionViewDelegateFlowLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesCollectionViewDelegateFlowLayout.h; sourceTree = "<group>"; };
|
||||
88A25F8519D8E01A00924534 /* JSQPhotoMediaItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQPhotoMediaItem.h; sourceTree = "<group>"; };
|
||||
88A25F8619D8E01A00924534 /* JSQPhotoMediaItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQPhotoMediaItem.m; sourceTree = "<group>"; };
|
||||
88A25F8719D8E01A00924534 /* JSQTextMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQTextMessage.h; sourceTree = "<group>"; };
|
||||
88A25F8819D8E01A00924534 /* JSQTextMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQTextMessage.m; sourceTree = "<group>"; };
|
||||
88A25F8A19D8E01A00924534 /* JSQMessagesCollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesCollectionView.h; sourceTree = "<group>"; };
|
||||
88A25F8B19D8E01A00924534 /* JSQMessagesCollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesCollectionView.m; sourceTree = "<group>"; };
|
||||
88A25F8C19D8E01A00924534 /* JSQMessagesCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesCollectionViewCell.h; sourceTree = "<group>"; };
|
||||
88A25F8D19D8E01A00924534 /* JSQMessagesCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesCollectionViewCell.m; sourceTree = "<group>"; };
|
||||
88A25F8E19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesCollectionViewCellIncoming.h; sourceTree = "<group>"; };
|
||||
88A25F8F19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesCollectionViewCellIncoming.m; sourceTree = "<group>"; };
|
||||
88A25F9019D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JSQMessagesCollectionViewCellIncoming.xib; sourceTree = "<group>"; };
|
||||
88A25F9119D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesCollectionViewCellOutgoing.h; sourceTree = "<group>"; };
|
||||
88A25F9219D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesCollectionViewCellOutgoing.m; sourceTree = "<group>"; };
|
||||
88A25F9319D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JSQMessagesCollectionViewCellOutgoing.xib; sourceTree = "<group>"; };
|
||||
88A25F9419D8E01A00924534 /* JSQMessagesComposerTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesComposerTextView.h; sourceTree = "<group>"; };
|
||||
88A25F9519D8E01A00924534 /* JSQMessagesComposerTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesComposerTextView.m; sourceTree = "<group>"; };
|
||||
88A25F9619D8E01A00924534 /* JSQMessagesInputToolbar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesInputToolbar.h; sourceTree = "<group>"; };
|
||||
@ -269,10 +257,11 @@
|
||||
88A25FEE19D8E18400924534 /* JSQMessagesToolbarButtonFactoryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesToolbarButtonFactoryTests.m; sourceTree = "<group>"; };
|
||||
88A25FF019D8E18400924534 /* JSQMessagesCollectionViewFlowLayoutTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesCollectionViewFlowLayoutTests.m; sourceTree = "<group>"; };
|
||||
88A25FF119D8E18400924534 /* JSQMessagesCollectionViewLayoutAttributesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesCollectionViewLayoutAttributesTests.m; sourceTree = "<group>"; };
|
||||
88A25FF319D8E18400924534 /* JSQMessageMediaTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessageMediaTests.m; sourceTree = "<group>"; };
|
||||
88A25FF319D8E18400924534 /* JSQMediaMessageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMediaMessageTests.m; sourceTree = "<group>"; };
|
||||
88A25FF419D8E18400924534 /* JSQMessagesAvatarImageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesAvatarImageTests.m; sourceTree = "<group>"; };
|
||||
88A25FF519D8E18400924534 /* JSQMessagesBubbleImageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesBubbleImageTests.m; sourceTree = "<group>"; };
|
||||
88A25FF619D8E18400924534 /* JSQMessageTextTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessageTextTests.m; sourceTree = "<group>"; };
|
||||
88A25FF619D8E18400924534 /* JSQMessageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessageTests.m; sourceTree = "<group>"; };
|
||||
88A25FF719D8E18400924534 /* JSQTextMessageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQTextMessageTests.m; sourceTree = "<group>"; };
|
||||
88A25FF919D8E18400924534 /* JSQMessagesCollectionViewCellTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesCollectionViewCellTests.m; sourceTree = "<group>"; };
|
||||
88A25FFA19D8E18400924534 /* JSQMessagesCollectionViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesCollectionViewTests.m; sourceTree = "<group>"; };
|
||||
88A25FFB19D8E18400924534 /* JSQMessagesComposerTextViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesComposerTextViewTests.m; sourceTree = "<group>"; };
|
||||
@ -284,36 +273,10 @@
|
||||
88A2601A19D8E45600924534 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
88A901B419F618B100F99777 /* JSQMediaItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMediaItem.h; sourceTree = "<group>"; };
|
||||
88A901B519F618B100F99777 /* JSQMediaItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMediaItem.m; sourceTree = "<group>"; };
|
||||
88C00A4D1A44D4C600B004B3 /* JSQLocationMediaItemTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQLocationMediaItemTests.m; sourceTree = "<group>"; };
|
||||
88C00A4F1A44D4D800B004B3 /* JSQPhotoMediaItemTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQPhotoMediaItemTests.m; sourceTree = "<group>"; };
|
||||
88C00A511A44D4E500B004B3 /* JSQVideoMediaItemTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQVideoMediaItemTests.m; sourceTree = "<group>"; };
|
||||
88C4582E19F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesMediaViewBubbleImageMasker.h; sourceTree = "<group>"; };
|
||||
88C4582F19F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesMediaViewBubbleImageMasker.m; sourceTree = "<group>"; };
|
||||
97E6750B77E8A7042BA0754B /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
FC15B7A81A1E880900F59801 /* JSQCallCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JSQCallCollectionViewCell.xib; sourceTree = "<group>"; };
|
||||
FC15B7AE1A1F6AC800F59801 /* JSQMessagesCollectionViewCellIncoming.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JSQMessagesCollectionViewCellIncoming.xib; sourceTree = "<group>"; };
|
||||
FC15B7AF1A1F6AC800F59801 /* JSQMessagesCollectionViewCellOutgoing.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JSQMessagesCollectionViewCellOutgoing.xib; sourceTree = "<group>"; };
|
||||
FC4FA0381A1E1BD100DA100A /* JSQCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQCall.h; sourceTree = "<group>"; };
|
||||
FC4FA0391A1E1BD100DA100A /* JSQCall.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQCall.m; sourceTree = "<group>"; };
|
||||
FC4FA03B1A1E81AF00DA100A /* JSQCallCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQCallCollectionViewCell.h; sourceTree = "<group>"; };
|
||||
FC4FA03C1A1E81AF00DA100A /* JSQCallCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQCallCollectionViewCell.m; sourceTree = "<group>"; };
|
||||
FC5C727E4CCDA2B95A7BA30C /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
FCA52AEE1A2B6ECE00CCADFA /* call_missed@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "call_missed@2x.png"; path = "../../JSQMessagesDemo/call_missed@2x.png"; sourceTree = "<group>"; };
|
||||
FCA52AF11A2B6FAE00CCADFA /* call_canceled@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "call_canceled@2x.png"; sourceTree = "<group>"; };
|
||||
FCA52AF21A2B6FAE00CCADFA /* call_failed@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "call_failed@2x.png"; sourceTree = "<group>"; };
|
||||
FCA52AF31A2B6FAE00CCADFA /* call_incoming@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "call_incoming@2x.png"; sourceTree = "<group>"; };
|
||||
FCA52AF41A2B6FAE00CCADFA /* call_outgoing@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "call_outgoing@2x.png"; sourceTree = "<group>"; };
|
||||
FCA52B001A2B9F0E00CCADFA /* warning_white@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "warning_white@2x.png"; sourceTree = "<group>"; };
|
||||
FCA52B011A2B9F0E00CCADFA /* error_white@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "error_white@2x.png"; sourceTree = "<group>"; };
|
||||
FCFA5E111A29FC1000C8E32E /* JSQDisplayedMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQDisplayedMessage.h; sourceTree = "<group>"; };
|
||||
FCFA5E121A29FC1000C8E32E /* JSQDisplayedMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQDisplayedMessage.m; sourceTree = "<group>"; };
|
||||
FCFA5E141A29FE3B00C8E32E /* JSQInfoMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQInfoMessage.h; sourceTree = "<group>"; };
|
||||
FCFA5E151A29FE3B00C8E32E /* JSQInfoMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQInfoMessage.m; sourceTree = "<group>"; };
|
||||
FCFA5E171A2A044500C8E32E /* JSQErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQErrorMessage.h; sourceTree = "<group>"; };
|
||||
FCFA5E181A2A044500C8E32E /* JSQErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQErrorMessage.m; sourceTree = "<group>"; };
|
||||
FCFA5E1A1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQDisplayedMessageCollectionViewCell.h; sourceTree = "<group>"; };
|
||||
FCFA5E1B1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQDisplayedMessageCollectionViewCell.m; sourceTree = "<group>"; };
|
||||
FCFA5E1C1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JSQDisplayedMessageCollectionViewCell.xib; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -375,7 +338,6 @@
|
||||
88445B3A19E0C0B10014F889 /* XCTest.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
path = ../..;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8841B88219F4983C00EA16B6 /* Strings */ = {
|
||||
@ -391,6 +353,7 @@
|
||||
children = (
|
||||
886C33FE19F45E30006B4997 /* JSQMessagesViewController.podspec */,
|
||||
88A25F3E19D8E01A00924534 /* JSQMessagesViewController */,
|
||||
636A8663AEEE5C37B65C515D /* Frameworks */,
|
||||
88A25F2B19D8DF2500924534 /* JSQMessagesDemo */,
|
||||
88A25F1E19D8DEC500924534 /* JSQMessagesTests */,
|
||||
2BBEF3CD91C31A49E5FF9E3C /* Pods */,
|
||||
@ -470,8 +433,6 @@
|
||||
88A25F3F19D8E01A00924534 /* Assets */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FCA52AFB1A2B9BAD00CCADFA /* InfoError */,
|
||||
FCA52AF01A2B6F8A00CCADFA /* Calls */,
|
||||
8841B88219F4983C00EA16B6 /* Strings */,
|
||||
8861666C19F492B70025B958 /* JSQMessagesAssets.bundle */,
|
||||
);
|
||||
@ -546,6 +507,8 @@
|
||||
88445B3F19E1B4470014F889 /* JSQLocationMediaItem.m */,
|
||||
88A901B419F618B100F99777 /* JSQMediaItem.h */,
|
||||
88A901B519F618B100F99777 /* JSQMediaItem.m */,
|
||||
88A25F7719D8E01A00924534 /* JSQMediaMessage.h */,
|
||||
88A25F7819D8E01A00924534 /* JSQMediaMessage.m */,
|
||||
88A25F7919D8E01A00924534 /* JSQMessage.h */,
|
||||
88A25F7A19D8E01A00924534 /* JSQMessage.m */,
|
||||
88A25F7B19D8E01A00924534 /* JSQMessageAvatarImageDataSource.h */,
|
||||
@ -560,16 +523,10 @@
|
||||
88A25F8419D8E01A00924534 /* JSQMessagesCollectionViewDelegateFlowLayout.h */,
|
||||
88A25F8519D8E01A00924534 /* JSQPhotoMediaItem.h */,
|
||||
88A25F8619D8E01A00924534 /* JSQPhotoMediaItem.m */,
|
||||
88A25F8719D8E01A00924534 /* JSQTextMessage.h */,
|
||||
88A25F8819D8E01A00924534 /* JSQTextMessage.m */,
|
||||
886C33FB19F4371E006B4997 /* JSQVideoMediaItem.h */,
|
||||
886C33FC19F4371E006B4997 /* JSQVideoMediaItem.m */,
|
||||
FC4FA0381A1E1BD100DA100A /* JSQCall.h */,
|
||||
FC4FA0391A1E1BD100DA100A /* JSQCall.m */,
|
||||
FCFA5E111A29FC1000C8E32E /* JSQDisplayedMessage.h */,
|
||||
FCFA5E121A29FC1000C8E32E /* JSQDisplayedMessage.m */,
|
||||
FCFA5E141A29FE3B00C8E32E /* JSQInfoMessage.h */,
|
||||
FCFA5E151A29FE3B00C8E32E /* JSQInfoMessage.m */,
|
||||
FCFA5E171A2A044500C8E32E /* JSQErrorMessage.h */,
|
||||
FCFA5E181A2A044500C8E32E /* JSQErrorMessage.m */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
@ -577,19 +534,16 @@
|
||||
88A25F8919D8E01A00924534 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
636A8663AEEE5C37B65C515D /* Frameworks */,
|
||||
883C11761A09FB100092A16D /* JSQMessagesCellTextView.h */,
|
||||
883C11771A09FB100092A16D /* JSQMessagesCellTextView.m */,
|
||||
88A25F8A19D8E01A00924534 /* JSQMessagesCollectionView.h */,
|
||||
88A25F8B19D8E01A00924534 /* JSQMessagesCollectionView.m */,
|
||||
88A25F8C19D8E01A00924534 /* JSQMessagesCollectionViewCell.h */,
|
||||
88A25F8D19D8E01A00924534 /* JSQMessagesCollectionViewCell.m */,
|
||||
88A25F8E19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.h */,
|
||||
88A25F8F19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.m */,
|
||||
FC15B7AE1A1F6AC800F59801 /* JSQMessagesCollectionViewCellIncoming.xib */,
|
||||
88A25F9019D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.xib */,
|
||||
88A25F9119D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.h */,
|
||||
88A25F9219D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.m */,
|
||||
FC15B7AF1A1F6AC800F59801 /* JSQMessagesCollectionViewCellOutgoing.xib */,
|
||||
88A25F9319D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.xib */,
|
||||
88A25F9419D8E01A00924534 /* JSQMessagesComposerTextView.h */,
|
||||
88A25F9519D8E01A00924534 /* JSQMessagesComposerTextView.m */,
|
||||
88A25F9619D8E01A00924534 /* JSQMessagesInputToolbar.h */,
|
||||
@ -607,12 +561,6 @@
|
||||
88A25FA019D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.h */,
|
||||
88A25FA119D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.m */,
|
||||
88A25FA219D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.xib */,
|
||||
FC4FA03B1A1E81AF00DA100A /* JSQCallCollectionViewCell.h */,
|
||||
FC4FA03C1A1E81AF00DA100A /* JSQCallCollectionViewCell.m */,
|
||||
FC15B7A81A1E880900F59801 /* JSQCallCollectionViewCell.xib */,
|
||||
FCFA5E1A1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.h */,
|
||||
FCFA5E1B1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.m */,
|
||||
FCFA5E1C1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.xib */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
@ -661,13 +609,11 @@
|
||||
88A25FF219D8E18400924534 /* ModelTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
88C00A4D1A44D4C600B004B3 /* JSQLocationMediaItemTests.m */,
|
||||
88A25FF319D8E18400924534 /* JSQMessageMediaTests.m */,
|
||||
88A25FF319D8E18400924534 /* JSQMediaMessageTests.m */,
|
||||
88A25FF419D8E18400924534 /* JSQMessagesAvatarImageTests.m */,
|
||||
88A25FF519D8E18400924534 /* JSQMessagesBubbleImageTests.m */,
|
||||
88A25FF619D8E18400924534 /* JSQMessageTextTests.m */,
|
||||
88C00A4F1A44D4D800B004B3 /* JSQPhotoMediaItemTests.m */,
|
||||
88C00A511A44D4E500B004B3 /* JSQVideoMediaItemTests.m */,
|
||||
88A25FF619D8E18400924534 /* JSQMessageTests.m */,
|
||||
88A25FF719D8E18400924534 /* JSQTextMessageTests.m */,
|
||||
);
|
||||
path = ModelTests;
|
||||
sourceTree = "<group>";
|
||||
@ -687,27 +633,6 @@
|
||||
path = ViewTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FCA52AF01A2B6F8A00CCADFA /* Calls */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FCA52AF11A2B6FAE00CCADFA /* call_canceled@2x.png */,
|
||||
FCA52AF21A2B6FAE00CCADFA /* call_failed@2x.png */,
|
||||
FCA52AF31A2B6FAE00CCADFA /* call_incoming@2x.png */,
|
||||
FCA52AF41A2B6FAE00CCADFA /* call_outgoing@2x.png */,
|
||||
FCA52AEE1A2B6ECE00CCADFA /* call_missed@2x.png */,
|
||||
);
|
||||
name = Calls;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FCA52AFB1A2B9BAD00CCADFA /* InfoError */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FCA52B001A2B9F0E00CCADFA /* warning_white@2x.png */,
|
||||
FCA52B011A2B9F0E00CCADFA /* error_white@2x.png */,
|
||||
);
|
||||
name = InfoError;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -805,26 +730,17 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
88E4D7131A0DBD6B000CC061 /* JSQMessages.strings in Resources */,
|
||||
886C33FF19F45E30006B4997 /* JSQMessagesViewController.podspec in Resources */,
|
||||
8861666D19F492B70025B958 /* JSQMessagesAssets.bundle in Resources */,
|
||||
FC15B7B11A1F6AC800F59801 /* JSQMessagesCollectionViewCellOutgoing.xib in Resources */,
|
||||
88A25FCF19D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.xib in Resources */,
|
||||
88A25FCD19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.xib in Resources */,
|
||||
8841B88519F4988800EA16B6 /* JSQMessages.strings in Resources */,
|
||||
88A25FD619D8E01A00924534 /* JSQMessagesToolbarContentView.xib in Resources */,
|
||||
FCA52AF71A2B6FAE00CCADFA /* call_incoming@2x.png in Resources */,
|
||||
88A25F3A19D8DF2500924534 /* Images.xcassets in Resources */,
|
||||
88A25FBC19D8E01A00924534 /* JSQMessagesViewController.xib in Resources */,
|
||||
FCA52AF81A2B6FAE00CCADFA /* call_outgoing@2x.png in Resources */,
|
||||
FCA52B021A2B9F0E00CCADFA /* warning_white@2x.png in Resources */,
|
||||
FCA52AF51A2B6FAE00CCADFA /* call_canceled@2x.png in Resources */,
|
||||
FCA52B031A2B9F0E00CCADFA /* error_white@2x.png in Resources */,
|
||||
FCA52AEF1A2B6ECE00CCADFA /* call_missed@2x.png in Resources */,
|
||||
88A25FD819D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.xib in Resources */,
|
||||
FCFA5E1E1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.xib in Resources */,
|
||||
88A25F3919D8DF2500924534 /* Main.storyboard in Resources */,
|
||||
FC15B7B01A1F6AC800F59801 /* JSQMessagesCollectionViewCellIncoming.xib in Resources */,
|
||||
88A25FD419D8E01A00924534 /* JSQMessagesLoadEarlierHeaderView.xib in Resources */,
|
||||
FC15B7A91A1E880900F59801 /* JSQCallCollectionViewCell.xib in Resources */,
|
||||
FCA52AF61A2B6FAE00CCADFA /* call_failed@2x.png in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -912,9 +828,7 @@
|
||||
88A25FCB19D8E01A00924534 /* JSQMessagesCollectionViewCell.m in Sources */,
|
||||
88A25FBB19D8E01A00924534 /* JSQMessagesViewController.m in Sources */,
|
||||
8885734D19DE55D000E89D20 /* NSUserDefaults+DemoSettings.m in Sources */,
|
||||
883C11781A09FB100092A16D /* JSQMessagesCellTextView.m in Sources */,
|
||||
88A25FB919D8E01A00924534 /* UIView+JSQMessages.m in Sources */,
|
||||
FCFA5E131A29FC1000C8E32E /* JSQDisplayedMessage.m in Sources */,
|
||||
88A25FCA19D8E01A00924534 /* JSQMessagesCollectionView.m in Sources */,
|
||||
88A25FD219D8E01A00924534 /* JSQMessagesLabel.m in Sources */,
|
||||
88445B4019E1B4470014F889 /* JSQLocationMediaItem.m in Sources */,
|
||||
@ -922,23 +836,19 @@
|
||||
88A25FD519D8E01A00924534 /* JSQMessagesToolbarContentView.m in Sources */,
|
||||
88A25FC119D8E01A00924534 /* JSQMessagesCollectionViewFlowLayout.m in Sources */,
|
||||
8885734A19DE540400E89D20 /* DemoSettingsViewController.m in Sources */,
|
||||
FC4FA03A1A1E1BD100DA100A /* JSQCall.m in Sources */,
|
||||
88A25FC719D8E01A00924534 /* JSQMessagesBubbleImage.m in Sources */,
|
||||
88A25FC519D8E01A00924534 /* JSQMessage.m in Sources */,
|
||||
88A25FD719D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.m in Sources */,
|
||||
88A25FD319D8E01A00924534 /* JSQMessagesLoadEarlierHeaderView.m in Sources */,
|
||||
FC4FA03D1A1E81AF00DA100A /* JSQCallCollectionViewCell.m in Sources */,
|
||||
88A25FC819D8E01A00924534 /* JSQPhotoMediaItem.m in Sources */,
|
||||
88C4583019F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.m in Sources */,
|
||||
88A25FB819D8E01A00924534 /* UIImage+JSQMessages.m in Sources */,
|
||||
88A25FBF19D8E01A00924534 /* JSQMessagesTimestampFormatter.m in Sources */,
|
||||
88A25FE019D8E0C400924534 /* DemoModelData.m in Sources */,
|
||||
FCFA5E1D1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.m in Sources */,
|
||||
88A25F3C19D8DF2500924534 /* main.m in Sources */,
|
||||
88A25F3719D8DF2500924534 /* AppDelegate.m in Sources */,
|
||||
886FFD2E19E9A65D00EB8485 /* UIDevice+JSQMessages.m in Sources */,
|
||||
88A25FB619D8E01A00924534 /* NSString+JSQMessages.m in Sources */,
|
||||
FCFA5E191A2A044500C8E32E /* JSQErrorMessage.m in Sources */,
|
||||
88A901B619F618B100F99777 /* JSQMediaItem.m in Sources */,
|
||||
88A25FCC19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.m in Sources */,
|
||||
88A25FBE19D8E01A00924534 /* JSQMessagesBubbleImageFactory.m in Sources */,
|
||||
@ -946,8 +856,9 @@
|
||||
88A25FB719D8E01A00924534 /* UIColor+JSQMessages.m in Sources */,
|
||||
886C33FD19F4371E006B4997 /* JSQVideoMediaItem.m in Sources */,
|
||||
88A25FBA19D8E01A00924534 /* JSQMessagesKeyboardController.m in Sources */,
|
||||
FCFA5E161A29FE3B00C8E32E /* JSQInfoMessage.m in Sources */,
|
||||
88A25FC019D8E01A00924534 /* JSQMessagesToolbarButtonFactory.m in Sources */,
|
||||
88A25FC919D8E01A00924534 /* JSQTextMessage.m in Sources */,
|
||||
88A25FC419D8E01A00924534 /* JSQMediaMessage.m in Sources */,
|
||||
88A25FC219D8E01A00924534 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m in Sources */,
|
||||
88A25FE119D8E0C400924534 /* TableViewController.m in Sources */,
|
||||
88A25FBD19D8E01A00924534 /* JSQMessagesAvatarImageFactory.m in Sources */,
|
||||
@ -963,14 +874,13 @@
|
||||
files = (
|
||||
88A2600219D8E18400924534 /* JSQMessagesUIColorTests.m in Sources */,
|
||||
88A2601819D8E18400924534 /* JSQMessagesToolbarContentViewTests.m in Sources */,
|
||||
88C00A521A44D4E500B004B3 /* JSQVideoMediaItemTests.m in Sources */,
|
||||
88A2601519D8E18400924534 /* JSQMessagesInputToolbarTests.m in Sources */,
|
||||
88A2601719D8E18400924534 /* JSQMessagesLoadEarlierHeaderViewTests.m in Sources */,
|
||||
88A2601219D8E18400924534 /* JSQMessagesCollectionViewCellTests.m in Sources */,
|
||||
88A2601619D8E18400924534 /* JSQMessagesLabelTests.m in Sources */,
|
||||
88A2600B19D8E18400924534 /* JSQMessagesCollectionViewFlowLayoutTests.m in Sources */,
|
||||
88A2601019D8E18400924534 /* JSQMessageTextTests.m in Sources */,
|
||||
88A2600D19D8E18400924534 /* JSQMessageMediaTests.m in Sources */,
|
||||
88A2601019D8E18400924534 /* JSQMessageTests.m in Sources */,
|
||||
88A2600D19D8E18400924534 /* JSQMediaMessageTests.m in Sources */,
|
||||
88A2600719D8E18400924534 /* JSQMessagesAvatarImageFactoryTests.m in Sources */,
|
||||
88A2600419D8E18400924534 /* JSQMessagesUIViewTests.m in Sources */,
|
||||
88A2600F19D8E18400924534 /* JSQMessagesBubbleImageTests.m in Sources */,
|
||||
@ -979,12 +889,11 @@
|
||||
88A2601419D8E18400924534 /* JSQMessagesComposerTextViewTests.m in Sources */,
|
||||
88A2601319D8E18400924534 /* JSQMessagesCollectionViewTests.m in Sources */,
|
||||
88A2600119D8E18400924534 /* JSQMessagesNSStringTests.m in Sources */,
|
||||
88A2601119D8E18400924534 /* JSQTextMessageTests.m in Sources */,
|
||||
88A2600A19D8E18400924534 /* JSQMessagesToolbarButtonFactoryTests.m in Sources */,
|
||||
88C00A501A44D4D800B004B3 /* JSQPhotoMediaItemTests.m in Sources */,
|
||||
88324C3419F6301C00BC732D /* JSQMessagesMediaViewBubbleImageMaskerTests.m in Sources */,
|
||||
88A2601919D8E18400924534 /* JSQMessagesTypingIndicatorFooterViewTests.m in Sources */,
|
||||
88A2600319D8E18400924534 /* JSQMessagesUIImageTests.m in Sources */,
|
||||
88C00A4E1A44D4C600B004B3 /* JSQLocationMediaItemTests.m in Sources */,
|
||||
88A2600C19D8E18400924534 /* JSQMessagesCollectionViewLayoutAttributesTests.m in Sources */,
|
||||
88A2600619D8E18400924534 /* JSQMessagesViewControllerTests.m in Sources */,
|
||||
88A2600519D8E18400924534 /* JSQMessagesKeyboardControllerTests.m in Sources */,
|
||||
@ -1121,14 +1030,11 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
INFOPLIST_FILE = "$(SRCROOT)/JSQMessagesDemo/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@ -1139,14 +1045,11 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
INFOPLIST_FILE = "$(SRCROOT)/JSQMessagesDemo/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
@ -45,4 +45,6 @@
|
||||
|
||||
- (void)closePressed:(UIBarButtonItem *)sender;
|
||||
|
||||
// TODO: example of async avatar loading
|
||||
|
||||
@end
|
||||
|
||||
@ -18,12 +18,6 @@
|
||||
|
||||
#import "DemoMessagesViewController.h"
|
||||
|
||||
#import "JSQCallCollectionViewCell.h"
|
||||
#import "JSQCall.h"
|
||||
|
||||
#import "JSQDisplayedMessageCollectionViewCell.h"
|
||||
#import "JSQErrorMessage.h"
|
||||
#import "JSQInfoMessage.h"
|
||||
|
||||
@implementation DemoMessagesViewController
|
||||
|
||||
@ -49,7 +43,7 @@
|
||||
*/
|
||||
self.senderId = kJSQDemoAvatarIdSquires;
|
||||
self.senderDisplayName = kJSQDemoAvatarDisplayNameSquires;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Load up our fake data for the demo
|
||||
@ -74,13 +68,6 @@
|
||||
style:UIBarButtonItemStyleBordered
|
||||
target:self
|
||||
action:@selector(receiveMessagePressed:)];
|
||||
|
||||
/**
|
||||
* Customize your toolbar buttons
|
||||
*
|
||||
* self.inputToolbar.contentView.leftBarButtonItem = custom button or nil to remove
|
||||
* self.inputToolbar.contentView.rightBarButtonItem = custom button or nil to remove
|
||||
*/
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
@ -108,16 +95,6 @@
|
||||
|
||||
|
||||
|
||||
#pragma mark - Testing
|
||||
|
||||
- (void)pushMainViewController
|
||||
{
|
||||
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
|
||||
UINavigationController *nc = [sb instantiateInitialViewController];
|
||||
[self.navigationController pushViewController:nc.topViewController animated:YES];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (void)receiveMessagePressed:(UIBarButtonItem *)sender
|
||||
@ -146,9 +123,9 @@
|
||||
JSQMessage *copyMessage = [[self.demoData.messages lastObject] copy];
|
||||
|
||||
if (!copyMessage) {
|
||||
copyMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdJobs
|
||||
displayName:kJSQDemoAvatarDisplayNameJobs
|
||||
text:@"First received!"];
|
||||
copyMessage = [JSQTextMessage messageWithSenderId:kJSQDemoAvatarIdJobs
|
||||
displayName:kJSQDemoAvatarDisplayNameJobs
|
||||
text:@"First received!"];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -164,7 +141,7 @@
|
||||
id<JSQMessageMediaData> newMediaData = nil;
|
||||
id newMediaAttachmentCopy = nil;
|
||||
|
||||
if ([copyMessage isKindOfClass:[JSQMessage class]]) {
|
||||
if ([copyMessage isKindOfClass:[JSQMediaMessage class]]) {
|
||||
/**
|
||||
* Last message was a media message
|
||||
*/
|
||||
@ -212,17 +189,17 @@
|
||||
NSLog(@"%s error: unrecognized media item", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
newMessage = [JSQMessage messageWithSenderId:randomUserId
|
||||
displayName:self.demoData.users[randomUserId]
|
||||
media:newMediaData];
|
||||
newMessage = [JSQMediaMessage messageWithSenderId:randomUserId
|
||||
displayName:self.demoData.users[randomUserId]
|
||||
media:newMediaData];
|
||||
}
|
||||
else {
|
||||
/**
|
||||
* Last message was a text message
|
||||
*/
|
||||
newMessage = [JSQMessage messageWithSenderId:randomUserId
|
||||
displayName:self.demoData.users[randomUserId]
|
||||
text:copyMessage.text];
|
||||
newMessage = [JSQTextMessage messageWithSenderId:randomUserId
|
||||
displayName:self.demoData.users[randomUserId]
|
||||
text:copyMessage.text];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -234,10 +211,10 @@
|
||||
*/
|
||||
[JSQSystemSoundPlayer jsq_playMessageReceivedSound];
|
||||
[self.demoData.messages addObject:newMessage];
|
||||
[self finishReceivingMessageAnimated:YES];
|
||||
[self finishReceivingMessage];
|
||||
|
||||
|
||||
if (newMessage.isMediaMessage) {
|
||||
if ([newMessage isKindOfClass:[JSQMediaMessage class]]) {
|
||||
/**
|
||||
* Simulate "downloading" media
|
||||
*/
|
||||
@ -299,14 +276,13 @@
|
||||
*/
|
||||
[JSQSystemSoundPlayer jsq_playMessageSentSound];
|
||||
|
||||
JSQMessage *message = [[JSQMessage alloc] initWithSenderId:senderId
|
||||
senderDisplayName:senderDisplayName
|
||||
date:date
|
||||
text:text];
|
||||
JSQTextMessage *message = [[JSQTextMessage alloc] initWithSenderId:senderId
|
||||
senderDisplayName:senderDisplayName
|
||||
date:date
|
||||
text:text];
|
||||
|
||||
[self.demoData.messages addObject:message];
|
||||
|
||||
[self finishSendingMessageAnimated:YES];
|
||||
[self finishSendingMessage];
|
||||
}
|
||||
|
||||
- (void)didPressAccessoryButton:(UIButton *)sender
|
||||
@ -347,8 +323,7 @@
|
||||
}
|
||||
|
||||
[JSQSystemSoundPlayer jsq_playMessageSentSound];
|
||||
|
||||
[self finishSendingMessageAnimated:YES];
|
||||
[self finishSendingMessage];
|
||||
}
|
||||
|
||||
|
||||
@ -374,7 +349,7 @@
|
||||
if ([message.senderId isEqualToString:self.senderId]) {
|
||||
return self.demoData.outgoingBubbleImageData;
|
||||
}
|
||||
|
||||
|
||||
return self.demoData.incomingBubbleImageData;
|
||||
}
|
||||
|
||||
@ -402,8 +377,6 @@
|
||||
*/
|
||||
JSQMessage *message = [self.demoData.messages objectAtIndex:indexPath.item];
|
||||
|
||||
if (![message isKindOfClass:[JSQCall class]] || ![message isKindOfClass:[JSQErrorMessage class]] || ![message isKindOfClass:[JSQInfoMessage class]]) return nil;
|
||||
|
||||
if ([message.senderId isEqualToString:self.senderId]) {
|
||||
if (![NSUserDefaults outgoingAvatarSetting]) {
|
||||
return nil;
|
||||
@ -414,7 +387,8 @@
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return [self.demoData.avatars objectForKey:message.senderId];
|
||||
}
|
||||
|
||||
@ -475,34 +449,38 @@
|
||||
/**
|
||||
* Override point for customizing cells
|
||||
*/
|
||||
JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
|
||||
|
||||
/**
|
||||
* Configure almost *anything* on the cell
|
||||
*
|
||||
* Text colors, label text, label colors, etc.
|
||||
*
|
||||
*
|
||||
* DO NOT set `cell.textView.font` !
|
||||
* Instead, you need to set `self.collectionView.collectionViewLayout.messageBubbleFont` to the font you want in `viewDidLoad`
|
||||
*
|
||||
*
|
||||
* DO NOT manipulate cell layout information!
|
||||
* Instead, override the properties you want on `self.collectionView.collectionViewLayout` from `viewDidLoad`
|
||||
*/
|
||||
|
||||
JSQMessage *msg = [self.demoData.messages objectAtIndex:indexPath.item];
|
||||
|
||||
if ([msg isKindOfClass:[JSQMessage class]])
|
||||
{
|
||||
JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
|
||||
if (!msg.isMediaMessage) {
|
||||
if ([msg.senderId isEqualToString:self.senderId]) {
|
||||
cell.textView.textColor = [UIColor blackColor];
|
||||
}
|
||||
else {
|
||||
cell.textView.textColor = [UIColor whiteColor];
|
||||
}
|
||||
|
||||
cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor,
|
||||
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };
|
||||
|
||||
if ([msg isKindOfClass:[JSQTextMessage class]]) {
|
||||
|
||||
if ([msg.senderId isEqualToString:self.senderId]) {
|
||||
cell.textView.textColor = [UIColor blackColor];
|
||||
}
|
||||
else {
|
||||
cell.textView.textColor = [UIColor whiteColor];
|
||||
}
|
||||
|
||||
return cell;
|
||||
|
||||
} else if ([msg isKindOfClass:[JSQCall class]]) {
|
||||
JSQCallCollectionViewCell *cell = (JSQCallCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
|
||||
return cell;
|
||||
} else {
|
||||
JSQDisplayedMessageCollectionViewCell * cell = (JSQDisplayedMessageCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
|
||||
return cell;
|
||||
cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor,
|
||||
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
|
||||
@ -524,9 +502,9 @@
|
||||
*
|
||||
* Show a timestamp for every 3rd message
|
||||
*/
|
||||
// if (indexPath.item % 3 == 0) {
|
||||
// return kJSQMessagesCollectionViewCellLabelHeightDefault;
|
||||
// }
|
||||
if (indexPath.item % 3 == 0) {
|
||||
return kJSQMessagesCollectionViewCellLabelHeightDefault;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
@ -20,9 +20,6 @@
|
||||
|
||||
#import "NSUserDefaults+DemoSettings.h"
|
||||
|
||||
#import "JSQCall.h"
|
||||
#import "JSQInfoMessage.h"
|
||||
#import "JSQErrorMessage.h"
|
||||
|
||||
/**
|
||||
* This is for demo/testing purposes only.
|
||||
@ -36,7 +33,7 @@
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
|
||||
|
||||
if ([NSUserDefaults emptyMessagesSetting]) {
|
||||
self.messages = [NSMutableArray new];
|
||||
}
|
||||
@ -85,7 +82,7 @@
|
||||
* Be sure to create your bubble images one time and reuse them for good performance.
|
||||
*
|
||||
*/
|
||||
JSQMessagesBubbleImageFactory *bubbleFactory = [[JSQMessagesBubbleImageFactory alloc] init];
|
||||
JSQMessagesBubbleImageFactory *bubbleFactory = [[JSQMessagesBubbleImageFactory alloc] init];
|
||||
|
||||
self.outgoingBubbleImageData = [bubbleFactory outgoingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleLightGrayColor]];
|
||||
self.incomingBubbleImageData = [bubbleFactory incomingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleGreenColor]];
|
||||
@ -102,75 +99,35 @@
|
||||
* You should have a mutable array or orderedSet, or something.
|
||||
*/
|
||||
self.messages = [[NSMutableArray alloc] initWithObjects:
|
||||
[[JSQCall alloc] initWithCallerId:kJSQDemoAvatarIdWoz
|
||||
callerDisplayName:kJSQDemoAvatarDisplayNameWoz
|
||||
date:[NSDate date]
|
||||
status:kCallOutgoing],
|
||||
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
|
||||
[[JSQTextMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameSquires
|
||||
date:[NSDate distantPast]
|
||||
text:@"Welcome to JSQMessages: A messaging UI framework for iOS."],
|
||||
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameSquires
|
||||
date:[NSDate distantPast]
|
||||
text:@"Welcome to JSQMessages: A messaging UI framework for iOS."],
|
||||
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdWoz
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameWoz
|
||||
date:[NSDate distantPast]
|
||||
text:@"It is simple, elegant, and easy to use. There are super sweet default settings, but you can customize like crazy."],
|
||||
|
||||
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameSquires
|
||||
date:[NSDate distantPast]
|
||||
text:@"It even has data detectors. You can call me tonight. My cell number is 123-456-7890. My website is www.hexedbits.com."],
|
||||
[[JSQTextMessage alloc] initWithSenderId:kJSQDemoAvatarIdWoz
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameWoz
|
||||
date:[NSDate distantPast]
|
||||
text:@"It is simple, elegant, and easy to use. There are super sweet default settings, but you can customize like crazy."],
|
||||
|
||||
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdJobs
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameJobs
|
||||
date:[NSDate date]
|
||||
text:@"JSQMessagesViewController is nearly an exact replica of the iOS Messages App. And perhaps, better."],
|
||||
[[JSQTextMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameSquires
|
||||
date:[NSDate distantPast]
|
||||
text:@"It even has data detectors. You can call me tonight. My cell number is 123-456-7890. My website is www.hexedbits.com."],
|
||||
|
||||
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdCook
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameCook
|
||||
date:[NSDate date]
|
||||
text:@"It is unit-tested, free, open-source, and documented."],
|
||||
[[JSQTextMessage alloc] initWithSenderId:kJSQDemoAvatarIdJobs
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameJobs
|
||||
date:[NSDate date]
|
||||
text:@"JSQMessagesViewController is nearly an exact replica of the iOS Messages App. And perhaps, better."],
|
||||
|
||||
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
|
||||
[[JSQTextMessage alloc] initWithSenderId:kJSQDemoAvatarIdCook
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameCook
|
||||
date:[NSDate date]
|
||||
text:@"It is unit-tested, free, open-source, and documented."],
|
||||
|
||||
[[JSQTextMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameSquires
|
||||
date:[NSDate date]
|
||||
text:@"Now with media messages!"],
|
||||
[[JSQCall alloc] initWithCallerId:kJSQDemoAvatarIdWoz
|
||||
callerDisplayName:kJSQDemoAvatarDisplayNameWoz
|
||||
date:[NSDate date]
|
||||
status:kCallIncoming],
|
||||
[[JSQCall alloc] initWithCallerId:kJSQDemoAvatarIdWoz
|
||||
callerDisplayName:kJSQDemoAvatarDisplayNameWoz
|
||||
date:[NSDate date]
|
||||
status:kCallMissed],
|
||||
[[JSQInfoMessage alloc] initWithInfoType:JSQInfoMessageTypeSessionDidEnd
|
||||
senderId:kJSQDemoAvatarIdCook
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameCook
|
||||
date:[NSDate date]],
|
||||
[[JSQErrorMessage alloc] initWithErrorType:JSQErrorMessageMissingKeyId
|
||||
senderId:kJSQDemoAvatarIdCook
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameCook
|
||||
date:[NSDate date]],
|
||||
[[JSQErrorMessage alloc] initWithErrorType:JSQErrorMessageInvalidMessage
|
||||
senderId:kJSQDemoAvatarIdCook
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameCook
|
||||
date:[NSDate date]],
|
||||
[[JSQErrorMessage alloc] initWithErrorType:JSQErrorMessageInvalidVersion
|
||||
senderId:kJSQDemoAvatarIdCook
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameCook
|
||||
date:[NSDate date]],
|
||||
[[JSQErrorMessage alloc] initWithErrorType:JSQErrorMessageInvalidKeyException
|
||||
senderId:kJSQDemoAvatarIdCook
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameCook
|
||||
date:[NSDate date]],
|
||||
[[JSQErrorMessage alloc] initWithErrorType:JSQErrorMessageWrongTrustedIdentityKey
|
||||
senderId:kJSQDemoAvatarIdCook
|
||||
senderDisplayName:kJSQDemoAvatarDisplayNameCook
|
||||
date:[NSDate date]],
|
||||
|
||||
nil];
|
||||
|
||||
[self addPhotoMediaMessage];
|
||||
@ -191,9 +148,9 @@
|
||||
* You should see "END" twice
|
||||
*/
|
||||
if ([NSUserDefaults longMessageSetting]) {
|
||||
JSQMessage *reallyLongMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires
|
||||
displayName:kJSQDemoAvatarDisplayNameSquires
|
||||
text:@"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? END Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? END"];
|
||||
JSQTextMessage *reallyLongMessage = [JSQTextMessage messageWithSenderId:kJSQDemoAvatarIdSquires
|
||||
displayName:kJSQDemoAvatarDisplayNameSquires
|
||||
text:@"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? END Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? END"];
|
||||
|
||||
[self.messages addObject:reallyLongMessage];
|
||||
}
|
||||
@ -202,9 +159,9 @@
|
||||
- (void)addPhotoMediaMessage
|
||||
{
|
||||
JSQPhotoMediaItem *photoItem = [[JSQPhotoMediaItem alloc] initWithImage:[UIImage imageNamed:@"goldengate"]];
|
||||
JSQMessage *photoMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires
|
||||
displayName:kJSQDemoAvatarDisplayNameSquires
|
||||
media:photoItem];
|
||||
JSQMediaMessage *photoMessage = [JSQMediaMessage messageWithSenderId:kJSQDemoAvatarIdSquires
|
||||
displayName:kJSQDemoAvatarDisplayNameSquires
|
||||
media:photoItem];
|
||||
[self.messages addObject:photoMessage];
|
||||
}
|
||||
|
||||
@ -215,9 +172,9 @@
|
||||
JSQLocationMediaItem *locationItem = [[JSQLocationMediaItem alloc] init];
|
||||
[locationItem setLocation:ferryBuildingInSF withCompletionHandler:completion];
|
||||
|
||||
JSQMessage *locationMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires
|
||||
displayName:kJSQDemoAvatarDisplayNameSquires
|
||||
media:locationItem];
|
||||
JSQMediaMessage *locationMessage = [JSQMediaMessage messageWithSenderId:kJSQDemoAvatarIdSquires
|
||||
displayName:kJSQDemoAvatarDisplayNameSquires
|
||||
media:locationItem];
|
||||
[self.messages addObject:locationMessage];
|
||||
}
|
||||
|
||||
@ -227,9 +184,9 @@
|
||||
NSURL *videoURL = [NSURL URLWithString:@"file://"];
|
||||
|
||||
JSQVideoMediaItem *videoItem = [[JSQVideoMediaItem alloc] initWithFileURL:videoURL isReadyToPlay:YES];
|
||||
JSQMessage *videoMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires
|
||||
displayName:kJSQDemoAvatarDisplayNameSquires
|
||||
media:videoItem];
|
||||
JSQMediaMessage *videoMessage = [JSQMediaMessage messageWithSenderId:kJSQDemoAvatarIdSquires
|
||||
displayName:kJSQDemoAvatarDisplayNameSquires
|
||||
media:videoItem];
|
||||
[self.messages addObject:videoMessage];
|
||||
}
|
||||
|
||||
|
||||
@ -15,11 +15,11 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>6.1.1</string>
|
||||
<string>6.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>6.1.1</string>
|
||||
<string>6.0.0</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
|
||||
|
Before Width: | Height: | Size: 14 KiB |
@ -16,22 +16,56 @@
|
||||
|
||||
|
||||
@interface JSQMessagesToolbarButtonFactoryTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation JSQMessagesToolbarButtonFactoryTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
{
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testDefaultSendButtonItem
|
||||
{
|
||||
UIButton *button = [JSQMessagesToolbarButtonFactory defaultSendButtonItem];
|
||||
XCTAssertNotNil(button, @"Button should not be nil");
|
||||
|
||||
XCTAssertTrue(CGRectEqualToRect(button.frame, CGRectZero), @"Button initial frame should equal CGRectZero");
|
||||
|
||||
NSString *title = @"Send";
|
||||
XCTAssertEqualObjects([button titleForState:UIControlStateNormal], title, @"Button title should equal %@", title);
|
||||
XCTAssertNil(button.imageView.image, @"Button image should be nil");
|
||||
|
||||
XCTAssertEqualObjects([button titleColorForState:UIControlStateNormal], [UIColor jsq_messageBubbleBlueColor], @"Button normal title color should be set");
|
||||
XCTAssertEqualObjects([button titleColorForState:UIControlStateHighlighted], [[UIColor jsq_messageBubbleBlueColor] jsq_colorByDarkeningColorWithValue:0.1f], @"Button highlighted title color should be set");
|
||||
XCTAssertEqualObjects([button titleColorForState:UIControlStateDisabled], [UIColor lightGrayColor], @"Button disabled title color should be set");
|
||||
|
||||
XCTAssertEqualObjects(button.titleLabel.font, [UIFont boldSystemFontOfSize:17.0f], @"Button font should be set");
|
||||
XCTAssertEqual(button.contentMode, UIViewContentModeCenter, @"Button content mode should be set");
|
||||
XCTAssertEqualObjects(button.backgroundColor, [UIColor clearColor], @"Button background color should be set");
|
||||
XCTAssertEqualObjects(button.tintColor, [UIColor jsq_messageBubbleBlueColor], @"Button tint color should be set");
|
||||
}
|
||||
|
||||
- (void)testDefaultAccessoryButtonItem
|
||||
{
|
||||
UIButton *button = [JSQMessagesToolbarButtonFactory defaultAccessoryButtonItem];
|
||||
XCTAssertNotNil(button, @"Button should not be nil");
|
||||
|
||||
XCTAssertTrue(CGRectEqualToRect(button.frame, CGRectZero), @"Button frame should equal CGRectZero");
|
||||
|
||||
XCTAssertNil(button.titleLabel.text, @"Button title should be nil");
|
||||
XCTAssertNotNil([button imageForState:UIControlStateNormal], @"Button normal image should not be nil");
|
||||
XCTAssertNotNil([button imageForState:UIControlStateHighlighted], @"Button highlighted image should not be nil");
|
||||
|
||||
XCTAssertEqual(button.contentMode, UIViewContentModeScaleAspectFit, @"Button content mode should be set");
|
||||
XCTAssertEqualObjects(button.backgroundColor, [UIColor clearColor], @"Button background color should be set");
|
||||
XCTAssertEqualObjects(button.tintColor, [UIColor lightGrayColor], @"Button tint color should be set");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
||||
JSQMessagesCollectionViewLayoutAttributes *attrs = [JSQMessagesCollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
|
||||
attrs.messageBubbleFont = [UIFont systemFontOfSize:15.0f];
|
||||
attrs.messageBubbleContainerViewWidth = 40.0f;
|
||||
attrs.messageBubbleLeftRightMargin = 40.0f;
|
||||
attrs.textViewTextContainerInsets = UIEdgeInsetsMake(10.0f, 8.0f, 10.0f, 8.0f);
|
||||
attrs.textViewFrameInsets = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 6.0f);
|
||||
attrs.incomingAvatarViewSize = CGSizeMake(34.0f, 34.0f);
|
||||
|
||||
@ -1,64 +0,0 @@
|
||||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// MIT License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "JSQLocationMediaItem.h"
|
||||
|
||||
|
||||
@interface JSQLocationMediaItemTests : XCTestCase
|
||||
|
||||
@property (strong, nonatomic) CLLocation *location;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation JSQLocationMediaItemTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
self.location = [[CLLocation alloc] initWithLatitude:37.795313 longitude:-122.393757];
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
{
|
||||
self.location = nil;
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testLocationItemInit
|
||||
{
|
||||
JSQLocationMediaItem *item = [[JSQLocationMediaItem alloc] initWithLocation:self.location];
|
||||
XCTAssertNotNil(item);
|
||||
}
|
||||
|
||||
- (void)testMediaDataProtocol
|
||||
{
|
||||
JSQLocationMediaItem *item = [[JSQLocationMediaItem alloc] init];
|
||||
|
||||
XCTAssertTrue(!CGSizeEqualToSize([item mediaViewDisplaySize], CGSizeZero));
|
||||
XCTAssertNotNil([item mediaPlaceholderView]);
|
||||
XCTAssertNil([item mediaView], @"Media view should be nil if location is nil");
|
||||
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:[NSString stringWithFormat:@"%s", __PRETTY_FUNCTION__]];
|
||||
|
||||
[item setLocation:self.location withCompletionHandler:^{
|
||||
[expectation fulfill];
|
||||
}];
|
||||
|
||||
[self waitForExpectationsWithTimeout:5 handler:^(NSError *error) {
|
||||
XCTAssertNil(error, @"Expectation should not error");
|
||||
}];
|
||||
|
||||
XCTAssertNotNil([item mediaView], @"Media view should NOT be nil once item has media data");
|
||||
}
|
||||
|
||||
@end
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
#import <OCMock/OCMock.h>
|
||||
|
||||
#import "JSQMessage.h"
|
||||
#import "JSQMediaMessage.h"
|
||||
|
||||
|
||||
// Fake media object for testing
|
||||
@ -35,7 +35,7 @@
|
||||
|
||||
|
||||
|
||||
@interface JSQMessageMediaTests : XCTestCase
|
||||
@interface JSQMediaMessageTests : XCTestCase
|
||||
|
||||
@property (strong, nonatomic) NSString *senderId;
|
||||
@property (strong, nonatomic) NSString *senderDisplayName;
|
||||
@ -45,7 +45,7 @@
|
||||
@end
|
||||
|
||||
|
||||
@implementation JSQMessageMediaTests
|
||||
@implementation JSQMediaMessageTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
@ -65,46 +65,46 @@
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testMediaMessageInit
|
||||
- (void)testTextMessageInit
|
||||
{
|
||||
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId
|
||||
senderDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
media:self.mockMediaData];
|
||||
JSQMediaMessage *msg = [[JSQMediaMessage alloc] initWithSenderId:self.senderId
|
||||
senderDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
media:self.mockMediaData];
|
||||
XCTAssertNotNil(msg, @"Message should not be nil");
|
||||
}
|
||||
|
||||
- (void)testMediaMessageInvalidInit
|
||||
- (void)testMessageInvalidInit
|
||||
{
|
||||
XCTAssertThrows([[JSQMessage alloc] init], @"Invalid init should throw");
|
||||
XCTAssertThrows([[JSQMessage alloc] initWithSenderId:nil senderDisplayName:nil date:nil media:nil], @"Invalid init should throw");
|
||||
XCTAssertThrows([[JSQMediaMessage alloc] init], @"Invalid init should throw");
|
||||
XCTAssertThrows([[JSQMediaMessage alloc] initWithSenderId:nil senderDisplayName:nil date:nil media:nil], @"Invalid init should throw");
|
||||
}
|
||||
|
||||
- (void)testMediaMessageIsEqual
|
||||
- (void)testMessageIsEqual
|
||||
{
|
||||
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId
|
||||
senderDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
media:self.mockMediaData];
|
||||
JSQMessage *copy = [msg copy];
|
||||
JSQMediaMessage *msg = [[JSQMediaMessage alloc] initWithSenderId:self.senderId
|
||||
senderDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
media:self.mockMediaData];
|
||||
JSQMediaMessage *copy = [msg copy];
|
||||
|
||||
XCTAssertEqualObjects(msg, copy, @"Copied messages should be equal");
|
||||
|
||||
XCTAssertEqual([msg hash], [copy hash], @"Copied messages hashes should be equal");
|
||||
|
||||
XCTAssertEqualObjects(msg, copy, @"Copied messages should be equal");
|
||||
XCTAssertEqualObjects(msg, msg, @"Messages should be equal to itself");
|
||||
}
|
||||
|
||||
- (void)testMediaMessageArchiving
|
||||
- (void)testMessageArchiving
|
||||
{
|
||||
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId
|
||||
senderDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
media:[FakeMedia new]];
|
||||
JSQMediaMessage *msg = [[JSQMediaMessage alloc] initWithSenderId:self.senderId
|
||||
senderDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
media:[FakeMedia new]];
|
||||
|
||||
NSData *msgData = [NSKeyedArchiver archivedDataWithRootObject:msg];
|
||||
|
||||
JSQMessage *unarchivedMsg = [NSKeyedUnarchiver unarchiveObjectWithData:msgData];
|
||||
JSQMediaMessage *unarchivedMsg = [NSKeyedUnarchiver unarchiveObjectWithData:msgData];
|
||||
|
||||
XCTAssertEqualObjects(msg, unarchivedMsg, @"Message should be equal");
|
||||
}
|
||||
@ -13,29 +13,23 @@
|
||||
#import "JSQMessage.h"
|
||||
|
||||
|
||||
@interface JSQMessageTextTests : XCTestCase
|
||||
@interface JSQMessageTests : XCTestCase
|
||||
|
||||
@property (strong, nonatomic) NSString *senderId;
|
||||
@property (strong, nonatomic) NSString *senderDisplayName;
|
||||
@property (strong, nonatomic) NSDate *date;
|
||||
@property (strong, nonatomic) NSString *text;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation JSQMessageTextTests
|
||||
@implementation JSQMessageTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
|
||||
self.senderId = @"324543-43556-212343";
|
||||
self.senderDisplayName = @"Jesse Squires";
|
||||
self.date = [NSDate date];
|
||||
|
||||
self.text = @"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque"
|
||||
@"laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi"
|
||||
@"architecto beatae vitae dicta sunt explicabo.";
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
@ -43,48 +37,39 @@
|
||||
self.senderId = nil;
|
||||
self.senderDisplayName = nil;
|
||||
self.date = nil;
|
||||
self.text = nil;
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
#pragma mark - Text messages
|
||||
|
||||
- (void)testTextMessageInit
|
||||
- (void)testMessageInit
|
||||
{
|
||||
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId
|
||||
senderDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
text:self.text];
|
||||
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId senderDisplayName:self.senderDisplayName date:self.date isMedia:NO];
|
||||
XCTAssertNotNil(msg, @"Message should not be nil");
|
||||
}
|
||||
|
||||
- (void)testTextMessageInvalidInit
|
||||
- (void)testMessageInvalidInit
|
||||
{
|
||||
XCTAssertThrows([[JSQMessage alloc] init], @"Invalid init should throw");
|
||||
XCTAssertThrows([[JSQMessage alloc] initWithSenderId:nil senderDisplayName:nil date:nil text:nil], @"Invalid init should throw");
|
||||
XCTAssertThrows([[JSQMessage alloc] initWithSenderId:nil senderDisplayName:nil date:nil isMedia:NO], @"Invalid init should throw");
|
||||
XCTAssertThrows([[JSQMessage alloc] initWithSenderId:self.senderId senderDisplayName:nil date:nil isMedia:YES], @"Invalid init should throw");
|
||||
XCTAssertThrows([[JSQMessage alloc] initWithSenderId:nil senderDisplayName:self.senderDisplayName date:nil isMedia:NO], @"Invalid init should throw");
|
||||
XCTAssertThrows([[JSQMessage alloc] initWithSenderId:nil senderDisplayName:nil date:self.date isMedia:YES], @"Invalid init should throw");
|
||||
}
|
||||
|
||||
- (void)testTextMessageIsEqual
|
||||
- (void)testMessageIsEqual
|
||||
{
|
||||
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId
|
||||
senderDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
text:self.text];
|
||||
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId senderDisplayName:self.senderDisplayName date:self.date isMedia:NO];
|
||||
JSQMessage *copy = [msg copy];
|
||||
|
||||
XCTAssertEqualObjects(msg, copy, @"Copied messages should be equal");
|
||||
|
||||
XCTAssertEqual([msg hash], [copy hash], @"Copied messages hashes should be equal");
|
||||
|
||||
XCTAssertEqualObjects(msg, copy, @"Copied messages should be equal");
|
||||
XCTAssertEqualObjects(msg, msg, @"Messages should be equal to itself");
|
||||
}
|
||||
|
||||
- (void)testTextMessageArchiving
|
||||
- (void)testMessageArchiving
|
||||
{
|
||||
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId
|
||||
senderDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
text:self.text];
|
||||
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId senderDisplayName:self.senderDisplayName date:self.date isMedia:YES];
|
||||
NSData *msgData = [NSKeyedArchiver archivedDataWithRootObject:msg];
|
||||
|
||||
JSQMessage *unarchivedMsg = [NSKeyedUnarchiver unarchiveObjectWithData:msgData];
|
||||
@ -1,76 +0,0 @@
|
||||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// MIT License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "JSQPhotoMediaItem.h"
|
||||
|
||||
|
||||
@interface JSQPhotoMediaItemTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation JSQPhotoMediaItemTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
{
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testPhotoItemInit
|
||||
{
|
||||
JSQPhotoMediaItem *item = [[JSQPhotoMediaItem alloc] initWithImage:[UIImage new]];
|
||||
XCTAssertNotNil(item);
|
||||
}
|
||||
|
||||
- (void)testPhotoItemIsEqual
|
||||
{
|
||||
JSQPhotoMediaItem *item = [[JSQPhotoMediaItem alloc] initWithImage:[UIImage imageNamed:@"demo_avatar_jobs"]];
|
||||
|
||||
JSQPhotoMediaItem *copy = [item copy];
|
||||
|
||||
XCTAssertEqualObjects(item, copy, @"Copied items should be equal");
|
||||
|
||||
XCTAssertEqual([item hash], [copy hash], @"Copied item hashes should be equal");
|
||||
|
||||
XCTAssertEqualObjects(item, item, @"Item should be equal to itself");
|
||||
}
|
||||
|
||||
- (void)testPhotoItemArchiving
|
||||
{
|
||||
JSQPhotoMediaItem *item = [[JSQPhotoMediaItem alloc] initWithImage:[UIImage new]];
|
||||
|
||||
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:item];
|
||||
|
||||
JSQPhotoMediaItem *unarchivedItem = [NSKeyedUnarchiver unarchiveObjectWithData:data];
|
||||
|
||||
XCTAssertEqualObjects(item, unarchivedItem);
|
||||
}
|
||||
|
||||
- (void)testMediaDataProtocol
|
||||
{
|
||||
JSQPhotoMediaItem *item = [[JSQPhotoMediaItem alloc] initWithImage:nil];
|
||||
|
||||
XCTAssertTrue(!CGSizeEqualToSize([item mediaViewDisplaySize], CGSizeZero));
|
||||
XCTAssertNotNil([item mediaPlaceholderView]);
|
||||
XCTAssertNil([item mediaView], @"Media view should be nil if image is nil");
|
||||
|
||||
item.image = [UIImage imageNamed:@"demo_avatar_jobs"];
|
||||
|
||||
XCTAssertNotNil([item mediaView], @"Media view should NOT be nil once item has media data");
|
||||
}
|
||||
|
||||
@end
|
||||
91
JSQMessagesTests/ModelTests/JSQTextMessageTests.m
Normal file
@ -0,0 +1,91 @@
|
||||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// MIT License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "JSQTextMessage.h"
|
||||
|
||||
|
||||
@interface JSQTextMessageTests : XCTestCase
|
||||
|
||||
@property (strong, nonatomic) NSString *senderId;
|
||||
@property (strong, nonatomic) NSString *senderDisplayName;
|
||||
@property (strong, nonatomic) NSDate *date;
|
||||
@property (strong, nonatomic) NSString *text;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation JSQTextMessageTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
self.senderId = @"324543-43556-212343";
|
||||
self.senderDisplayName = @"Jesse Squires";
|
||||
self.date = [NSDate date];
|
||||
self.text = @"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque"
|
||||
@"laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi"
|
||||
@"architecto beatae vitae dicta sunt explicabo.";
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
{
|
||||
self.senderId = nil;
|
||||
self.senderDisplayName = nil;
|
||||
self.date = nil;
|
||||
self.text = nil;
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testTextMessageInit
|
||||
{
|
||||
JSQTextMessage *msg = [[JSQTextMessage alloc] initWithSenderId:self.senderId
|
||||
senderDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
text:self.text];
|
||||
XCTAssertNotNil(msg, @"Message should not be nil");
|
||||
}
|
||||
|
||||
- (void)testMessageInvalidInit
|
||||
{
|
||||
XCTAssertThrows([[JSQTextMessage alloc] init], @"Invalid init should throw");
|
||||
XCTAssertThrows([[JSQTextMessage alloc] initWithSenderId:nil senderDisplayName:nil date:nil text:nil], @"Invalid init should throw");
|
||||
}
|
||||
|
||||
- (void)testMessageIsEqual
|
||||
{
|
||||
JSQTextMessage *msg = [[JSQTextMessage alloc] initWithSenderId:self.senderId
|
||||
senderDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
text:self.text];
|
||||
JSQTextMessage *copy = [msg copy];
|
||||
|
||||
XCTAssertEqualObjects(msg, copy, @"Copied messages should be equal");
|
||||
XCTAssertEqual([msg hash], [copy hash], @"Copied messages hashes should be equal");
|
||||
|
||||
XCTAssertEqualObjects(msg, copy, @"Copied messages should be equal");
|
||||
XCTAssertEqualObjects(msg, msg, @"Messages should be equal to itself");
|
||||
}
|
||||
|
||||
- (void)testMessageArchiving
|
||||
{
|
||||
JSQTextMessage *msg = [[JSQTextMessage alloc] initWithSenderId:self.senderId
|
||||
senderDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
text:self.text];
|
||||
NSData *msgData = [NSKeyedArchiver archivedDataWithRootObject:msg];
|
||||
|
||||
JSQTextMessage *unarchivedMsg = [NSKeyedUnarchiver unarchiveObjectWithData:msgData];
|
||||
|
||||
XCTAssertEqualObjects(msg, unarchivedMsg, @"Message should be equal");
|
||||
}
|
||||
|
||||
@end
|
||||
@ -1,77 +0,0 @@
|
||||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// MIT License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "JSQVideoMediaItem.h"
|
||||
|
||||
|
||||
@interface JSQVideoMediaItemTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation JSQVideoMediaItemTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
{
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testVideoMediaItemInit
|
||||
{
|
||||
JSQVideoMediaItem *item = [[JSQVideoMediaItem alloc] initWithFileURL:[NSURL URLWithString:@"file://"] isReadyToPlay:NO];
|
||||
XCTAssertNotNil(item);
|
||||
}
|
||||
|
||||
- (void)testVideoItemIsEqual
|
||||
{
|
||||
JSQVideoMediaItem *item = [[JSQVideoMediaItem alloc] initWithFileURL:[NSURL URLWithString:@"file://"] isReadyToPlay:YES];
|
||||
|
||||
JSQVideoMediaItem *copy = [item copy];
|
||||
|
||||
XCTAssertEqualObjects(item, copy, @"Copied items should be equal");
|
||||
|
||||
XCTAssertEqual([item hash], [copy hash], @"Copied item hashes should be equal");
|
||||
|
||||
XCTAssertEqualObjects(item, item, @"Item should be equal to itself");
|
||||
}
|
||||
|
||||
- (void)testVideoItemArchiving
|
||||
{
|
||||
JSQVideoMediaItem *item = [[JSQVideoMediaItem alloc] initWithFileURL:[NSURL URLWithString:@"file://"] isReadyToPlay:YES];
|
||||
|
||||
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:item];
|
||||
|
||||
JSQVideoMediaItem *unarchivedItem = [NSKeyedUnarchiver unarchiveObjectWithData:data];
|
||||
|
||||
XCTAssertEqualObjects(item, unarchivedItem);
|
||||
}
|
||||
|
||||
- (void)testMediaDataProtocol
|
||||
{
|
||||
JSQVideoMediaItem *item = [[JSQVideoMediaItem alloc] init];
|
||||
|
||||
XCTAssertTrue(!CGSizeEqualToSize([item mediaViewDisplaySize], CGSizeZero));
|
||||
XCTAssertNotNil([item mediaPlaceholderView]);
|
||||
XCTAssertNil([item mediaView], @"Media view should be nil if fileURL is nil, and readyToPlay is NO");
|
||||
|
||||
item.fileURL = [NSURL URLWithString:@"file://"];
|
||||
item.isReadyToPlay = YES;
|
||||
|
||||
XCTAssertNotNil([item mediaView], @"Media view should NOT be nil once item has media data");
|
||||
}
|
||||
|
||||
@end
|
||||
@ -54,7 +54,7 @@
|
||||
XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.textView.scrollIndicatorInsets, UIEdgeInsetsMake(6.0f, 0.0f, 6.0f, 0.0f)), @"Property should be equal to default value");
|
||||
|
||||
XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.textView.textContainerInset, UIEdgeInsetsMake(4.0f, 2.0f, 4.0f, 2.0f)), @"Property should be equal to default value");
|
||||
XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.textView.contentInset, UIEdgeInsetsMake(1.0f, 0.0f, 1.0f, 0.0f)), @"Property should be equal to default value");
|
||||
XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.textView.contentInset, UIEdgeInsetsMake(2.0f, 0.0f, 2.0f, 0.0f)), @"Property should be equal to default value");
|
||||
|
||||
XCTAssertEqual(self.textView.scrollEnabled, YES, @"Property should be equal to default value");
|
||||
XCTAssertEqual(self.textView.scrollsToTop, NO, @"Property should be equal to default value");
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'JSQMessagesViewController'
|
||||
s.version = '6.1.1'
|
||||
s.version = '6.0-beta6'
|
||||
s.summary = 'An elegant messages UI library for iOS.'
|
||||
s.homepage = 'http://jessesquires.github.io/JSQMessagesViewController'
|
||||
s.license = 'MIT'
|
||||
s.screenshots = ['https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot0.png',
|
||||
'https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot1.png',
|
||||
'https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot2.png',
|
||||
'https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot3.png']
|
||||
'https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot1.png']
|
||||
s.author = { 'Jesse Squires' => 'jesse.squires.developer@gmail.com' }
|
||||
s.social_media_url = 'https://twitter.com/jesse_squires'
|
||||
s.source = { :git => 'https://github.com/jessesquires/JSQMessagesViewController.git', :tag => s.version.to_s }
|
||||
|
||||
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
@ -32,32 +32,11 @@
|
||||
*/
|
||||
+ (UIColor *)jsq_messageBubbleBlueColor;
|
||||
|
||||
/**
|
||||
* @return A color object containing HSB values similar to the iOS 7 red color.
|
||||
*/
|
||||
+ (UIColor *)jsq_messageBubbleRedColor;
|
||||
|
||||
/**
|
||||
* @return A color object containing HSB values similar to the iOS 7 messages app light gray bubble color.
|
||||
*/
|
||||
+ (UIColor *)jsq_messageBubbleLightGrayColor;
|
||||
|
||||
/**
|
||||
* @return A color object containing HSB values similar to Signal gray bubble color.
|
||||
*/
|
||||
+ (UIColor *)jsq_messageBubbleGrayColor;
|
||||
|
||||
/**
|
||||
* @return A color object containing HSB values similar to Signal light blue bubble color.
|
||||
*/
|
||||
+ (UIColor *)jsq_messageBubbleLightBlueColor;
|
||||
|
||||
/**
|
||||
* @return A color object containing HSB values similar to Signal background gray color.
|
||||
*/
|
||||
+ (UIColor *)jsq_messageBackgroundGrayColor;
|
||||
|
||||
|
||||
#pragma mark - Utilities
|
||||
|
||||
/**
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
{
|
||||
return [UIColor colorWithHue:130.0f / 360.0f
|
||||
saturation:0.68f
|
||||
brightness:0.84f
|
||||
brightness:0.80f
|
||||
alpha:1.0f];
|
||||
}
|
||||
|
||||
@ -38,14 +38,6 @@
|
||||
alpha:1.0f];
|
||||
}
|
||||
|
||||
+ (UIColor *)jsq_messageBubbleRedColor
|
||||
{
|
||||
return [UIColor colorWithHue:0.0f / 360.0f
|
||||
saturation:0.79f
|
||||
brightness:1.0f
|
||||
alpha:1.0f];
|
||||
}
|
||||
|
||||
+ (UIColor *)jsq_messageBubbleLightGrayColor
|
||||
{
|
||||
return [UIColor colorWithHue:240.0f / 360.0f
|
||||
@ -54,23 +46,6 @@
|
||||
alpha:1.0f];
|
||||
}
|
||||
|
||||
+ (UIColor *)jsq_messageBubbleLightBlueColor
|
||||
{
|
||||
return [UIColor colorWithRed:137/255.f green:214/255.f blue:250/255.f alpha:1];
|
||||
}
|
||||
|
||||
+ (UIColor *)jsq_messageBubbleGrayColor
|
||||
{
|
||||
return [UIColor colorWithRed:230/255.f green:230/255.f blue:230/255.f alpha:1];
|
||||
}
|
||||
|
||||
+ (UIColor *)jsq_messageBackgroundGrayColor
|
||||
{
|
||||
return [UIColor colorWithRed:242.f/255 green:242.f/255 blue:242.f/255 alpha:1];
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark - Utilities
|
||||
|
||||
- (UIColor *)jsq_colorByDarkeningColorWithValue:(CGFloat)value
|
||||
|
||||
@ -95,5 +95,4 @@
|
||||
return [UIImage jsq_bubbleImageFromBundleWithName:@"play"];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@ -59,13 +59,6 @@ FOUNDATION_EXPORT NSString * const JSQMessagesKeyboardControllerUserInfoKeyKeybo
|
||||
*/
|
||||
- (void)keyboardController:(JSQMessagesKeyboardController *)keyboardController keyboardDidChangeFrame:(CGRect)keyboardFrame;
|
||||
|
||||
/**
|
||||
* Tells the delegate that the keyboard has been hidden.
|
||||
*
|
||||
* @param keyboardController The keyboard controller that is notifying the delegate.
|
||||
*/
|
||||
- (void)keyboardControllerKeyboardDidHide:(JSQMessagesKeyboardController *)keyboardController;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@ -138,15 +138,14 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
|
||||
|
||||
- (void)beginListeningForKeyboard
|
||||
{
|
||||
if (self.textView.inputAccessoryView == nil) {
|
||||
self.textView.inputAccessoryView = [[UIView alloc] init];
|
||||
}
|
||||
|
||||
self.textView.inputAccessoryView = [[UIView alloc] init];
|
||||
[self jsq_registerForNotifications];
|
||||
}
|
||||
|
||||
- (void)endListeningForKeyboard
|
||||
{
|
||||
self.textView.inputAccessoryView = nil;
|
||||
|
||||
[self jsq_unregisterForNotifications];
|
||||
|
||||
[self jsq_setKeyboardViewHidden:NO];
|
||||
@ -213,8 +212,6 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
|
||||
|
||||
[self jsq_handleKeyboardNotification:notification completion:^(BOOL finished) {
|
||||
[self.panGestureRecognizer removeTarget:self action:NULL];
|
||||
|
||||
[self.delegate keyboardControllerKeyboardDidHide:self];
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@ -143,28 +143,6 @@
|
||||
*/
|
||||
@property (copy, nonatomic) NSString *incomingMediaCellIdentifier;
|
||||
|
||||
/*
|
||||
* The collection view cell identifier used to dequeue call collection view cell.
|
||||
*
|
||||
* @discussion This cell identifier's default value is returned by [JSQCallCollectionViewCell cellReuseIdentifier]. Value must not be nil.
|
||||
*
|
||||
* @see JSQCallCollectionViewCell
|
||||
*
|
||||
*/
|
||||
|
||||
@property (copy, nonatomic) NSString *callCellIndentifier;
|
||||
|
||||
/*
|
||||
* The collection view cell identifier used to dequeue displayed message collection view cell.
|
||||
*
|
||||
* @discussion This cell identifier's default value is returned by [JSQDisplayedMessageCollectionViewCell cellReuseIdentifier]. Value must not be nil.
|
||||
*
|
||||
* @see JSQDisplayedMessageCollectionViewCell
|
||||
*
|
||||
*/
|
||||
|
||||
@property (copy, nonatomic) NSString *displayedMessageCellIndentifier;
|
||||
|
||||
/**
|
||||
* Specifies whether or not the view controller should show the typing indicator for an incoming message.
|
||||
*
|
||||
@ -239,46 +217,32 @@
|
||||
- (void)didPressAccessoryButton:(UIButton *)sender;
|
||||
|
||||
/**
|
||||
* Animates the sending of a new message. See `finishSendingMessageAnimated:` for more details.
|
||||
* Completes the "sending" of a new message by animating and resetting the `inputToolbar`,
|
||||
* animating the addition of a new collection view cell in the collection view,
|
||||
* reloading the collection view, and scrolling to the newly sent message
|
||||
* as specified by `automaticallyScrollsToMostRecentMessage`.
|
||||
*
|
||||
* @see `finishSendingMessageAnimated:`.
|
||||
* @discussion You should call this method at the end of `didPressSendButton:withMessage:`
|
||||
* after adding the new message to your data source and performing any related tasks.
|
||||
*
|
||||
* @see `automaticallyScrollsToMostRecentMessage`.
|
||||
* @see `didPressSendButton: withMessage:`.
|
||||
*/
|
||||
- (void)finishSendingMessage;
|
||||
|
||||
/**
|
||||
* Completes the "sending" of a new message by resetting the `inputToolbar`, adding a new collection view cell in the collection view,
|
||||
* reloading the collection view, and scrolling to the newly sent message as specified by `automaticallyScrollsToMostRecentMessage`.
|
||||
* Scrolling to the new message can be animated as specified by the animated parameter.
|
||||
* Completes the "receiving" of a new message by animating the typing indicator,
|
||||
* animating the addition of a new collection view cell in the collection view,
|
||||
* reloading the collection view, and scrolling to the newly sent message
|
||||
* as specified by `automaticallyScrollsToMostRecentMessage`.
|
||||
*
|
||||
* @param animated Specifies whether the sending of a message should be animated or not. Pass `YES` to animate changes, `NO` otherwise.
|
||||
*
|
||||
* @discussion You should call this method at the end of `didPressSendButton: withMessageText: senderId: senderDisplayName: date`
|
||||
* after adding the new message to your data source and performing any related tasks.
|
||||
* @discussion You should call this method after adding a new "received" message
|
||||
* to your data source and performing any related tasks.
|
||||
*
|
||||
* @see `automaticallyScrollsToMostRecentMessage`.
|
||||
*/
|
||||
- (void)finishSendingMessageAnimated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
* Animates the receiving of a new message. See `finishReceivingMessageAnimated:` for more details.
|
||||
*
|
||||
* @see `finishReceivingMessageAnimated:`.
|
||||
*/
|
||||
- (void)finishReceivingMessage;
|
||||
|
||||
/**
|
||||
* Completes the "receiving" of a new message by showing the typing indicator, adding a new collection view cell in the collection view,
|
||||
* reloading the collection view, and scrolling to the newly sent message as specified by `automaticallyScrollsToMostRecentMessage`.
|
||||
* Scrolling to the new message can be animated as specified by the animated parameter.
|
||||
*
|
||||
* @param animated Specifies whether the receiving of a message should be animated or not. Pass `YES` to animate changes, `NO` otherwise.
|
||||
*
|
||||
* @discussion You should call this method after adding a new "received" message to your data source and performing any related tasks.
|
||||
*
|
||||
* @see `automaticallyScrollsToMostRecentMessage`.
|
||||
*/
|
||||
- (void)finishReceivingMessageAnimated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
* Scrolls the collection view such that the bottom most cell is completely visible, above the `inputToolbar`.
|
||||
*
|
||||
|
||||
@ -42,16 +42,11 @@
|
||||
#import "UIColor+JSQMessages.h"
|
||||
#import "UIDevice+JSQMessages.h"
|
||||
|
||||
#import "JSQCall.h"
|
||||
#import "JSQCallCollectionViewCell.h"
|
||||
|
||||
#import "JSQInfoMessage.h"
|
||||
#import "JSQErrorMessage.h"
|
||||
#import "JSQDisplayedMessageCollectionViewCell.h"
|
||||
|
||||
static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObservingContext;
|
||||
|
||||
|
||||
|
||||
@interface JSQMessagesViewController () <JSQMessagesInputToolbarDelegate,
|
||||
JSQMessagesKeyboardControllerDelegate>
|
||||
|
||||
@ -124,7 +119,6 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
||||
- (void)jsq_configureMessagesViewController
|
||||
{
|
||||
self.view.backgroundColor = [UIColor whiteColor];
|
||||
;
|
||||
|
||||
self.jsq_isObserving = NO;
|
||||
|
||||
@ -148,10 +142,6 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
||||
self.incomingCellIdentifier = [JSQMessagesCollectionViewCellIncoming cellReuseIdentifier];
|
||||
self.incomingMediaCellIdentifier = [JSQMessagesCollectionViewCellIncoming mediaCellReuseIdentifier];
|
||||
|
||||
self.callCellIndentifier = [JSQCallCollectionViewCell cellReuseIdentifier];
|
||||
|
||||
self.displayedMessageCellIndentifier = [JSQDisplayedMessageCollectionViewCell cellReuseIdentifier];
|
||||
|
||||
self.showTypingIndicator = NO;
|
||||
|
||||
self.showLoadEarlierMessagesHeader = NO;
|
||||
@ -213,12 +203,6 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
||||
[self.collectionView reloadData];
|
||||
}
|
||||
|
||||
- (void)setTopContentAdditionalInset:(CGFloat)topContentAdditionalInset
|
||||
{
|
||||
_topContentAdditionalInset = topContentAdditionalInset;
|
||||
[self jsq_updateCollectionViewInsets];
|
||||
}
|
||||
|
||||
#pragma mark - View lifecycle
|
||||
|
||||
- (void)viewDidLoad
|
||||
@ -300,6 +284,13 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
||||
[self.collectionView.collectionViewLayout invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
|
||||
}
|
||||
|
||||
#pragma mark - UIResponder
|
||||
|
||||
- (BOOL)canBecomeFirstResponder
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Messages view controller
|
||||
|
||||
- (void)didPressSendButton:(UIButton *)button
|
||||
@ -311,18 +302,10 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
||||
NSAssert(NO, @"Error! required method not implemented in subclass. Need to implement %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
- (void)didPressAccessoryButton:(UIButton *)sender
|
||||
{
|
||||
NSAssert(NO, @"Error! required method not implemented in subclass. Need to implement %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
- (void)didPressAccessoryButton:(UIButton *)sender { }
|
||||
|
||||
- (void)finishSendingMessage
|
||||
{
|
||||
[self finishSendingMessageAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)finishSendingMessageAnimated:(BOOL)animated {
|
||||
|
||||
UITextView *textView = self.inputToolbar.contentView.textView;
|
||||
textView.text = nil;
|
||||
[textView.undoManager removeAllActions];
|
||||
@ -335,24 +318,19 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
||||
[self.collectionView reloadData];
|
||||
|
||||
if (self.automaticallyScrollsToMostRecentMessage) {
|
||||
[self scrollToBottomAnimated:animated];
|
||||
[self scrollToBottomAnimated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)finishReceivingMessage
|
||||
{
|
||||
[self finishReceivingMessageAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)finishReceivingMessageAnimated:(BOOL)animated {
|
||||
|
||||
self.showTypingIndicator = NO;
|
||||
|
||||
[self.collectionView.collectionViewLayout invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
|
||||
[self.collectionView reloadData];
|
||||
|
||||
if (self.automaticallyScrollsToMostRecentMessage) {
|
||||
[self scrollToBottomAnimated:animated];
|
||||
|
||||
if (self.automaticallyScrollsToMostRecentMessage && ![self jsq_isMenuVisible]) {
|
||||
[self scrollToBottomAnimated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,36 +342,11 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
||||
|
||||
NSInteger items = [self.collectionView numberOfItemsInSection:0];
|
||||
|
||||
if (items == 0) {
|
||||
return;
|
||||
if (items > 0) {
|
||||
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:items - 1 inSection:0]
|
||||
atScrollPosition:UICollectionViewScrollPositionTop
|
||||
animated:animated];
|
||||
}
|
||||
|
||||
CGFloat collectionViewContentHeight = [self.collectionView.collectionViewLayout collectionViewContentSize].height;
|
||||
BOOL isContentTooSmall = (collectionViewContentHeight < self.collectionView.bounds.size.height);
|
||||
|
||||
if (isContentTooSmall) {
|
||||
// workaround for the first few messages not scrolling
|
||||
// when the collection view content size is too small, `scrollToItemAtIndexPath:` doesn't work properly
|
||||
// this seems to be a UIKit bug, see #256 on GitHub
|
||||
[self.collectionView scrollRectToVisible:CGRectMake(0.0, collectionViewContentHeight - 1.0f, 1.0f, 1.0f)
|
||||
animated:animated];
|
||||
return;
|
||||
}
|
||||
|
||||
// workaround for really long messages not scrolling
|
||||
// if last message is too long, use scroll position bottom for better appearance, else use top
|
||||
// possibly a UIKit bug, see #480 on GitHub
|
||||
NSUInteger finalRow = MAX(0, [self.collectionView numberOfItemsInSection:0] - 1);
|
||||
NSIndexPath *finalIndexPath = [NSIndexPath indexPathForItem:finalRow inSection:0];
|
||||
CGSize finalCellSize = [self.collectionView.collectionViewLayout sizeForItemAtIndexPath:finalIndexPath];
|
||||
|
||||
CGFloat maxHeightForVisibleMessage = CGRectGetHeight(self.collectionView.bounds) - self.collectionView.contentInset.top - CGRectGetHeight(self.inputToolbar.bounds);
|
||||
|
||||
UICollectionViewScrollPosition scrollPosition = (finalCellSize.height > maxHeightForVisibleMessage) ? UICollectionViewScrollPositionBottom : UICollectionViewScrollPositionTop;
|
||||
|
||||
[self.collectionView scrollToItemAtIndexPath:finalIndexPath
|
||||
atScrollPosition:scrollPosition
|
||||
animated:animated];
|
||||
}
|
||||
|
||||
#pragma mark - JSQMessages collection view data source
|
||||
@ -452,102 +405,14 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
||||
NSParameterAssert(messageSenderId != nil);
|
||||
|
||||
BOOL isOutgoingMessage = [messageSenderId isEqualToString:self.senderId];
|
||||
BOOL isCall = [messageItem messageType] == TSCallAdapter;
|
||||
BOOL isInfoMessage = [messageItem messageType] == TSInfoMessageAdapter;
|
||||
BOOL isErrorMessage = [messageItem messageType] == TSErrorMessageAdapter;
|
||||
|
||||
BOOL isMediaMessage = NO;
|
||||
|
||||
if (!isCall && !isInfoMessage && !isErrorMessage )
|
||||
{
|
||||
isMediaMessage = [messageItem isMediaMessage];
|
||||
}
|
||||
|
||||
BOOL isMediaMessage = [messageItem isMediaMessage];
|
||||
|
||||
NSString *cellIdentifier = nil;
|
||||
|
||||
if (isCall) {
|
||||
JSQCall * call = (JSQCall*)messageItem;
|
||||
cellIdentifier = self.callCellIndentifier;
|
||||
JSQCallCollectionViewCell * callCell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
|
||||
|
||||
NSString *text = call.date != nil ? [call text] : call.senderDisplayName;
|
||||
NSString *allText = call.date != nil ? [text stringByAppendingString:[call dateText]] : text;
|
||||
const CGFloat fontSize = 14;
|
||||
UIFont *boldFont = [UIFont fontWithName:@"HelveticaNeue-Medium" size:12.0f];
|
||||
UIFont *regularFont = [UIFont fontWithName:@"HelveticaNeue-Light" size:12.0f];
|
||||
UIColor *foregroundColor = [UIColor whiteColor];
|
||||
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
boldFont, NSFontAttributeName, nil];
|
||||
|
||||
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:allText
|
||||
attributes:attrs];
|
||||
if([call date]!=nil) {
|
||||
// Not a group meta message
|
||||
NSDictionary *subAttrs = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
regularFont, NSFontAttributeName, nil];
|
||||
const NSRange range = NSMakeRange([text length],[[call dateText] length]);
|
||||
|
||||
[attributedText setAttributes:subAttrs range:range];
|
||||
BOOL isOutgoing = [self.senderId isEqualToString:call.senderId];
|
||||
if (isOutgoing)
|
||||
{
|
||||
callCell.outgoingCallImageView.image = [call thumbnailImage];
|
||||
} else {
|
||||
callCell.incomingCallImageView.image = [call thumbnailImage];
|
||||
}
|
||||
}
|
||||
else {
|
||||
// A group meta message
|
||||
callCell.incomingCallImageView.image = [call thumbnailImage];
|
||||
}
|
||||
|
||||
callCell.cellLabel.attributedText = attributedText;
|
||||
callCell.cellLabel.lineBreakMode = UILineBreakModeWordWrap;
|
||||
callCell.cellLabel.numberOfLines = 0; // uses as many lines as it needs
|
||||
callCell.cellLabel.textColor = [UIColor colorWithRed:32.f/255.f green:144.f/255.f blue:234.f/255.f alpha:1.f];
|
||||
|
||||
|
||||
callCell.layer.shouldRasterize = YES;
|
||||
callCell.layer.rasterizationScale = [UIScreen mainScreen].scale;
|
||||
return callCell;
|
||||
|
||||
} else if (isInfoMessage) {
|
||||
|
||||
JSQInfoMessage * infoMessage = (JSQInfoMessage*)messageItem;
|
||||
cellIdentifier = self.displayedMessageCellIndentifier;
|
||||
JSQDisplayedMessageCollectionViewCell * infoCell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
|
||||
infoCell.delegate = collectionView;
|
||||
infoCell.cellLabel.text = [infoMessage text];
|
||||
infoCell.cellLabel.textColor = [UIColor darkGrayColor];
|
||||
infoCell.cellLabel.layer.borderColor = [[UIColor colorWithRed:239.f/255.f green:189.f/255.f blue:88.f/255.f alpha:1.0f] CGColor];
|
||||
infoCell.headerImageView.image = [UIImage imageNamed:@"warning_white"];
|
||||
infoCell.layer.shouldRasterize = YES;
|
||||
infoCell.layer.rasterizationScale = [UIScreen mainScreen].scale;
|
||||
return infoCell;
|
||||
|
||||
} else if (isErrorMessage) {
|
||||
|
||||
JSQErrorMessage * errorMessage = (JSQErrorMessage*)messageItem;
|
||||
cellIdentifier = self.displayedMessageCellIndentifier;
|
||||
JSQDisplayedMessageCollectionViewCell * errorCell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
|
||||
errorCell.delegate = collectionView;
|
||||
errorCell.cellLabel.text = [errorMessage text];
|
||||
errorCell.cellLabel.textColor = [UIColor darkGrayColor];
|
||||
errorCell.cellLabel.layer.borderColor = [[UIColor colorWithRed:195.f/255.f green:0 blue:22.f/255.f alpha:1.0f] CGColor];
|
||||
errorCell.headerImageView.image = [UIImage imageNamed:@"error_white"];
|
||||
errorCell.layer.shouldRasterize = YES;
|
||||
errorCell.layer.rasterizationScale = [UIScreen mainScreen].scale;
|
||||
return errorCell;
|
||||
|
||||
} else if (isMediaMessage) {
|
||||
|
||||
if (isMediaMessage) {
|
||||
cellIdentifier = isOutgoingMessage ? self.outgoingMediaCellIdentifier : self.incomingMediaCellIdentifier;
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
else {
|
||||
cellIdentifier = isOutgoingMessage ? self.outgoingCellIdentifier : self.incomingCellIdentifier;
|
||||
|
||||
}
|
||||
|
||||
JSQMessagesCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
|
||||
@ -581,16 +446,8 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
||||
if (needsAvatar) {
|
||||
avatarImageDataSource = [collectionView.dataSource collectionView:collectionView avatarImageDataForItemAtIndexPath:indexPath];
|
||||
if (avatarImageDataSource != nil) {
|
||||
|
||||
UIImage *avatarImage = [avatarImageDataSource avatarImage];
|
||||
if (avatarImage == nil) {
|
||||
cell.avatarImageView.image = [avatarImageDataSource avatarPlaceholderImage];
|
||||
cell.avatarImageView.highlightedImage = nil;
|
||||
}
|
||||
else {
|
||||
cell.avatarImageView.image = avatarImage;
|
||||
cell.avatarImageView.highlightedImage = [avatarImageDataSource avatarHighlightedImage];
|
||||
}
|
||||
cell.avatarImageView.image = [avatarImageDataSource avatarImage] ?: [avatarImageDataSource avatarPlaceholderImage];
|
||||
cell.avatarImageView.highlightedImage = [avatarImageDataSource avatarHighlightedImage];
|
||||
}
|
||||
}
|
||||
|
||||
@ -598,6 +455,8 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
||||
cell.messageBubbleTopLabel.attributedText = [collectionView.dataSource collectionView:collectionView attributedTextForMessageBubbleTopLabelAtIndexPath:indexPath];
|
||||
cell.cellBottomLabel.attributedText = [collectionView.dataSource collectionView:collectionView attributedTextForCellBottomLabelAtIndexPath:indexPath];
|
||||
|
||||
cell.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
CGFloat bubbleTopLabelInset = (avatarImageDataSource != nil) ? 60.0f : 15.0f;
|
||||
|
||||
if (isOutgoingMessage) {
|
||||
@ -609,8 +468,8 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
||||
|
||||
cell.textView.dataDetectorTypes = UIDataDetectorTypeAll;
|
||||
|
||||
cell.layer.shouldRasterize = YES;
|
||||
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
|
||||
cell.layer.shouldRasterize = YES;
|
||||
|
||||
return cell;
|
||||
}
|
||||
@ -653,16 +512,8 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
||||
|
||||
- (BOOL)collectionView:(JSQMessagesCollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
// disable menu for media messages, calls, info and error messages
|
||||
// disable menu for media messages
|
||||
id<JSQMessageData> messageItem = [collectionView.dataSource collectionView:collectionView messageDataForItemAtIndexPath:indexPath];
|
||||
|
||||
BOOL isErrorOrInfoMessage = messageItem.messageType == TSInfoMessageAdapter || messageItem.messageType == TSErrorMessageAdapter;
|
||||
BOOL isCall = messageItem.messageType == TSCallAdapter;
|
||||
|
||||
if (isErrorOrInfoMessage || isCall) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if ([messageItem isMediaMessage]) {
|
||||
return NO;
|
||||
}
|
||||
@ -732,8 +583,6 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
||||
didTapCellAtIndexPath:(NSIndexPath *)indexPath
|
||||
touchLocation:(CGPoint)touchLocation { }
|
||||
|
||||
|
||||
|
||||
#pragma mark - Input toolbar delegate
|
||||
|
||||
- (void)messagesInputToolbar:(JSQMessagesInputToolbar *)toolbar didPressLeftBarButton:(UIButton *)sender
|
||||
@ -879,10 +728,6 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
||||
|
||||
- (void)keyboardController:(JSQMessagesKeyboardController *)keyboardController keyboardDidChangeFrame:(CGRect)keyboardFrame
|
||||
{
|
||||
if (![self.inputToolbar.contentView.textView isFirstResponder] && self.toolbarBottomLayoutGuide.constant == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
CGFloat heightFromBottom = CGRectGetMaxY(self.collectionView.frame) - CGRectGetMinY(keyboardFrame);
|
||||
|
||||
heightFromBottom = MAX(0.0f, heightFromBottom);
|
||||
@ -890,16 +735,6 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
||||
[self jsq_setToolbarBottomLayoutGuideConstant:heightFromBottom];
|
||||
}
|
||||
|
||||
- (void)keyboardControllerKeyboardDidHide:(JSQMessagesKeyboardController *)keyboardController
|
||||
{
|
||||
if (![self.inputToolbar.contentView.textView isFirstResponder]) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self jsq_setToolbarBottomLayoutGuideConstant:0.0f];
|
||||
[self.inputToolbar.contentView.textView resignFirstResponder];
|
||||
}
|
||||
|
||||
- (void)jsq_setToolbarBottomLayoutGuideConstant:(CGFloat)constant
|
||||
{
|
||||
self.toolbarBottomLayoutGuide.constant = constant;
|
||||
|
||||
@ -73,7 +73,4 @@
|
||||
*/
|
||||
- (JSQMessagesBubbleImage *)incomingMessagesBubbleImageWithColor:(UIColor *)color;
|
||||
|
||||
|
||||
- (JSQMessagesBubbleImage *)outgoingMessageFailedBubbleImageWithColor:(UIColor *)color;
|
||||
|
||||
@end
|
||||
|
||||
@ -83,11 +83,6 @@
|
||||
return [self jsq_messagesBubbleImageWithColor:color flippedForIncoming:YES];
|
||||
}
|
||||
|
||||
- (JSQMessagesBubbleImage *)outgoingMessageFailedBubbleImageWithColor:(UIColor *)color
|
||||
{
|
||||
return [self jsq_messagesBubbleImageWithColor:color flippedForIncoming:NO];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (UIEdgeInsets)jsq_centerPointEdgeInsetsForImageSize:(CGSize)bubbleImageSize
|
||||
|
||||
@ -27,16 +27,16 @@
|
||||
+ (UIButton *)defaultAccessoryButtonItem
|
||||
{
|
||||
UIImage *accessoryImage = [UIImage jsq_defaultAccessoryImage];
|
||||
UIImage *normalImage = [accessoryImage jsq_imageMaskedWithColor:[UIColor colorWithRed:0 green:71/255.f blue:1.0f alpha:1.0f]];
|
||||
UIImage *normalImage = [accessoryImage jsq_imageMaskedWithColor:[UIColor lightGrayColor]];
|
||||
UIImage *highlightedImage = [accessoryImage jsq_imageMaskedWithColor:[UIColor darkGrayColor]];
|
||||
|
||||
UIButton *accessoryButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, accessoryImage.size.width, 32.0f)];
|
||||
UIButton *accessoryButton = [[UIButton alloc] initWithFrame:CGRectZero];
|
||||
[accessoryButton setImage:normalImage forState:UIControlStateNormal];
|
||||
[accessoryButton setImage:highlightedImage forState:UIControlStateHighlighted];
|
||||
|
||||
accessoryButton.contentMode = UIViewContentModeScaleAspectFit;
|
||||
accessoryButton.backgroundColor = [UIColor clearColor];
|
||||
//accessoryButton.tintColor = [UIColor lightGrayColor];
|
||||
accessoryButton.tintColor = [UIColor lightGrayColor];
|
||||
|
||||
return accessoryButton;
|
||||
}
|
||||
@ -51,25 +51,13 @@
|
||||
[sendButton setTitleColor:[[UIColor jsq_messageBubbleBlueColor] jsq_colorByDarkeningColorWithValue:0.1f] forState:UIControlStateHighlighted];
|
||||
[sendButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled];
|
||||
|
||||
sendButton.titleLabel.font = [UIFont fontWithName:@"HelveticaNeue-Thin" size:17.0f];
|
||||
sendButton.titleLabel.font = [UIFont boldSystemFontOfSize:17.0f];
|
||||
sendButton.titleLabel.adjustsFontSizeToFitWidth = YES;
|
||||
sendButton.titleLabel.minimumScaleFactor = 0.85f;
|
||||
sendButton.contentMode = UIViewContentModeCenter;
|
||||
sendButton.backgroundColor = [UIColor clearColor];
|
||||
sendButton.tintColor = [UIColor jsq_messageBubbleBlueColor];
|
||||
|
||||
CGFloat maxHeight = 32.0f;
|
||||
|
||||
CGRect sendTitleRect = [sendTitle boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, maxHeight)
|
||||
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
|
||||
attributes:@{ NSFontAttributeName : sendButton.titleLabel.font }
|
||||
context:nil];
|
||||
|
||||
sendButton.frame = CGRectMake(0.0f,
|
||||
0.0f,
|
||||
CGRectGetWidth(CGRectIntegral(sendTitleRect)),
|
||||
maxHeight);
|
||||
|
||||
return sendButton;
|
||||
}
|
||||
|
||||
|
||||
@ -40,6 +40,8 @@
|
||||
|
||||
// Model
|
||||
#import "JSQMessage.h"
|
||||
#import "JSQTextMessage.h"
|
||||
#import "JSQMediaMessage.h"
|
||||
|
||||
#import "JSQMediaItem.h"
|
||||
#import "JSQPhotoMediaItem.h"
|
||||
|
||||
@ -167,13 +167,6 @@ FOUNDATION_EXPORT const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault;
|
||||
*/
|
||||
@property (assign, nonatomic) CGSize outgoingAvatarViewSize;
|
||||
|
||||
/**
|
||||
* The maximum number of items that the layout should keep in its cache of layout information.
|
||||
*
|
||||
* @discussion The default value is `200`. A limit of `0` means no limit. This is not a strict limit.
|
||||
*/
|
||||
@property (assign, nonatomic) NSUInteger cacheLimit;
|
||||
|
||||
/**
|
||||
* Computes and returns the size of the `messageBubbleImageView` property of a `JSQMessagesCollectionViewCell`
|
||||
* at the specified indexPath. The returned size contains the required dimensions to display the entire message contents.
|
||||
|
||||
@ -33,15 +33,6 @@
|
||||
|
||||
#import "UIImage+JSQMessages.h"
|
||||
|
||||
#import "JSQCall.h"
|
||||
#import "JSQCallCollectionViewCell.h"
|
||||
|
||||
#import "JSQDisplayedMessage.h"
|
||||
#import "JSQDisplayedMessageCollectionViewCell.h"
|
||||
|
||||
#import "JSQErrorMessage.h"
|
||||
#import "JSQInfoMessage.h"
|
||||
|
||||
|
||||
const CGFloat kJSQMessagesCollectionViewCellLabelHeightDefault = 20.0f;
|
||||
const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
||||
@ -49,7 +40,7 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
||||
|
||||
@interface JSQMessagesCollectionViewFlowLayout ()
|
||||
|
||||
@property (strong, nonatomic) NSCache *messageBubbleCache;
|
||||
@property (strong, nonatomic) NSMutableDictionary *messageBubbleSizes;
|
||||
|
||||
@property (strong, nonatomic) UIDynamicAnimator *dynamicAnimator;
|
||||
@property (strong, nonatomic) NSMutableSet *visibleIndexPaths;
|
||||
@ -90,9 +81,7 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
||||
|
||||
_bubbleImageAssetWidth = [UIImage jsq_bubbleCompactImage].size.width;
|
||||
|
||||
_messageBubbleCache = [NSCache new];
|
||||
_messageBubbleCache.name = @"JSQMessagesCollectionViewFlowLayout.messageBubbleCache";
|
||||
_messageBubbleCache.countLimit = 200;
|
||||
_messageBubbleSizes = [NSMutableDictionary new];
|
||||
|
||||
_messageBubbleFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
|
||||
|
||||
@ -100,7 +89,7 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
||||
_messageBubbleLeftRightMargin = 240.0f;
|
||||
}
|
||||
else {
|
||||
_messageBubbleLeftRightMargin = 50.0f;
|
||||
_messageBubbleLeftRightMargin = 40.0f;
|
||||
}
|
||||
|
||||
_messageBubbleTextViewFrameInsets = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 6.0f);
|
||||
@ -155,8 +144,8 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
||||
|
||||
_messageBubbleFont = nil;
|
||||
|
||||
[_messageBubbleCache removeAllObjects];
|
||||
_messageBubbleCache = nil;
|
||||
[_messageBubbleSizes removeAllObjects];
|
||||
_messageBubbleSizes = nil;
|
||||
|
||||
[_dynamicAnimator removeAllBehaviors];
|
||||
_dynamicAnimator = nil;
|
||||
@ -230,11 +219,6 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
||||
[self invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
|
||||
}
|
||||
|
||||
- (void)setCacheLimit:(NSUInteger)cacheLimit
|
||||
{
|
||||
self.messageBubbleCache.countLimit = cacheLimit;
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (CGFloat)itemWidth
|
||||
@ -258,11 +242,6 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
||||
return _visibleIndexPaths;
|
||||
}
|
||||
|
||||
- (NSUInteger)cacheLimit
|
||||
{
|
||||
return self.messageBubbleCache.countLimit;
|
||||
}
|
||||
|
||||
#pragma mark - Notifications
|
||||
|
||||
- (void)jsq_didReceiveApplicationMemoryWarningNotification:(NSNotification *)notification
|
||||
@ -287,10 +266,6 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
||||
|
||||
if (context.invalidateFlowLayoutAttributes
|
||||
|| context.invalidateFlowLayoutDelegateMetrics) {
|
||||
[self jsq_resetDynamicAnimator];
|
||||
}
|
||||
|
||||
if (context.emptyCache) {
|
||||
[self jsq_resetLayout];
|
||||
}
|
||||
|
||||
@ -323,8 +298,8 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
||||
NSMutableArray *attributesInRectCopy = [attributesInRect mutableCopy];
|
||||
NSArray *dynamicAttributes = [self.dynamicAnimator itemsInRect:rect];
|
||||
|
||||
// avoid duplicate attributes
|
||||
// use dynamic animator attribute item instead of regular item, if it exists
|
||||
// avoid duplicate attributes
|
||||
// use dynamic animator attribute item instead of regular item, if it exists
|
||||
for (UICollectionViewLayoutAttributes *eachItem in attributesInRect) {
|
||||
|
||||
for (UICollectionViewLayoutAttributes *eachDynamicItem in dynamicAttributes) {
|
||||
@ -424,7 +399,7 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
||||
|
||||
- (void)jsq_resetLayout
|
||||
{
|
||||
[self.messageBubbleCache removeAllObjects];
|
||||
[self.messageBubbleSizes removeAllObjects];
|
||||
[self jsq_resetDynamicAnimator];
|
||||
}
|
||||
|
||||
@ -440,58 +415,49 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
||||
|
||||
- (CGSize)messageBubbleSizeForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
id<JSQMessageData> messageItem = [self.collectionView.dataSource collectionView:self.collectionView messageDataForItemAtIndexPath:indexPath];
|
||||
|
||||
NSValue *cachedSize = [self.messageBubbleCache objectForKey:@(messageItem.hash)];
|
||||
if (cachedSize != nil) {
|
||||
NSValue *cachedSize = [self.messageBubbleSizes objectForKey:indexPath];
|
||||
if (cachedSize) {
|
||||
return [cachedSize CGSizeValue];
|
||||
}
|
||||
|
||||
id<JSQMessageData> messageItem = [self.collectionView.dataSource collectionView:self.collectionView messageDataForItemAtIndexPath:indexPath];
|
||||
CGSize finalSize = CGSizeZero;
|
||||
|
||||
if (messageItem.messageType != TSCallAdapter && messageItem.messageType != TSErrorMessageAdapter && messageItem.messageType != TSInfoMessageAdapter) {
|
||||
if ([messageItem isMediaMessage]) {
|
||||
finalSize = [[messageItem media] mediaViewDisplaySize];
|
||||
}
|
||||
else {
|
||||
CGSize avatarSize = [self jsq_avatarSizeForIndexPath:indexPath];
|
||||
if ([messageItem isMediaMessage]) {
|
||||
finalSize = [[messageItem media] mediaViewDisplaySize];
|
||||
}
|
||||
else {
|
||||
CGSize avatarSize = [self jsq_avatarSizeForIndexPath:indexPath];
|
||||
|
||||
// from the cell xibs, there is a 2 point space between avatar and bubble
|
||||
CGFloat spacingBetweenAvatarAndBubble = 2.0f;
|
||||
CGFloat horizontalContainerInsets = self.messageBubbleTextViewTextContainerInsets.left + self.messageBubbleTextViewTextContainerInsets.right;
|
||||
CGFloat horizontalFrameInsets = self.messageBubbleTextViewFrameInsets.left + self.messageBubbleTextViewFrameInsets.right;
|
||||
// from the cell xibs, there is a 2 point space between avatar and bubble
|
||||
CGFloat spacingBetweenAvatarAndBubble = 2.0f;
|
||||
CGFloat horizontalContainerInsets = self.messageBubbleTextViewTextContainerInsets.left + self.messageBubbleTextViewTextContainerInsets.right;
|
||||
CGFloat horizontalFrameInsets = self.messageBubbleTextViewFrameInsets.left + self.messageBubbleTextViewFrameInsets.right;
|
||||
|
||||
CGFloat horizontalInsetsTotal = horizontalContainerInsets + horizontalFrameInsets + spacingBetweenAvatarAndBubble;
|
||||
CGFloat maximumTextWidth = self.itemWidth - avatarSize.width - self.messageBubbleLeftRightMargin - horizontalInsetsTotal;
|
||||
CGFloat horizontalInsetsTotal = horizontalContainerInsets + horizontalFrameInsets + spacingBetweenAvatarAndBubble;
|
||||
CGFloat maximumTextWidth = self.itemWidth - avatarSize.width - self.messageBubbleLeftRightMargin - horizontalInsetsTotal;
|
||||
|
||||
CGRect stringRect = [[messageItem text] boundingRectWithSize:CGSizeMake(maximumTextWidth, CGFLOAT_MAX)
|
||||
CGRect stringRect = [[messageItem text] boundingRectWithSize:CGSizeMake(maximumTextWidth, CGFLOAT_MAX)
|
||||
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
|
||||
attributes:@{ NSFontAttributeName : self.messageBubbleFont }
|
||||
context:nil];
|
||||
|
||||
CGSize stringSize = CGRectIntegral(stringRect).size;
|
||||
CGSize stringSize = CGRectIntegral(stringRect).size;
|
||||
|
||||
CGFloat verticalContainerInsets = self.messageBubbleTextViewTextContainerInsets.top + self.messageBubbleTextViewTextContainerInsets.bottom;
|
||||
CGFloat verticalFrameInsets = self.messageBubbleTextViewFrameInsets.top + self.messageBubbleTextViewFrameInsets.bottom;
|
||||
CGFloat verticalContainerInsets = self.messageBubbleTextViewTextContainerInsets.top + self.messageBubbleTextViewTextContainerInsets.bottom;
|
||||
CGFloat verticalFrameInsets = self.messageBubbleTextViewFrameInsets.top + self.messageBubbleTextViewFrameInsets.bottom;
|
||||
|
||||
// add extra 2 points of space, because `boundingRectWithSize:` is slightly off
|
||||
// not sure why. magix. (shrug) if you know, submit a PR
|
||||
CGFloat verticalInsets = verticalContainerInsets + verticalFrameInsets + 2.0f;
|
||||
CGFloat verticalInsets = verticalContainerInsets + verticalFrameInsets + 2.0f;
|
||||
|
||||
// same as above, an extra 2 points of magix
|
||||
CGFloat finalWidth = MAX(stringSize.width + horizontalInsetsTotal, self.bubbleImageAssetWidth) + 2.0f;
|
||||
CGFloat finalWidth = MAX(stringSize.width + horizontalInsetsTotal, self.bubbleImageAssetWidth) + 2.0f;
|
||||
|
||||
finalSize = CGSizeMake(finalWidth, stringSize.height + verticalInsets);
|
||||
}
|
||||
}
|
||||
else if (messageItem.messageType == TSCallAdapter)
|
||||
{
|
||||
finalSize = CGSizeMake(kCallCellWidth, kCallCellHeight);
|
||||
} else {
|
||||
finalSize = CGSizeMake(kDisplayedMessageCellWidth, kDisplayedMessageCellHeight);
|
||||
finalSize = CGSizeMake(finalWidth, stringSize.height + verticalInsets);
|
||||
}
|
||||
|
||||
[self.messageBubbleCache setObject:[NSValue valueWithCGSize:finalSize] forKey:@(messageItem.hash)];
|
||||
[self.messageBubbleSizes setObject:[NSValue valueWithCGSize:finalSize] forKey:indexPath];
|
||||
|
||||
return finalSize;
|
||||
}
|
||||
@ -514,8 +480,11 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
||||
NSIndexPath *indexPath = layoutAttributes.indexPath;
|
||||
|
||||
CGSize messageBubbleSize = [self messageBubbleSizeForItemAtIndexPath:indexPath];
|
||||
CGFloat remainingItemWidthForBubble = self.itemWidth - [self jsq_avatarSizeForIndexPath:indexPath].width;
|
||||
|
||||
layoutAttributes.messageBubbleContainerViewWidth = messageBubbleSize.width;
|
||||
CGFloat messageBubblePadding = remainingItemWidthForBubble - messageBubbleSize.width;
|
||||
|
||||
layoutAttributes.messageBubbleLeftRightMargin = MAX(messageBubblePadding, 0.0f);
|
||||
|
||||
layoutAttributes.textViewFrameInsets = self.messageBubbleTextViewFrameInsets;
|
||||
|
||||
|
||||
@ -27,12 +27,6 @@
|
||||
*/
|
||||
@interface JSQMessagesCollectionViewFlowLayoutInvalidationContext : UICollectionViewFlowLayoutInvalidationContext
|
||||
|
||||
/**
|
||||
* A boolean indicating whether to empty the layout information cache for items and views in the layout.
|
||||
* The default value is `NO`.
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL emptyCache;
|
||||
|
||||
/**
|
||||
* Creates and returns a new `JSQMessagesCollectionViewFlowLayoutInvalidationContext` object.
|
||||
*
|
||||
|
||||
@ -28,7 +28,6 @@
|
||||
if (self) {
|
||||
self.invalidateFlowLayoutDelegateMetrics = NO;
|
||||
self.invalidateFlowLayoutAttributes = NO;
|
||||
_emptyCache = NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -45,8 +44,11 @@
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"<%@: invalidateFlowLayoutDelegateMetrics=%@, invalidateFlowLayoutAttributes=%@, invalidateDataSourceCounts=%@, emptyCache=%@>",
|
||||
[self class], @(self.invalidateFlowLayoutDelegateMetrics), @(self.invalidateFlowLayoutAttributes), @(self.invalidateDataSourceCounts), @(self.emptyCache)];
|
||||
return [NSString stringWithFormat:@"<%@: invalidateFlowLayoutDelegateMetrics=%d, invalidateFlowLayoutAttributes=%d, invalidateDataSourceCounts=%d>",
|
||||
[self class],
|
||||
self.invalidateFlowLayoutDelegateMetrics,
|
||||
self.invalidateFlowLayoutAttributes,
|
||||
self.invalidateDataSourceCounts];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -31,12 +31,16 @@
|
||||
@property (strong, nonatomic) UIFont *messageBubbleFont;
|
||||
|
||||
/**
|
||||
* The width of the `messageBubbleContainerView` of a `JSQMessagesCollectionViewCell`.
|
||||
* This value should be greater than `0.0`.
|
||||
* The horizontal spacing between the message bubble and the edge of the collection
|
||||
* view cell in which it is displayed. This value should be greater than or equal to `0.0`.
|
||||
*
|
||||
* @see JSQMessagesCollectionViewCell.
|
||||
* @discussion For *outgoing* messages, this value specifies the amount of spacing from the left most edge
|
||||
* of the collection view cell to the left most edge of a message bubble with in the cell.
|
||||
*
|
||||
* For *incoming* messages, this value specifies the amount of spacing from the right most edge
|
||||
* of the collection view cell to the right most edge of a message bubble with in the cell.
|
||||
*/
|
||||
@property (assign, nonatomic) CGFloat messageBubbleContainerViewWidth;
|
||||
@property (assign, nonatomic) CGFloat messageBubbleLeftRightMargin;
|
||||
|
||||
/**
|
||||
* The inset of the text container's layout area within the text view's content area in a `JSQMessagesCollectionViewCell`.
|
||||
|
||||
@ -45,10 +45,10 @@
|
||||
_messageBubbleFont = messageBubbleFont;
|
||||
}
|
||||
|
||||
- (void)setMessageBubbleContainerViewWidth:(CGFloat)messageBubbleContainerViewWidth
|
||||
- (void)setMessageBubbleLeftRightMargin:(CGFloat)messageBubbleLeftRightMargin
|
||||
{
|
||||
NSParameterAssert(messageBubbleContainerViewWidth > 0.0f);
|
||||
_messageBubbleContainerViewWidth = ceilf(messageBubbleContainerViewWidth);
|
||||
NSParameterAssert(messageBubbleLeftRightMargin >= 0.0f);
|
||||
_messageBubbleLeftRightMargin = ceilf(messageBubbleLeftRightMargin);
|
||||
}
|
||||
|
||||
- (void)setIncomingAvatarViewSize:(CGSize)incomingAvatarViewSize
|
||||
@ -121,7 +121,7 @@
|
||||
|| !UIEdgeInsetsEqualToEdgeInsets(layoutAttributes.textViewTextContainerInsets, self.textViewTextContainerInsets)
|
||||
|| !CGSizeEqualToSize(layoutAttributes.incomingAvatarViewSize, self.incomingAvatarViewSize)
|
||||
|| !CGSizeEqualToSize(layoutAttributes.outgoingAvatarViewSize, self.outgoingAvatarViewSize)
|
||||
|| (int)layoutAttributes.messageBubbleContainerViewWidth != (int)self.messageBubbleContainerViewWidth
|
||||
|| (int)layoutAttributes.messageBubbleLeftRightMargin != (int)self.messageBubbleLeftRightMargin
|
||||
|| (int)layoutAttributes.cellTopLabelHeight != (int)self.cellTopLabelHeight
|
||||
|| (int)layoutAttributes.messageBubbleTopLabelHeight != (int)self.messageBubbleTopLabelHeight
|
||||
|| (int)layoutAttributes.cellBottomLabelHeight != (int)self.cellBottomLabelHeight) {
|
||||
@ -148,7 +148,7 @@
|
||||
}
|
||||
|
||||
copy.messageBubbleFont = self.messageBubbleFont;
|
||||
copy.messageBubbleContainerViewWidth = self.messageBubbleContainerViewWidth;
|
||||
copy.messageBubbleLeftRightMargin = self.messageBubbleLeftRightMargin;
|
||||
copy.textViewFrameInsets = self.textViewFrameInsets;
|
||||
copy.textViewTextContainerInsets = self.textViewTextContainerInsets;
|
||||
copy.incomingAvatarViewSize = self.incomingAvatarViewSize;
|
||||
@ -156,7 +156,6 @@
|
||||
copy.cellTopLabelHeight = self.cellTopLabelHeight;
|
||||
copy.messageBubbleTopLabelHeight = self.messageBubbleTopLabelHeight;
|
||||
copy.cellBottomLabelHeight = self.cellBottomLabelHeight;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
@ -1,70 +0,0 @@
|
||||
//
|
||||
// JSQCall.h
|
||||
// JSQMessages
|
||||
//
|
||||
// Created by Dylan Bourgeois on 20/11/14.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "JSQMessageData.h"
|
||||
|
||||
typedef enum : NSUInteger {
|
||||
kCallOutgoing = 1,
|
||||
kCallIncoming = 2,
|
||||
kCallMissed = 3,
|
||||
kGroupUpdateJoin = 4,
|
||||
kGroupUpdateLeft = 5,
|
||||
kGroupUpdate = 6
|
||||
} CallStatus;
|
||||
|
||||
|
||||
|
||||
@interface JSQCall : NSObject <JSQMessageData, NSCoding, NSCopying>
|
||||
|
||||
/*
|
||||
* Returns the string Id of the user who initiated the call
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) NSString *senderId;
|
||||
|
||||
|
||||
/*
|
||||
* Returns the display name for user who initiated the call
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) NSString *senderDisplayName;
|
||||
|
||||
/*
|
||||
* Returns date of the call
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) NSDate *date;
|
||||
|
||||
/*
|
||||
* Returns the call status
|
||||
* @see CallStatus
|
||||
*/
|
||||
@property (nonatomic) CallStatus status;
|
||||
|
||||
/*
|
||||
* Returns message type for adapter
|
||||
*/
|
||||
@property (nonatomic) TSMessageAdapterType messageType;
|
||||
|
||||
/*
|
||||
* User can configure whether a thumbnail is used in the display of this cell or not
|
||||
*/
|
||||
@property (nonatomic) BOOL useThumbnail;
|
||||
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
- (instancetype)initWithCallerId:(NSString *)callerId
|
||||
callerDisplayName:(NSString *)callerDisplayName
|
||||
date:(NSDate *)date
|
||||
status:(CallStatus)status;
|
||||
|
||||
-(NSString*)text;
|
||||
-(NSString*)dateText;
|
||||
|
||||
-(UIImage*)thumbnailImage;
|
||||
|
||||
@end
|
||||
@ -1,171 +0,0 @@
|
||||
//
|
||||
// JSQCall.m
|
||||
// JSQMessages
|
||||
//
|
||||
// Created by Dylan Bourgeois on 20/11/14.
|
||||
//
|
||||
|
||||
#import "JSQCall.h"
|
||||
|
||||
#import "JSQMessagesTimestampFormatter.h"
|
||||
#import "UIImage+JSQMessages.h"
|
||||
|
||||
@implementation JSQCall
|
||||
|
||||
#pragma mark - Initialzation
|
||||
|
||||
-(instancetype)initWithCallerId:(NSString *)senderId
|
||||
callerDisplayName:(NSString *)senderDisplayName
|
||||
date:(NSDate *)date
|
||||
status:(CallStatus)status
|
||||
{
|
||||
NSParameterAssert(senderId != nil);
|
||||
NSParameterAssert(senderDisplayName != nil);
|
||||
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_senderId = [senderId copy];
|
||||
_senderDisplayName = [senderDisplayName copy];
|
||||
_date = [date copy];
|
||||
_status = status;
|
||||
_messageType = TSCallAdapter;
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(id)init
|
||||
{
|
||||
NSAssert(NO,@"%s is not a valid initializer for %@. Use %@ instead", __PRETTY_FUNCTION__, [self class], NSStringFromSelector(@selector(initWithCallerId:callerDisplayName:date:status:)));
|
||||
return nil;
|
||||
}
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
_senderId = nil;
|
||||
_senderDisplayName = nil;
|
||||
_date = nil;
|
||||
}
|
||||
|
||||
-(NSString*)text
|
||||
{
|
||||
NSString *name = _senderDisplayName;
|
||||
|
||||
switch (self.status) {
|
||||
case kCallMissed:
|
||||
return [NSString stringWithFormat:@"Missed call from %@. ", name];
|
||||
case kCallIncoming:
|
||||
return [NSString stringWithFormat:@"You received a call from %@. ", name];
|
||||
case kCallOutgoing:
|
||||
return [NSString stringWithFormat:@"You called %@. ", name];
|
||||
default:
|
||||
return nil;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
-(NSString*)dateText
|
||||
{
|
||||
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
||||
dateFormatter.timeStyle = NSDateFormatterShortStyle;
|
||||
dateFormatter.dateStyle = NSDateFormatterMediumStyle;
|
||||
dateFormatter.doesRelativeDateFormatting = YES;
|
||||
return [dateFormatter stringFromDate:_date];
|
||||
}
|
||||
|
||||
-(UIImage*)thumbnailImage {
|
||||
// This relies on those assets being in the project
|
||||
if(!_useThumbnail) {
|
||||
return nil;
|
||||
}
|
||||
switch (_status) {
|
||||
case kCallOutgoing:
|
||||
return [UIImage imageNamed:@"statCallOutgoing--blue"];
|
||||
break;
|
||||
case kCallIncoming:
|
||||
case kCallMissed:
|
||||
return [UIImage imageNamed:@"statCallIncoming--blue"];
|
||||
break;
|
||||
case kGroupUpdate:
|
||||
return [UIImage imageNamed:@"statRefreshedGroup--blue"];
|
||||
break;
|
||||
case kGroupUpdateLeft:
|
||||
return [UIImage imageNamed:@"statLeftGroup--blue"];
|
||||
break;
|
||||
case kGroupUpdateJoin:
|
||||
return [UIImage imageNamed:@"statJoinedGroup--blue"];
|
||||
break;
|
||||
default:
|
||||
return nil;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - NSObject
|
||||
|
||||
-(BOOL)isEqual:(id)object
|
||||
{
|
||||
if (self==object) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (![object isKindOfClass:[self class]])
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
JSQCall * aCall = (JSQCall*)object;
|
||||
|
||||
return [self.senderId isEqualToString:aCall.senderId]
|
||||
&& [self.senderDisplayName isEqualToString:aCall.senderDisplayName]
|
||||
&& ([self.date compare:aCall.date] == NSOrderedSame)
|
||||
&& self.status == aCall.status;
|
||||
}
|
||||
|
||||
-(NSUInteger)hash
|
||||
{
|
||||
return self.senderId.hash ^ self.date.hash;
|
||||
}
|
||||
|
||||
-(NSString*)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"<%@: senderId=%@, senderDisplayName=%@, date=%@>",
|
||||
[self class], self.senderId, self.senderDisplayName, self.date];
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding
|
||||
|
||||
-(instancetype)initWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_senderId = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(senderId))];
|
||||
_senderDisplayName = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(senderDisplayName))];
|
||||
_date = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(date))];
|
||||
_status = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(status))];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
||||
{
|
||||
[aCoder encodeObject:self.senderId forKey:NSStringFromSelector(@selector(senderId))];
|
||||
[aCoder encodeObject:self.senderDisplayName forKey:NSStringFromSelector(@selector(senderDisplayName))];
|
||||
[aCoder encodeObject:self.date forKey:NSStringFromSelector(@selector(date))];
|
||||
[aCoder encodeDouble:self.status forKey:NSStringFromSelector(@selector(status))];
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
-(instancetype)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
return [[[self class] allocWithZone:zone]initWithCallerId:self.senderId
|
||||
callerDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
status:self.status];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
@ -1,44 +0,0 @@
|
||||
//
|
||||
// JSQDisplayedMessage.h
|
||||
// JSQMessages
|
||||
//
|
||||
// Created by Dylan Bourgeois on 29/11/14.
|
||||
// Copyright (c) 2014 Hexed Bits. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "JSQMessageData.h"
|
||||
|
||||
/* JSQDisplayed message is the parent class for displaying information to the user
|
||||
* from within the conversation view. Do not use directly :
|
||||
*
|
||||
* @see JSQInfoMessage
|
||||
* @see JSQErrorMessage
|
||||
*
|
||||
*/
|
||||
|
||||
@interface JSQDisplayedMessage : NSObject <JSQMessageData>
|
||||
|
||||
/*
|
||||
* Returns the unique identifier of the person affected by the displayed message
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) NSString *senderId;
|
||||
|
||||
|
||||
/*
|
||||
* Returns the name of the person affected by the displayed message
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) NSString *senderDisplayName;
|
||||
|
||||
/*
|
||||
* Returns date of the displayed message
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) NSDate *date;
|
||||
|
||||
#pragma mark - Initializer
|
||||
|
||||
-(instancetype)initWithSenderId:(NSString*)senderId
|
||||
senderDisplayName:(NSString*)senderDisplayName
|
||||
date:(NSDate*)date;
|
||||
|
||||
@end
|
||||
@ -1,35 +0,0 @@
|
||||
//
|
||||
// JSQDisplayedMessage.m
|
||||
// JSQMessages
|
||||
//
|
||||
// Created by Dylan Bourgeois on 29/11/14.
|
||||
// Copyright (c) 2014 Hexed Bits. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JSQDisplayedMessage.h"
|
||||
|
||||
@implementation JSQDisplayedMessage
|
||||
|
||||
-(id)init
|
||||
{
|
||||
NSAssert(NO,@"%s is not a valid initializer for %@. Use %@ instead", __PRETTY_FUNCTION__, [self class], NSStringFromSelector(@selector(initWithSenderId:senderDisplayName:date:)));
|
||||
return nil;
|
||||
}
|
||||
|
||||
-(instancetype)initWithSenderId:(NSString*)senderId
|
||||
senderDisplayName:(NSString*)senderDisplayName
|
||||
date:(NSDate*)date
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
_senderId = [senderId copy];
|
||||
_senderDisplayName = [senderDisplayName copy];
|
||||
_date = [date copy];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@ -1,36 +0,0 @@
|
||||
//
|
||||
// JSQErrorMessage.h
|
||||
// JSQMessages
|
||||
//
|
||||
// Created by Dylan Bourgeois on 29/11/14.
|
||||
// Copyright (c) 2014 Hexed Bits. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JSQDisplayedMessage.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, JSQErrorMessageType){
|
||||
JSQErrorMessageNoSession,
|
||||
JSQErrorMessageWrongTrustedIdentityKey,
|
||||
JSQErrorMessageInvalidKeyException,
|
||||
JSQErrorMessageMissingKeyId,
|
||||
JSQErrorMessageInvalidMessage,
|
||||
JSQErrorMessageDuplicateMessage,
|
||||
JSQErrorMessageInvalidVersion
|
||||
};
|
||||
|
||||
@interface JSQErrorMessage : JSQDisplayedMessage
|
||||
|
||||
@property (nonatomic) JSQErrorMessageType errorMessageType;
|
||||
|
||||
@property (nonatomic) TSMessageAdapterType messageType;
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
- (instancetype)initWithErrorType:(JSQErrorMessageType)messageType
|
||||
senderId:(NSString*)senderId
|
||||
senderDisplayName:(NSString*)senderDisplayName
|
||||
date:(NSDate*)date;
|
||||
|
||||
- (NSString*)text;
|
||||
|
||||
@end
|
||||
@ -1,75 +0,0 @@
|
||||
//
|
||||
// JSQErrorMessage.m
|
||||
// JSQMessages
|
||||
//
|
||||
// Created by Dylan Bourgeois on 29/11/14.
|
||||
// Copyright (c) 2014 Hexed Bits. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JSQErrorMessage.h"
|
||||
|
||||
@implementation JSQErrorMessage
|
||||
|
||||
- (instancetype)initWithErrorType:(JSQErrorMessageType)messageType
|
||||
senderId:(NSString *)senderId
|
||||
senderDisplayName:(NSString *)senderDisplayName
|
||||
date:(NSDate *)date
|
||||
{
|
||||
self = [super initWithSenderId:senderId senderDisplayName:senderDisplayName date:date];
|
||||
|
||||
if (self) {
|
||||
_errorMessageType = messageType;
|
||||
_messageType = TSErrorMessageAdapter;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString*)text
|
||||
{
|
||||
switch (self.errorMessageType) {
|
||||
case JSQErrorMessageNoSession:
|
||||
return [NSString stringWithFormat:@"No session error"];
|
||||
break;
|
||||
case JSQErrorMessageWrongTrustedIdentityKey:
|
||||
return [NSString stringWithFormat:@"Error : Wrong trusted identity key for %@.", self.senderDisplayName];
|
||||
break;
|
||||
case JSQErrorMessageInvalidKeyException:
|
||||
return [NSString stringWithFormat:@"Error : Invalid key exception for %@.", self.senderDisplayName];
|
||||
break;
|
||||
case JSQErrorMessageMissingKeyId:
|
||||
return [NSString stringWithFormat:@"Error: Missing key identifier for %@", self.senderDisplayName];
|
||||
break;
|
||||
case JSQErrorMessageInvalidMessage:
|
||||
return [NSString stringWithFormat:@"Error: Invalid message"];
|
||||
break;
|
||||
case JSQErrorMessageDuplicateMessage:
|
||||
return [NSString stringWithFormat:@"Error: Duplicate message"];
|
||||
break;
|
||||
case JSQErrorMessageInvalidVersion:
|
||||
return [NSString stringWithFormat:@"Error: Invalid version for contact %@.", self.senderDisplayName];
|
||||
break;
|
||||
|
||||
default:
|
||||
return nil;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSUInteger)hash
|
||||
{
|
||||
return self.senderId.hash ^ self.date.hash;
|
||||
}
|
||||
|
||||
- (NSString*)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"<%@: senderId=%@, senderDisplayName=%@, date=%@, type=%ld>",
|
||||
[self class], self.senderId, self.senderDisplayName, self.date, self.errorMessageType];
|
||||
}
|
||||
|
||||
-(TSMessageAdapterType)messageType
|
||||
{
|
||||
return TSErrorMessageAdapter;
|
||||
}
|
||||
|
||||
@end
|
||||
@ -1,31 +0,0 @@
|
||||
//
|
||||
// JSQInfoMessage.h
|
||||
// JSQMessages
|
||||
//
|
||||
// Created by Dylan Bourgeois on 29/11/14.
|
||||
// Copyright (c) 2014 Hexed Bits. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JSQDisplayedMessage.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, JSQInfoMessageType){
|
||||
JSQInfoMessageTypeSessionDidEnd,
|
||||
};
|
||||
|
||||
@interface JSQInfoMessage : JSQDisplayedMessage
|
||||
|
||||
@property (nonatomic) JSQInfoMessageType infoMessageType;
|
||||
|
||||
@property (nonatomic) TSMessageAdapterType messageType;
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
- (instancetype)initWithInfoType:(JSQInfoMessageType)messageType
|
||||
senderId:(NSString*)senderId
|
||||
senderDisplayName:(NSString*)senderDisplayName
|
||||
date:(NSDate*)date;
|
||||
|
||||
- (NSString*)text;
|
||||
|
||||
|
||||
@end
|
||||
@ -1,54 +0,0 @@
|
||||
//
|
||||
// JSQInfoMessage.m
|
||||
// JSQMessages
|
||||
//
|
||||
// Created by Dylan Bourgeois on 29/11/14.
|
||||
// Copyright (c) 2014 Hexed Bits. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JSQInfoMessage.h"
|
||||
|
||||
@implementation JSQInfoMessage
|
||||
|
||||
- (instancetype)initWithInfoType:(JSQInfoMessageType)messageType
|
||||
senderId:(NSString *)senderId
|
||||
senderDisplayName:(NSString *)senderDisplayName
|
||||
date:(NSDate *)date
|
||||
{
|
||||
//@discussion: NSParameterAssert() ?
|
||||
|
||||
self = [super initWithSenderId:senderId senderDisplayName:senderDisplayName date:date];
|
||||
|
||||
if (self) {
|
||||
_infoMessageType = messageType;
|
||||
_messageType = TSInfoMessageAdapter;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(NSString*)text
|
||||
{
|
||||
switch (self.infoMessageType) {
|
||||
case JSQInfoMessageTypeSessionDidEnd:
|
||||
return [NSString stringWithFormat:@"Session with %@ ended.", self.senderDisplayName];
|
||||
break;
|
||||
|
||||
default:
|
||||
return nil;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
-(NSUInteger)hash
|
||||
{
|
||||
return self.senderId.hash ^ self.date.hash;
|
||||
}
|
||||
|
||||
-(NSString*)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"<%@: senderId=%@, senderDisplayName=%@, date=%@, type=%ld>",
|
||||
[self class], self.senderId, self.senderDisplayName, self.date, self.infoMessageType];
|
||||
}
|
||||
|
||||
@end
|
||||
@ -170,7 +170,7 @@
|
||||
|
||||
- (NSUInteger)hash
|
||||
{
|
||||
return super.hash ^ self.location.hash;
|
||||
return self.location.hash;
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
|
||||
62
JSQMessagesViewController/Model/JSQMediaMessage.h
Normal file
@ -0,0 +1,62 @@
|
||||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// Documentation
|
||||
// http://cocoadocs.org/docsets/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// GitHub
|
||||
// https://github.com/jessesquires/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// Released under an MIT license: http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import "JSQMessage.h"
|
||||
|
||||
/**
|
||||
* The `JSQMediaMessage` class is a concrete class for media message model objects that inherits from `JSQMessage`.
|
||||
* An instance of `JSQMediaMessage` is an immutable model object that represents a single user media message.
|
||||
* It implements the `JSQMessageData` protocol and contains the message media.
|
||||
*/
|
||||
@interface JSQMediaMessage : JSQMessage <JSQMessageData, NSCoding, NSCopying>
|
||||
|
||||
/**
|
||||
* Returns the media item associate with the message.
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) id<JSQMessageMediaData> media;
|
||||
|
||||
/**
|
||||
* Initializes and returns a media message object having the given senderId, displayName, media,
|
||||
* and current system date.
|
||||
*
|
||||
* @param senderId The unique identifier for the user who sent the message. This value must not be `nil`.
|
||||
* @param displayName The display name for the user who sent the message. This value must not be `nil`.
|
||||
* @param media The media data for the message. This value must not be `nil`.
|
||||
*
|
||||
* @return An initialized `JSQMediaMessage` object if successful, `nil` otherwise.
|
||||
*/
|
||||
+ (instancetype)messageWithSenderId:(NSString *)senderId
|
||||
displayName:(NSString *)displayName
|
||||
media:(id<JSQMessageMediaData>)media;
|
||||
|
||||
/**
|
||||
* Initializes and returns a media message object having the given senderId, displayName, date, and media.
|
||||
*
|
||||
* @param senderId The unique identifier for the user who sent the message. This value must not be `nil`.
|
||||
* @param senderDisplayName The display name for the user who sent the message. This value must not be `nil`.
|
||||
* @param date The date that the message was sent. This value must not be `nil`.
|
||||
* @param media The media data for the message. This value must not be `nil`.
|
||||
*
|
||||
* @return An initialized `JSQMediaMessage` object if successful, `nil` otherwise.
|
||||
*/
|
||||
- (instancetype)initWithSenderId:(NSString *)senderId
|
||||
senderDisplayName:(NSString *)senderDisplayName
|
||||
date:(NSDate *)date
|
||||
media:(id<JSQMessageMediaData>)media;
|
||||
|
||||
@end
|
||||
114
JSQMessagesViewController/Model/JSQMediaMessage.m
Normal file
@ -0,0 +1,114 @@
|
||||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// Documentation
|
||||
// http://cocoadocs.org/docsets/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// GitHub
|
||||
// https://github.com/jessesquires/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// Released under an MIT license: http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import "JSQMediaMessage.h"
|
||||
|
||||
@implementation JSQMediaMessage
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
+ (instancetype)messageWithSenderId:(NSString *)senderId
|
||||
displayName:(NSString *)displayName
|
||||
media:(id<JSQMessageMediaData>)media
|
||||
{
|
||||
return [[JSQMediaMessage alloc] initWithSenderId:senderId
|
||||
senderDisplayName:displayName
|
||||
date:[NSDate date]
|
||||
media:media];
|
||||
}
|
||||
|
||||
- (instancetype)initWithSenderId:(NSString *)senderId
|
||||
senderDisplayName:(NSString *)senderDisplayName
|
||||
date:(NSDate *)date
|
||||
media:(id<JSQMessageMediaData>)media
|
||||
{
|
||||
NSParameterAssert(media != nil);
|
||||
|
||||
self = [super initWithSenderId:senderId senderDisplayName:senderDisplayName date:date isMedia:YES];
|
||||
if (self) {
|
||||
_media = media;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
NSAssert(NO, @"%s is not a valid initializer for %@. Use %@ instead.",
|
||||
__PRETTY_FUNCTION__, [self class], NSStringFromSelector(@selector(initWithSenderId:senderDisplayName:date:media:)));
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
_media = nil;
|
||||
}
|
||||
|
||||
#pragma mark - NSObject
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (![super isEqual:object]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
JSQMediaMessage *mediaMessage = (JSQMediaMessage *)object;
|
||||
|
||||
return [self.media isEqual:mediaMessage.media];
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"<%@: senderId=%@, senderDisplayName=%@, date=%@, isMediaMessage=%@, media=%@>",
|
||||
[self class], self.senderId, self.senderDisplayName, self.date, @(self.isMediaMessage), self.media];
|
||||
}
|
||||
- (id)debugQuickLookObject
|
||||
{
|
||||
return [self.media mediaView] ?: [self.media mediaPlaceholderView];
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
self = [super initWithCoder:aDecoder];
|
||||
if (self) {
|
||||
_media = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(media))];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
if ([self.media conformsToProtocol:@protocol(NSCoding)]) {
|
||||
[aCoder encodeObject:self.media forKey:NSStringFromSelector(@selector(media))];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
return [[[self class] allocWithZone:zone] initWithSenderId:self.senderId
|
||||
senderDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
media:self.media];
|
||||
}
|
||||
|
||||
@end
|
||||
@ -20,21 +20,14 @@
|
||||
|
||||
#import "JSQMessageData.h"
|
||||
|
||||
|
||||
typedef enum : NSUInteger {
|
||||
kMessageNone,
|
||||
kMessageSent,
|
||||
kMessageRead,
|
||||
kMessageReceived,
|
||||
kMesageFailed
|
||||
} MessageStatus;
|
||||
|
||||
/**
|
||||
* The `JSQMessage` class is a concrete class for message model objects that represents a single user message.
|
||||
* The message can be a text message or media message, depending on how it is initialized.
|
||||
* It implements the `JSQMessageData` protocol and it contains the senderId, senderDisplayName,
|
||||
* and the date that the message was sent. If initialized as a media message it also contains a media attachment,
|
||||
* otherwise it contains the message text.
|
||||
* The `JSQMessage` class is an abstract base class for message model objects that represents a single user message.
|
||||
* It contains the senderId, senderDisplayName, and the date that the message was sent.
|
||||
*
|
||||
* @warning This class is intended to be subclassed. You should not use it directly.
|
||||
*
|
||||
* @see JSQTextMessage.
|
||||
* @see JSQMediaMessage.
|
||||
*/
|
||||
@interface JSQMessage : NSObject <JSQMessageData, NSCoding, NSCopying>
|
||||
|
||||
@ -55,94 +48,25 @@ typedef enum : NSUInteger {
|
||||
|
||||
/**
|
||||
* Returns a boolean value specifying whether or not the message contains media.
|
||||
* If `NO`, the message contains text. If `YES`, the message contains media.
|
||||
* The value of this property depends on how the object was initialized.
|
||||
* The default value is `NO`, meaning that is message contains text, not media.
|
||||
*/
|
||||
@property (assign, nonatomic, readonly) BOOL isMediaMessage;
|
||||
|
||||
@property (nonatomic) MessageStatus status;
|
||||
|
||||
/**
|
||||
* Returns the body text of the message, or `nil` if the message is a media message.
|
||||
* That is, if `isMediaMessage` is equal to `YES` then this value will be `nil`.
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) NSString *text;
|
||||
|
||||
/**
|
||||
* Returns the media item attachment of the message, or `nil` if the message is not a media message.
|
||||
* That is, if `isMediaMessage` is equal to `NO` then this value will be `nil`.
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) id<JSQMessageMediaData> media;
|
||||
|
||||
|
||||
@property (nonatomic) TSMessageAdapterType messageType;
|
||||
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
/**
|
||||
* Initializes and returns a message object having the given senderId, displayName, text,
|
||||
* and current system date.
|
||||
*
|
||||
* @param senderId The unique identifier for the user who sent the message. This value must not be `nil`.
|
||||
* @param displayName The display name for the user who sent the message. This value must not be `nil`.
|
||||
* @param text The body text of the message. This value must not be `nil`.
|
||||
*
|
||||
* @discussion Initializing a `JSQMessage` with this method will set `isMediaMessage` to `NO`.
|
||||
*
|
||||
* @return An initialized `JSQMessage` object if successful, `nil` otherwise.
|
||||
*/
|
||||
+ (instancetype)messageWithSenderId:(NSString *)senderId
|
||||
displayName:(NSString *)displayName
|
||||
text:(NSString *)text;
|
||||
|
||||
/**
|
||||
* Initializes and returns a message object having the given senderId, senderDisplayName, date, and text.
|
||||
* Initializes and returns a message object having the given senderId, senderDisplayName, and date.
|
||||
*
|
||||
* @param senderId The unique identifier for the user who sent the message. This value must not be `nil`.
|
||||
* @param senderDisplayName The display name for the user who sent the message. This value must not be `nil`.
|
||||
* @param date The date that the message was sent. This value must not be `nil`.
|
||||
* @param text The body text of the message. This value must not be `nil`.
|
||||
*
|
||||
* @discussion Initializing a `JSQMessage` with this method will set `isMediaMessage` to `NO`.
|
||||
* @param isMedia A boolean value specifying whether or not the message contains media.
|
||||
*
|
||||
* @return An initialized `JSQMessage` object if successful, `nil` otherwise.
|
||||
*/
|
||||
- (instancetype)initWithSenderId:(NSString *)senderId
|
||||
senderDisplayName:(NSString *)senderDisplayName
|
||||
date:(NSDate *)date
|
||||
text:(NSString *)text;
|
||||
/**
|
||||
* Initializes and returns a message object having the given senderId, displayName, media,
|
||||
* and current system date.
|
||||
*
|
||||
* @param senderId The unique identifier for the user who sent the message. This value must not be `nil`.
|
||||
* @param displayName The display name for the user who sent the message. This value must not be `nil`.
|
||||
* @param media The media data for the message. This value must not be `nil`.
|
||||
*
|
||||
* @discussion Initializing a `JSQMessage` with this method will set `isMediaMessage` to `YES`.
|
||||
*
|
||||
* @return An initialized `JSQMessage` object if successful, `nil` otherwise.
|
||||
*/
|
||||
+ (instancetype)messageWithSenderId:(NSString *)senderId
|
||||
displayName:(NSString *)displayName
|
||||
media:(id<JSQMessageMediaData>)media;
|
||||
|
||||
/**
|
||||
* Initializes and returns a message object having the given senderId, displayName, date, and media.
|
||||
*
|
||||
* @param senderId The unique identifier for the user who sent the message. This value must not be `nil`.
|
||||
* @param senderDisplayName The display name for the user who sent the message. This value must not be `nil`.
|
||||
* @param date The date that the message was sent. This value must not be `nil`.
|
||||
* @param media The media data for the message. This value must not be `nil`.
|
||||
*
|
||||
* @discussion Initializing a `JSQMessage` with this method will set `isMediaMessage` to `YES`.
|
||||
*
|
||||
* @return An initialized `JSQMessage` object if successful, `nil` otherwise.
|
||||
*/
|
||||
- (instancetype)initWithSenderId:(NSString *)senderId
|
||||
senderDisplayName:(NSString *)senderDisplayName
|
||||
date:(NSDate *)date
|
||||
media:(id<JSQMessageMediaData>)media;
|
||||
isMedia:(BOOL)isMedia;
|
||||
|
||||
@end
|
||||
|
||||
@ -18,70 +18,10 @@
|
||||
|
||||
#import "JSQMessage.h"
|
||||
|
||||
|
||||
|
||||
@interface JSQMessage ()
|
||||
|
||||
- (instancetype)initWithSenderId:(NSString *)senderId
|
||||
senderDisplayName:(NSString *)senderDisplayName
|
||||
date:(NSDate *)date
|
||||
isMedia:(BOOL)isMedia;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation JSQMessage
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
+ (instancetype)messageWithSenderId:(NSString *)senderId
|
||||
displayName:(NSString *)displayName
|
||||
text:(NSString *)text
|
||||
{
|
||||
return [[JSQMessage alloc] initWithSenderId:senderId
|
||||
senderDisplayName:displayName
|
||||
date:[NSDate date]
|
||||
text:text];
|
||||
}
|
||||
|
||||
- (instancetype)initWithSenderId:(NSString *)senderId
|
||||
senderDisplayName:(NSString *)senderDisplayName
|
||||
date:(NSDate *)date
|
||||
text:(NSString *)text
|
||||
{
|
||||
NSParameterAssert(text != nil);
|
||||
|
||||
self = [self initWithSenderId:senderId senderDisplayName:senderDisplayName date:date isMedia:NO];
|
||||
if (self) {
|
||||
_text = [text copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)messageWithSenderId:(NSString *)senderId
|
||||
displayName:(NSString *)displayName
|
||||
media:(id<JSQMessageMediaData>)media
|
||||
{
|
||||
return [[JSQMessage alloc] initWithSenderId:senderId
|
||||
senderDisplayName:displayName
|
||||
date:[NSDate date]
|
||||
media:media];
|
||||
}
|
||||
|
||||
- (instancetype)initWithSenderId:(NSString *)senderId
|
||||
senderDisplayName:(NSString *)senderDisplayName
|
||||
date:(NSDate *)date
|
||||
media:(id<JSQMessageMediaData>)media
|
||||
{
|
||||
NSParameterAssert(media != nil);
|
||||
|
||||
self = [self initWithSenderId:senderId senderDisplayName:senderDisplayName date:date isMedia:YES];
|
||||
if (self) {
|
||||
_media = media;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithSenderId:(NSString *)senderId
|
||||
senderDisplayName:(NSString *)senderDisplayName
|
||||
date:(NSDate *)date
|
||||
@ -97,14 +37,14 @@
|
||||
_senderDisplayName = [senderDisplayName copy];
|
||||
_date = [date copy];
|
||||
_isMediaMessage = isMedia;
|
||||
_messageType = TSGenericTextMessageAdapter;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
NSAssert(NO, @"%s is not a valid initializer for %@.", __PRETTY_FUNCTION__, [self class]);
|
||||
NSAssert(NO, @"%s is not a valid initializer for %@. Use %@ instead.",
|
||||
__PRETTY_FUNCTION__, [self class], NSStringFromSelector(@selector(initWithSenderId:senderDisplayName:date:isMedia:)));
|
||||
return nil;
|
||||
}
|
||||
|
||||
@ -113,9 +53,6 @@
|
||||
_senderId = nil;
|
||||
_senderDisplayName = nil;
|
||||
_date = nil;
|
||||
_status = kMessageNone;
|
||||
_text = nil;
|
||||
_media = nil;
|
||||
}
|
||||
|
||||
#pragma mark - NSObject
|
||||
@ -132,34 +69,21 @@
|
||||
|
||||
JSQMessage *aMessage = (JSQMessage *)object;
|
||||
|
||||
if (self.isMediaMessage != aMessage.isMediaMessage) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
BOOL hasEqualContent = self.isMediaMessage ? [self.media isEqual:aMessage.media] : [self.text isEqualToString:aMessage.text];
|
||||
|
||||
return [self.senderId isEqualToString:aMessage.senderId]
|
||||
&& [self.senderDisplayName isEqualToString:aMessage.senderDisplayName]
|
||||
&& ([self.date compare:aMessage.date] == NSOrderedSame)
|
||||
&& hasEqualContent;
|
||||
&& self.isMediaMessage == aMessage.isMediaMessage;
|
||||
}
|
||||
|
||||
- (NSUInteger)hash
|
||||
{
|
||||
NSUInteger contentHash = self.isMediaMessage ? self.media.hash : self.text.hash;
|
||||
|
||||
return self.senderId.hash ^ self.date.hash ^ contentHash;
|
||||
return self.senderId.hash ^ self.date.hash;
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"<%@: senderId=%@, senderDisplayName=%@, date=%@, isMediaMessage=%@, text=%@, media=%@>",
|
||||
[self class], self.senderId, self.senderDisplayName, self.date, @(self.isMediaMessage), self.text, self.media];
|
||||
}
|
||||
|
||||
- (id)debugQuickLookObject
|
||||
{
|
||||
return [self.media mediaView] ?: [self.media mediaPlaceholderView];
|
||||
return [NSString stringWithFormat:@"<%@: senderId=%@, senderDisplayName=%@, date=%@, isMediaMessage=%@>",
|
||||
[self class], self.senderId, self.senderDisplayName, self.date, @(self.isMediaMessage)];
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding
|
||||
@ -172,8 +96,6 @@
|
||||
_senderDisplayName = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(senderDisplayName))];
|
||||
_date = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(date))];
|
||||
_isMediaMessage = [aDecoder decodeBoolForKey:NSStringFromSelector(@selector(isMediaMessage))];
|
||||
_text = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(text))];
|
||||
_media = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(media))];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -184,28 +106,16 @@
|
||||
[aCoder encodeObject:self.senderDisplayName forKey:NSStringFromSelector(@selector(senderDisplayName))];
|
||||
[aCoder encodeObject:self.date forKey:NSStringFromSelector(@selector(date))];
|
||||
[aCoder encodeBool:self.isMediaMessage forKey:NSStringFromSelector(@selector(isMediaMessage))];
|
||||
[aCoder encodeObject:self.text forKey:NSStringFromSelector(@selector(text))];
|
||||
|
||||
if ([self.media conformsToProtocol:@protocol(NSCoding)]) {
|
||||
[aCoder encodeObject:self.media forKey:NSStringFromSelector(@selector(media))];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
if (self.isMediaMessage) {
|
||||
return [[[self class] allocWithZone:zone] initWithSenderId:self.senderId
|
||||
senderDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
media:self.media];
|
||||
}
|
||||
|
||||
return [[[self class] allocWithZone:zone] initWithSenderId:self.senderId
|
||||
senderDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
text:self.text];
|
||||
isMedia:self.isMediaMessage];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -20,16 +20,6 @@
|
||||
|
||||
#import "JSQMessageMediaData.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, TSMessageAdapterType) {
|
||||
TSIncomingMessageAdapter,
|
||||
TSOutgoingMessageAdapter,
|
||||
TSCallAdapter,
|
||||
TSInfoMessageAdapter,
|
||||
TSErrorMessageAdapter,
|
||||
TSMediaAttachmentAdapter,
|
||||
TSGenericTextMessageAdapter, //Used when message direction is unknown (outgoing or incoming)
|
||||
};
|
||||
|
||||
/**
|
||||
* The `JSQMessageData` protocol defines the common interface through which
|
||||
* a `JSQMessagesViewController` and `JSQMessagesCollectionView` interact with message model objects.
|
||||
@ -71,12 +61,19 @@ typedef NS_ENUM(NSInteger, TSMessageAdapterType) {
|
||||
*/
|
||||
- (NSDate *)date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return An integer that can be used as a table address in a hash table structure.
|
||||
* This method is used to determine if the message data item contains text or media.
|
||||
* If this method returns `YES`, an instance of `JSQMessagesViewController` will ignore
|
||||
* the `text` method of this protocol when dequeuing a `JSQMessagesCollectionViewCell`
|
||||
* and only call the `media` method.
|
||||
*
|
||||
* Similarly, if this method returns `NO` then the `media` method will be ignored and
|
||||
* and only the `text` method will be called.
|
||||
*
|
||||
* @return A boolean value specifying whether or not this is a media message or a text message.
|
||||
* Return `YES` if this item is a media message, and `NO` if it is a text message.
|
||||
*/
|
||||
- (NSUInteger)hash;
|
||||
- (BOOL)isMediaMessage;
|
||||
|
||||
@optional
|
||||
|
||||
@ -94,38 +91,4 @@ typedef NS_ENUM(NSInteger, TSMessageAdapterType) {
|
||||
*/
|
||||
- (id<JSQMessageMediaData>)media;
|
||||
|
||||
/**
|
||||
* This method is used to determine if the message data item contains text or media.
|
||||
* If this method returns `YES`, an instance of `JSQMessagesViewController` will ignore
|
||||
* the `text` method of this protocol when dequeuing a `JSQMessagesCollectionViewCell`
|
||||
* and only call the `media` method.
|
||||
*
|
||||
* Similarly, if this method returns `NO` then the `media` method will be ignored and
|
||||
* and only the `text` method will be called.
|
||||
*
|
||||
* @return A boolean value specifying whether or not this is a media message or a text message.
|
||||
* Return `YES` if this item is a media message, and `NO` if it is a text message.
|
||||
*/
|
||||
- (BOOL)isMediaMessage;
|
||||
|
||||
|
||||
/*
|
||||
* Returns the message's state (eg for Signal :
|
||||
* TSOutgoingMessageStateAttemptingOut,
|
||||
* TSOutgoingMessageStateUnsent,
|
||||
* TSOutgoingMessageStateSent,
|
||||
* TSOutgoingMessageStateDelivered)
|
||||
*/
|
||||
- (NSInteger) messageState;
|
||||
|
||||
/*
|
||||
* Returns the type of message.
|
||||
* Does not need to be implemented for JSQMessage,
|
||||
* only for children JSQOutgoingMessage or JSQIncomingMessage.
|
||||
*
|
||||
* @see TSMessageType
|
||||
*/
|
||||
|
||||
- (TSMessageAdapterType) messageType;
|
||||
|
||||
@end
|
||||
|
||||
@ -70,9 +70,4 @@
|
||||
*/
|
||||
- (UIView *)mediaPlaceholderView;
|
||||
|
||||
/**
|
||||
* @return An integer that can be used as a table address in a hash table structure.
|
||||
*/
|
||||
- (NSUInteger)hash;
|
||||
|
||||
@end
|
||||
|
||||
@ -49,7 +49,6 @@
|
||||
_cachedImageView = nil;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Setters
|
||||
|
||||
- (void)setImage:(UIImage *)image
|
||||
@ -87,9 +86,20 @@
|
||||
|
||||
#pragma mark - NSObject
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (![super isEqual:object]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
JSQPhotoMediaItem *photoItem = (JSQPhotoMediaItem *)object;
|
||||
|
||||
return [self.image isEqual:photoItem.image];
|
||||
}
|
||||
|
||||
- (NSUInteger)hash
|
||||
{
|
||||
return super.hash ^ self.image.hash;
|
||||
return self.image.hash;
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
|
||||
62
JSQMessagesViewController/Model/JSQTextMessage.h
Normal file
@ -0,0 +1,62 @@
|
||||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// Documentation
|
||||
// http://cocoadocs.org/docsets/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// GitHub
|
||||
// https://github.com/jessesquires/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// Released under an MIT license: http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import "JSQMessage.h"
|
||||
|
||||
/**
|
||||
* The `JSQTextMessage` class is a concrete class for text message model objects that inherits from `JSQMessage`.
|
||||
* An instance of `JSQTextMessage` is an immutable model object that represents a single user text message.
|
||||
* It implements the `JSQMessageData` protocol and contains the message text.
|
||||
*/
|
||||
@interface JSQTextMessage : JSQMessage <JSQMessageData, NSCoding, NSCopying>
|
||||
|
||||
/**
|
||||
* Returns the body text of the message.
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) NSString *text;
|
||||
|
||||
/**
|
||||
* Initializes and returns a text message object having the given senderId, displayName, text,
|
||||
* and current system date.
|
||||
*
|
||||
* @param senderId The unique identifier for the user who sent the message. This value must not be `nil`.
|
||||
* @param displayName The display name for the user who sent the message. This value must not be `nil`.
|
||||
* @param text The body text of the message. This value must not be `nil`.
|
||||
*
|
||||
* @return An initialized `JSQTextMessage` object if successful, `nil` otherwise.
|
||||
*/
|
||||
+ (instancetype)messageWithSenderId:(NSString *)senderId
|
||||
displayName:(NSString *)displayName
|
||||
text:(NSString *)text;
|
||||
|
||||
/**
|
||||
* Initializes and returns a text message object having the given senderId, senderDisplayName, date, and text.
|
||||
*
|
||||
* @param senderId The unique identifier for the user who sent the message. This value must not be `nil`.
|
||||
* @param senderDisplayName The display name for the user who sent the message. This value must not be `nil`.
|
||||
* @param date The date that the message was sent. This value must not be `nil`.
|
||||
* @param text The body text of the message. This value must not be `nil`.
|
||||
*
|
||||
* @return An initialized `JSQTextMessage` object if successful, `nil` otherwise.
|
||||
*/
|
||||
- (instancetype)initWithSenderId:(NSString *)senderId
|
||||
senderDisplayName:(NSString *)senderDisplayName
|
||||
date:(NSDate *)date
|
||||
text:(NSString *)text;
|
||||
|
||||
@end
|
||||
107
JSQMessagesViewController/Model/JSQTextMessage.m
Normal file
@ -0,0 +1,107 @@
|
||||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// Documentation
|
||||
// http://cocoadocs.org/docsets/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// GitHub
|
||||
// https://github.com/jessesquires/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// Released under an MIT license: http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import "JSQTextMessage.h"
|
||||
|
||||
@implementation JSQTextMessage
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
+ (instancetype)messageWithSenderId:(NSString *)senderId
|
||||
displayName:(NSString *)displayName
|
||||
text:(NSString *)text
|
||||
{
|
||||
return [[JSQTextMessage alloc] initWithSenderId:senderId
|
||||
senderDisplayName:displayName
|
||||
date:[NSDate date]
|
||||
text:text];
|
||||
}
|
||||
|
||||
- (instancetype)initWithSenderId:(NSString *)senderId
|
||||
senderDisplayName:(NSString *)senderDisplayName
|
||||
date:(NSDate *)date
|
||||
text:(NSString *)text
|
||||
{
|
||||
NSParameterAssert(text != nil);
|
||||
|
||||
self = [super initWithSenderId:senderId senderDisplayName:senderDisplayName date:date isMedia:NO];
|
||||
if (self) {
|
||||
_text = [text copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
NSAssert(NO, @"%s is not a valid initializer for %@. Use %@ instead.",
|
||||
__PRETTY_FUNCTION__, [self class], NSStringFromSelector(@selector(initWithSenderId:senderDisplayName:date:text:)));
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
_text = nil;
|
||||
}
|
||||
|
||||
#pragma mark - NSObject
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (![super isEqual:object]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
JSQTextMessage *textMessage = (JSQTextMessage *)object;
|
||||
|
||||
return [self.text isEqualToString:textMessage.text];
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"<%@: senderId=%@, senderDisplayName=%@, date=%@, isMediaMessage=%@, text=%@>",
|
||||
[self class], self.senderId, self.senderDisplayName, self.date, @(self.isMediaMessage), self.text];
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
self = [super initWithCoder:aDecoder];
|
||||
if (self) {
|
||||
_text = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(text))];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
[aCoder encodeObject:self.text forKey:NSStringFromSelector(@selector(text))];
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
return [[[self class] allocWithZone:zone] initWithSenderId:self.senderId
|
||||
senderDisplayName:self.senderDisplayName
|
||||
date:self.date
|
||||
text:self.text];
|
||||
}
|
||||
|
||||
@end
|
||||
@ -112,7 +112,7 @@
|
||||
|
||||
- (NSUInteger)hash
|
||||
{
|
||||
return super.hash ^ self.fileURL.hash;
|
||||
return self.fileURL.hash;
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
//
|
||||
// JSQCallCollectionViewCell.h
|
||||
// JSQMessages
|
||||
//
|
||||
// Created by Dylan Bourgeois on 20/11/14.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "JSQMessagesLabel.h"
|
||||
|
||||
#define kCallCellHeight 40.0f
|
||||
#define kCallCellWidth 400.0f
|
||||
|
||||
@interface JSQCallCollectionViewCell : UICollectionViewCell
|
||||
|
||||
@property (weak, nonatomic, readonly) JSQMessagesLabel *cellLabel;
|
||||
|
||||
@property (weak, nonatomic, readonly) UIImageView *outgoingCallImageView;
|
||||
|
||||
@property (weak, nonatomic, readonly) UIImageView *incomingCallImageView;
|
||||
|
||||
|
||||
#pragma mark - Class methods
|
||||
|
||||
+ (UINib *)nib;
|
||||
|
||||
+ (NSString *)cellReuseIdentifier;
|
||||
|
||||
@end
|
||||
@ -1,95 +0,0 @@
|
||||
//
|
||||
// JSQCallCollectionViewCell.m
|
||||
// JSQMessages
|
||||
//
|
||||
// Created by Dylan Bourgeois on 20/11/14.
|
||||
//
|
||||
|
||||
#import "JSQCallCollectionViewCell.h"
|
||||
|
||||
#import "UIView+JSQMessages.h"
|
||||
|
||||
|
||||
@interface JSQCallCollectionViewCell ()
|
||||
|
||||
@property (weak, nonatomic) IBOutlet JSQMessagesLabel *cellLabel;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *outgoingCallImageView;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *incomingCallImageView;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *cellLabelHeightConstraint;
|
||||
|
||||
- (void)jsq_updateConstraint:(NSLayoutConstraint *)constraint withConstant:(CGFloat)constant;
|
||||
|
||||
@end
|
||||
|
||||
@implementation JSQCallCollectionViewCell
|
||||
|
||||
#pragma mark - Class Methods
|
||||
|
||||
+ (UINib *)nib
|
||||
{
|
||||
return [UINib nibWithNibName:NSStringFromClass([self class]) bundle:[NSBundle mainBundle]];
|
||||
}
|
||||
|
||||
+ (NSString *)cellReuseIdentifier
|
||||
{
|
||||
return NSStringFromClass([self class]);
|
||||
}
|
||||
|
||||
#pragma mark - Initializer
|
||||
|
||||
-(void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
|
||||
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
|
||||
self.backgroundColor = [UIColor whiteColor];
|
||||
self.cellLabelHeightConstraint.constant = 0.0f;
|
||||
|
||||
self.cellLabel.textAlignment = NSTextAlignmentCenter;
|
||||
self.cellLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:14.0f];
|
||||
self.cellLabel.textColor = [UIColor lightGrayColor];
|
||||
}
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
_cellLabel = nil;
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - Collection view cell
|
||||
|
||||
-(void)prepareForReuse
|
||||
{
|
||||
[super prepareForReuse];
|
||||
|
||||
self.cellLabel.text = nil;
|
||||
}
|
||||
|
||||
-(void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
|
||||
{
|
||||
[super applyLayoutAttributes:layoutAttributes];
|
||||
|
||||
[self jsq_updateConstraint:self.cellLabelHeightConstraint
|
||||
withConstant:kCallCellHeight];
|
||||
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Utilities
|
||||
|
||||
- (void)jsq_updateConstraint:(NSLayoutConstraint *)constraint withConstant:(CGFloat)constant
|
||||
{
|
||||
if (constraint.constant == constant) {
|
||||
return;
|
||||
}
|
||||
|
||||
constraint.constant = constant;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
@ -1,62 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6250" systemVersion="14C68k" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6244"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="Efo-Hk-7Hw" customClass="JSQCallCollectionViewCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YEr-eC-P6i" customClass="JSQMessagesLabel">
|
||||
<rect key="frame" x="39" y="0.0" width="242" height="20"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="20" id="7nw-w2-91p"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="o2l-Ms-1mk">
|
||||
<rect key="frame" x="281" y="0.0" width="20" height="20"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="20" id="78L-mQ-gEo"/>
|
||||
<constraint firstAttribute="width" constant="20" id="olH-5o-XyR"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="H8m-r4-eEC">
|
||||
<rect key="frame" x="19" y="0.0" width="20" height="20"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="20" id="Qay-jM-aBk"/>
|
||||
<constraint firstAttribute="width" constant="20" id="RpE-jJ-cYX"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<constraints>
|
||||
<constraint firstItem="YEr-eC-P6i" firstAttribute="centerY" secondItem="o2l-Ms-1mk" secondAttribute="centerY" id="8wg-Tg-9Nh"/>
|
||||
<constraint firstAttribute="trailing" secondItem="YEr-eC-P6i" secondAttribute="trailing" constant="39" id="Hj7-z5-WMM"/>
|
||||
<constraint firstItem="YEr-eC-P6i" firstAttribute="leading" secondItem="H8m-r4-eEC" secondAttribute="trailing" id="ZZJ-jL-10d"/>
|
||||
<constraint firstItem="YEr-eC-P6i" firstAttribute="top" secondItem="Efo-Hk-7Hw" secondAttribute="top" id="rEI-cY-6lx"/>
|
||||
<constraint firstItem="YEr-eC-P6i" firstAttribute="leading" secondItem="Efo-Hk-7Hw" secondAttribute="leading" constant="39" id="uNd-aK-1hE"/>
|
||||
<constraint firstItem="YEr-eC-P6i" firstAttribute="centerY" secondItem="H8m-r4-eEC" secondAttribute="centerY" id="wg8-V9-pBf"/>
|
||||
<constraint firstItem="o2l-Ms-1mk" firstAttribute="leading" secondItem="YEr-eC-P6i" secondAttribute="trailing" id="wmR-MD-QeR"/>
|
||||
</constraints>
|
||||
<size key="customSize" width="320" height="20"/>
|
||||
<connections>
|
||||
<outlet property="cellLabel" destination="YEr-eC-P6i" id="jii-8O-zLL"/>
|
||||
<outlet property="cellLabelHeightConstraint" destination="7nw-w2-91p" id="3IA-T6-4Eo"/>
|
||||
<outlet property="incomingCallImageView" destination="H8m-r4-eEC" id="hVW-Ng-BnU"/>
|
||||
<outlet property="outgoingCallImageView" destination="o2l-Ms-1mk" id="Q5m-uX-80H"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="219" y="435"/>
|
||||
</collectionViewCell>
|
||||
</objects>
|
||||
</document>
|
||||
@ -1,49 +0,0 @@
|
||||
//
|
||||
// JSQDisplayedMessageCollectionViewCell.h
|
||||
// JSQMessages
|
||||
//
|
||||
// Created by Dylan Bourgeois on 29/11/14.
|
||||
// Copyright (c) 2014 Hexed Bits. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "JSQMessagesLabel.h"
|
||||
|
||||
#define kDisplayedMessageCellTextLabelHeight 50.0f
|
||||
#define kDisplayedMessageCellHeight 70.0f
|
||||
#define kDisplayedMessageCellWidth 200.0f
|
||||
|
||||
@class JSQDisplayedMessageCollectionViewCell;
|
||||
|
||||
@protocol JSQDisplayedCollectionViewCellDelegate <NSObject>
|
||||
|
||||
@required
|
||||
|
||||
|
||||
/**
|
||||
* Tells the delegate that the error/info message bubble has been tapped.
|
||||
*
|
||||
* @param cell The cell that received the tap touch event.
|
||||
*/
|
||||
|
||||
- (void)displayedCollectionViewCellDidTapMessage:(JSQDisplayedMessageCollectionViewCell *)cell;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@interface JSQDisplayedMessageCollectionViewCell : UICollectionViewCell
|
||||
|
||||
@property (weak, nonatomic, readonly) JSQMessagesLabel * cellLabel;
|
||||
|
||||
@property (weak, nonatomic, readonly) UIImageView * headerImageView;
|
||||
|
||||
@property (weak, nonatomic) id<JSQDisplayedCollectionViewCellDelegate> delegate;
|
||||
|
||||
#pragma mark - Class methods
|
||||
|
||||
+ (UINib *) nib;
|
||||
|
||||
+ (NSString *) cellReuseIdentifier;
|
||||
|
||||
@end
|
||||
@ -1,125 +0,0 @@
|
||||
//
|
||||
// JSQDisplayedMessageCollectionViewCell.m
|
||||
// JSQMessages
|
||||
//
|
||||
// Created by Dylan Bourgeois on 29/11/14.
|
||||
// Copyright (c) 2014 Hexed Bits. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JSQDisplayedMessageCollectionViewCell.h"
|
||||
|
||||
#import "UIView+JSQMessages.h"
|
||||
|
||||
@interface JSQDisplayedMessageCollectionViewCell ()
|
||||
|
||||
@property(weak, nonatomic) IBOutlet JSQMessagesLabel* cellLabel;
|
||||
|
||||
@property(weak, nonatomic) IBOutlet NSLayoutConstraint* cellLabelHeightConstraint;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIImageView* headerImageView;
|
||||
|
||||
- (void)jsq_updateConstraint:(NSLayoutConstraint *)constraint withConstant:(CGFloat)constant;
|
||||
|
||||
@end
|
||||
|
||||
@implementation JSQDisplayedMessageCollectionViewCell
|
||||
|
||||
#pragma mark - Class Methods
|
||||
|
||||
+ (UINib *)nib
|
||||
{
|
||||
return [UINib nibWithNibName:NSStringFromClass([self class]) bundle:[NSBundle mainBundle]];
|
||||
}
|
||||
|
||||
+ (NSString *)cellReuseIdentifier
|
||||
{
|
||||
return NSStringFromClass([self class]);
|
||||
}
|
||||
|
||||
#pragma mark - Initializer
|
||||
|
||||
-(void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
|
||||
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
|
||||
self.backgroundColor = [UIColor whiteColor];
|
||||
self.cellLabelHeightConstraint.constant = 0.0f;
|
||||
|
||||
self.cellLabel.layer.borderColor = [[UIColor lightGrayColor] CGColor];
|
||||
self.cellLabel.layer.borderWidth = 0.75f;
|
||||
self.cellLabel.layer.cornerRadius = 5.0f;
|
||||
self.cellLabel.textAlignment = NSTextAlignmentCenter;
|
||||
self.cellLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:14.0f];
|
||||
self.cellLabel.textColor = [UIColor lightGrayColor];
|
||||
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(jsq_handleTapGesture:)];
|
||||
[self addGestureRecognizer:tap];
|
||||
|
||||
}
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
_cellLabel = nil;
|
||||
|
||||
_delegate = nil;
|
||||
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - Collection view cell
|
||||
|
||||
-(void)prepareForReuse
|
||||
{
|
||||
[super prepareForReuse];
|
||||
|
||||
self.cellLabel.text = nil;
|
||||
}
|
||||
|
||||
-(void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
|
||||
{
|
||||
[super applyLayoutAttributes:layoutAttributes];
|
||||
|
||||
[self jsq_updateConstraint:self.cellLabelHeightConstraint
|
||||
withConstant:kDisplayedMessageCellTextLabelHeight];
|
||||
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Utilities
|
||||
|
||||
- (void)jsq_updateConstraint:(NSLayoutConstraint *)constraint withConstant:(CGFloat)constant
|
||||
{
|
||||
if (constraint.constant == constant) {
|
||||
return;
|
||||
}
|
||||
|
||||
constraint.constant = constant;
|
||||
}
|
||||
|
||||
#pragma mark - Gesture recognizers
|
||||
|
||||
-(void)jsq_handleTapGesture:(UITapGestureRecognizer *)tap
|
||||
{
|
||||
CGPoint touchPoint = [tap locationInView:self];
|
||||
|
||||
if (CGRectContainsPoint(self.contentView.frame, touchPoint))
|
||||
{
|
||||
[self.delegate displayedCollectionViewCellDidTapMessage:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
|
||||
{
|
||||
CGPoint touchPt = [touch locationInView:self];
|
||||
|
||||
if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
|
||||
return CGRectContainsPoint(self.contentView.frame, touchPt);
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@ -1,65 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6250" systemVersion="14C68k" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6244"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="eMU-z2-CzM" customClass="JSQDisplayedMessageCollectionViewCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="70"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="70"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OVa-Xw-5vl" customClass="JSQMessagesLabel">
|
||||
<rect key="frame" x="8" y="20" width="304" height="50"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="50" id="fed-2c-dqd"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="warning_white.png" translatesAutoresizingMaskIntoConstraints="NO" id="ePO-Cy-jUE">
|
||||
<rect key="frame" x="143" y="-3" width="35" height="35"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="35" id="Llx-81-oyV"/>
|
||||
<constraint firstAttribute="width" constant="35" id="Nth-3D-Wo9"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<constraints>
|
||||
<constraint firstItem="OVa-Xw-5vl" firstAttribute="top" secondItem="eMU-z2-CzM" secondAttribute="top" id="2E8-Lm-cti"/>
|
||||
<constraint firstItem="OVa-Xw-5vl" firstAttribute="top" secondItem="ePO-Cy-jUE" secondAttribute="bottom" constant="-12" id="4ie-2d-9cn"/>
|
||||
<constraint firstAttribute="trailing" secondItem="OVa-Xw-5vl" secondAttribute="trailing" constant="8" id="5Mk-DE-t1M"/>
|
||||
<constraint firstItem="OVa-Xw-5vl" firstAttribute="leading" secondItem="eMU-z2-CzM" secondAttribute="leading" constant="8" id="E3N-dw-XQG"/>
|
||||
<constraint firstItem="OVa-Xw-5vl" firstAttribute="top" secondItem="ePO-Cy-jUE" secondAttribute="bottom" id="Yy0-Kd-Lu4"/>
|
||||
<constraint firstItem="ePO-Cy-jUE" firstAttribute="top" secondItem="eMU-z2-CzM" secondAttribute="top" id="ZSC-Dm-tsL"/>
|
||||
<constraint firstAttribute="bottom" secondItem="OVa-Xw-5vl" secondAttribute="bottom" id="jaG-ZH-h7s"/>
|
||||
<constraint firstItem="OVa-Xw-5vl" firstAttribute="centerX" secondItem="ePO-Cy-jUE" secondAttribute="centerX" id="rdy-5p-ndu"/>
|
||||
</constraints>
|
||||
<size key="customSize" width="320" height="55"/>
|
||||
<variation key="default">
|
||||
<mask key="constraints">
|
||||
<exclude reference="2E8-Lm-cti"/>
|
||||
<exclude reference="Yy0-Kd-Lu4"/>
|
||||
<exclude reference="ZSC-Dm-tsL"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<connections>
|
||||
<outlet property="cellLabel" destination="OVa-Xw-5vl" id="7PC-oj-dQZ"/>
|
||||
<outlet property="cellLabelHeightConstraint" destination="fed-2c-dqd" id="98O-NG-4yI"/>
|
||||
<outlet property="headerImageView" destination="ePO-Cy-jUE" id="4uq-2C-V7U"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="219" y="433"/>
|
||||
</collectionViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="warning_white.png" width="100" height="100"/>
|
||||
</resources>
|
||||
</document>
|
||||
@ -1,27 +0,0 @@
|
||||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// Documentation
|
||||
// http://cocoadocs.org/docsets/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// GitHub
|
||||
// https://github.com/jessesquires/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// Released under an MIT license: http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
/**
|
||||
* `JSQMessagesCellTextView` is a subclass of `UITextView` that is used to display text
|
||||
* in a `JSQMessagesCollectionViewCell`.
|
||||
*/
|
||||
@interface JSQMessagesCellTextView : UITextView
|
||||
|
||||
@end
|
||||
@ -1,77 +0,0 @@
|
||||
//
|
||||
// Created by Jesse Squires
|
||||
// http://www.jessesquires.com
|
||||
//
|
||||
//
|
||||
// Documentation
|
||||
// http://cocoadocs.org/docsets/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// GitHub
|
||||
// https://github.com/jessesquires/JSQMessagesViewController
|
||||
//
|
||||
//
|
||||
// License
|
||||
// Copyright (c) 2014 Jesse Squires
|
||||
// Released under an MIT license: http://opensource.org/licenses/MIT
|
||||
//
|
||||
|
||||
#import "JSQMessagesCellTextView.h"
|
||||
|
||||
@implementation JSQMessagesCellTextView
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
|
||||
self.textColor = [UIColor whiteColor];
|
||||
self.editable = NO;
|
||||
self.selectable = YES;
|
||||
self.userInteractionEnabled = YES;
|
||||
self.dataDetectorTypes = UIDataDetectorTypeNone;
|
||||
self.showsHorizontalScrollIndicator = NO;
|
||||
self.showsVerticalScrollIndicator = NO;
|
||||
self.scrollEnabled = NO;
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.contentInset = UIEdgeInsetsZero;
|
||||
self.scrollIndicatorInsets = UIEdgeInsetsZero;
|
||||
self.contentOffset = CGPointZero;
|
||||
self.textContainerInset = UIEdgeInsetsZero;
|
||||
self.textContainer.lineFragmentPadding = 0;
|
||||
self.linkTextAttributes = @{ NSForegroundColorAttributeName : [UIColor whiteColor],
|
||||
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };
|
||||
}
|
||||
|
||||
- (void)setSelectedRange:(NSRange)selectedRange
|
||||
{
|
||||
// prevent selecting text
|
||||
[super setSelectedRange:NSMakeRange(NSNotFound, 0)];
|
||||
}
|
||||
|
||||
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
|
||||
{
|
||||
// ignore double-tap to prevent copy/define/etc. menu from showing
|
||||
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
|
||||
UITapGestureRecognizer *tap = (UITapGestureRecognizer *)gestureRecognizer;
|
||||
if (tap.numberOfTapsRequired == 2) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
|
||||
{
|
||||
// ignore double-tap to prevent copy/define/etc. menu from showing
|
||||
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
|
||||
UITapGestureRecognizer *tap = (UITapGestureRecognizer *)gestureRecognizer;
|
||||
if (tap.numberOfTapsRequired == 2) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
@ -22,8 +22,6 @@
|
||||
#import "JSQMessagesCollectionViewDelegateFlowLayout.h"
|
||||
#import "JSQMessagesCollectionViewDataSource.h"
|
||||
#import "JSQMessagesCollectionViewCell.h"
|
||||
#import "JSQDisplayedMessageCollectionViewCell.h"
|
||||
|
||||
|
||||
@class JSQMessagesTypingIndicatorFooterView;
|
||||
@class JSQMessagesLoadEarlierHeaderView;
|
||||
@ -33,7 +31,7 @@
|
||||
* The `JSQMessagesCollectionView` class manages an ordered collection of message data items and presents
|
||||
* them using a specialized layout for messages.
|
||||
*/
|
||||
@interface JSQMessagesCollectionView : UICollectionView <JSQMessagesCollectionViewCellDelegate, JSQDisplayedCollectionViewCellDelegate>
|
||||
@interface JSQMessagesCollectionView : UICollectionView <JSQMessagesCollectionViewCellDelegate>
|
||||
|
||||
/**
|
||||
* The object that provides the data for the collection view.
|
||||
|
||||
@ -27,7 +27,6 @@
|
||||
|
||||
#import "UIColor+JSQMessages.h"
|
||||
|
||||
#import "JSQCallCollectionViewCell.h"
|
||||
|
||||
@interface JSQMessagesCollectionView () <JSQMessagesLoadEarlierHeaderViewDelegate>
|
||||
|
||||
@ -68,12 +67,6 @@
|
||||
[self registerNib:[JSQMessagesLoadEarlierHeaderView nib]
|
||||
forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
|
||||
withReuseIdentifier:[JSQMessagesLoadEarlierHeaderView headerReuseIdentifier]];
|
||||
|
||||
[self registerNib:[JSQCallCollectionViewCell nib]
|
||||
forCellWithReuseIdentifier:[JSQCallCollectionViewCell cellReuseIdentifier]];
|
||||
|
||||
[self registerNib:[JSQDisplayedMessageCollectionViewCell nib]
|
||||
forCellWithReuseIdentifier:[JSQDisplayedMessageCollectionViewCell cellReuseIdentifier]];
|
||||
|
||||
_typingIndicatorDisplaysOnLeft = YES;
|
||||
_typingIndicatorMessageBubbleColor = [UIColor jsq_messageBubbleLightGrayColor];
|
||||
@ -140,47 +133,21 @@
|
||||
|
||||
- (void)messagesCollectionViewCellDidTapAvatar:(JSQMessagesCollectionViewCell *)cell
|
||||
{
|
||||
NSIndexPath *indexPath = [self indexPathForCell:cell];
|
||||
if (indexPath == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self.delegate collectionView:self
|
||||
didTapAvatarImageView:cell.avatarImageView
|
||||
atIndexPath:indexPath];
|
||||
atIndexPath:[self indexPathForCell:cell]];
|
||||
}
|
||||
|
||||
- (void)messagesCollectionViewCellDidTapMessageBubble:(JSQMessagesCollectionViewCell *)cell
|
||||
{
|
||||
NSIndexPath *indexPath = [self indexPathForCell:cell];
|
||||
if (indexPath == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self.delegate collectionView:self didTapMessageBubbleAtIndexPath:indexPath];
|
||||
[self.delegate collectionView:self didTapMessageBubbleAtIndexPath:[self indexPathForCell:cell]];
|
||||
}
|
||||
|
||||
- (void)messagesCollectionViewCellDidTapCell:(JSQMessagesCollectionViewCell *)cell atPosition:(CGPoint)position
|
||||
{
|
||||
NSIndexPath *indexPath = [self indexPathForCell:cell];
|
||||
if (indexPath == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self.delegate collectionView:self
|
||||
didTapCellAtIndexPath:indexPath
|
||||
didTapCellAtIndexPath:[self indexPathForCell:cell]
|
||||
touchLocation:position];
|
||||
}
|
||||
|
||||
- (void)displayedCollectionViewCellDidTapMessage:(JSQDisplayedMessageCollectionViewCell *)cell
|
||||
{
|
||||
NSIndexPath * indexPath = [self indexPathForCell:cell];
|
||||
|
||||
if (indexPath == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self.delegate collectionView:self didTapMessageBubbleAtIndexPath:indexPath];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -19,7 +19,6 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "JSQMessagesLabel.h"
|
||||
#import "JSQMessagesCellTextView.h"
|
||||
|
||||
@class JSQMessagesCollectionViewCell;
|
||||
|
||||
@ -103,7 +102,7 @@
|
||||
*
|
||||
* @warning If mediaView returns a non-nil view, then this value will be `nil`.
|
||||
*/
|
||||
@property (weak, nonatomic, readonly) JSQMessagesCellTextView *textView;
|
||||
@property (weak, nonatomic, readonly) UITextView *textView;
|
||||
|
||||
/**
|
||||
* Returns the bubble image view of the cell that is responsible for displaying message bubble images.
|
||||
|
||||
@ -24,7 +24,6 @@
|
||||
|
||||
#import "UIView+JSQMessages.h"
|
||||
#import "UIDevice+JSQMessages.h"
|
||||
#import "UIColor+JSQMessages.h"
|
||||
|
||||
|
||||
@interface JSQMessagesCollectionViewCell ()
|
||||
@ -35,13 +34,11 @@
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIView *messageBubbleContainerView;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *messageBubbleImageView;
|
||||
@property (weak, nonatomic) IBOutlet JSQMessagesCellTextView *textView;
|
||||
@property (weak, nonatomic) IBOutlet UITextView *textView;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *avatarImageView;
|
||||
@property (weak, nonatomic) IBOutlet UIView *avatarContainerView;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *messageBubbleContainerWidthConstraint;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewTopVerticalSpaceConstraint;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewBottomVerticalSpaceConstraint;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewAvatarHorizontalSpaceConstraint;
|
||||
@ -54,6 +51,8 @@
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *avatarContainerViewWidthConstraint;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *avatarContainerViewHeightConstraint;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *messageBubbleLeftRightMarginConstraint;
|
||||
|
||||
@property (assign, nonatomic) UIEdgeInsets textViewFrameInsets;
|
||||
|
||||
@property (assign, nonatomic) CGSize avatarViewSize;
|
||||
@ -94,8 +93,11 @@
|
||||
[super awakeFromNib];
|
||||
|
||||
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
[self.messageBubbleContainerView setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
[self.avatarContainerView setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
|
||||
self.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
self.cellTopLabelHeightConstraint.constant = 0.0f;
|
||||
self.messageBubbleTopLabelHeightConstraint.constant = 0.0f;
|
||||
self.cellBottomLabelHeightConstraint.constant = 0.0f;
|
||||
@ -112,6 +114,23 @@
|
||||
self.cellBottomLabel.font = [UIFont systemFontOfSize:11.0f];
|
||||
self.cellBottomLabel.textColor = [UIColor lightGrayColor];
|
||||
|
||||
self.textView.textColor = [UIColor whiteColor];
|
||||
self.textView.editable = NO;
|
||||
self.textView.selectable = YES;
|
||||
self.textView.userInteractionEnabled = YES;
|
||||
self.textView.dataDetectorTypes = UIDataDetectorTypeNone;
|
||||
self.textView.showsHorizontalScrollIndicator = NO;
|
||||
self.textView.showsVerticalScrollIndicator = NO;
|
||||
self.textView.scrollEnabled = NO;
|
||||
self.textView.backgroundColor = [UIColor clearColor];
|
||||
self.textView.contentInset = UIEdgeInsetsZero;
|
||||
self.textView.scrollIndicatorInsets = UIEdgeInsetsZero;
|
||||
self.textView.contentOffset = CGPointZero;
|
||||
self.textView.textContainerInset = UIEdgeInsetsZero;
|
||||
self.textView.textContainer.lineFragmentPadding = 0;
|
||||
self.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : [UIColor whiteColor],
|
||||
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };
|
||||
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(jsq_handleTapGesture:)];
|
||||
[self addGestureRecognizer:tap];
|
||||
self.tapGestureRecognizer = tap;
|
||||
@ -140,7 +159,7 @@
|
||||
- (void)prepareForReuse
|
||||
{
|
||||
[super prepareForReuse];
|
||||
|
||||
|
||||
self.cellTopLabel.text = nil;
|
||||
self.messageBubbleTopLabel.text = nil;
|
||||
self.cellBottomLabel.text = nil;
|
||||
@ -168,9 +187,9 @@
|
||||
}
|
||||
|
||||
self.textViewFrameInsets = customAttributes.textViewFrameInsets;
|
||||
|
||||
[self jsq_updateConstraint:self.messageBubbleContainerWidthConstraint
|
||||
withConstant:customAttributes.messageBubbleContainerViewWidth];
|
||||
|
||||
[self jsq_updateConstraint:self.messageBubbleLeftRightMarginConstraint
|
||||
withConstant:customAttributes.messageBubbleLeftRightMargin];
|
||||
|
||||
[self jsq_updateConstraint:self.cellTopLabelHeightConstraint
|
||||
withConstant:customAttributes.cellTopLabelHeight];
|
||||
@ -260,7 +279,7 @@
|
||||
if ([_mediaView isEqual:mediaView]) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
[self.messageBubbleImageView removeFromSuperview];
|
||||
[self.textView removeFromSuperview];
|
||||
|
||||
@ -274,13 +293,11 @@
|
||||
// because of cell re-use (and caching media views, if using built-in library media item)
|
||||
// we may have dequeued a cell with a media view and add this one on top
|
||||
// thus, remove any additional subviews hidden behind the new media view
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
for (NSUInteger i = 0; i < self.messageBubbleContainerView.subviews.count; i++) {
|
||||
if (self.messageBubbleContainerView.subviews[i] != _mediaView) {
|
||||
[self.messageBubbleContainerView.subviews[i] removeFromSuperview];
|
||||
}
|
||||
for (NSUInteger i = 0; i < self.messageBubbleContainerView.subviews.count; i++) {
|
||||
if (self.messageBubbleContainerView.subviews[i] != _mediaView) {
|
||||
[self.messageBubbleContainerView.subviews[i] removeFromSuperview];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
12
JSQMessagesViewController/Views/JSQMessagesCollectionViewCellIncoming.xib
Executable file → Normal file
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6250" systemVersion="14A389" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6245" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6244"/>
|
||||
<deployment defaultVersion="1792" identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
@ -40,7 +40,7 @@
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="OCS-Fu-acq" userLabel="Bubble Image View">
|
||||
<rect key="frame" x="0.0" y="0.0" width="244" height="94"/>
|
||||
</imageView>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KYU-B8-cUW" customClass="JSQMessagesCellTextView">
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KYU-B8-cUW">
|
||||
<rect key="frame" x="6" y="0.0" width="238" height="94"/>
|
||||
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
@ -56,7 +56,6 @@
|
||||
<constraint firstItem="KYU-B8-cUW" firstAttribute="top" secondItem="btS-p8-B7Z" secondAttribute="top" id="aEL-yH-N1p"/>
|
||||
<constraint firstAttribute="bottom" secondItem="OCS-Fu-acq" secondAttribute="bottom" id="aJ4-ZD-tk9"/>
|
||||
<constraint firstItem="OCS-Fu-acq" firstAttribute="leading" secondItem="btS-p8-B7Z" secondAttribute="leading" id="qpQ-dc-2V5"/>
|
||||
<constraint firstAttribute="width" constant="244" id="stE-iz-VHo"/>
|
||||
<constraint firstItem="OCS-Fu-acq" firstAttribute="top" secondItem="btS-p8-B7Z" secondAttribute="top" id="zTa-8g-VY4"/>
|
||||
</constraints>
|
||||
</view>
|
||||
@ -103,6 +102,7 @@
|
||||
<constraint firstItem="btS-p8-B7Z" firstAttribute="leading" secondItem="Da1-09-wR4" secondAttribute="trailing" constant="2" id="j0I-pm-eex"/>
|
||||
<constraint firstItem="btS-p8-B7Z" firstAttribute="top" secondItem="Ufa-bF-l1Y" secondAttribute="bottom" id="jAu-Dn-7rN"/>
|
||||
<constraint firstItem="Da1-09-wR4" firstAttribute="leading" secondItem="4lh-CK-yVn" secondAttribute="leading" id="jiu-B4-TSD"/>
|
||||
<constraint firstAttribute="trailing" secondItem="btS-p8-B7Z" secondAttribute="trailing" constant="40" id="k2n-jk-kOg"/>
|
||||
<constraint firstAttribute="bottom" secondItem="UPz-5x-c1T" secondAttribute="bottom" id="nsK-Gh-M3Z"/>
|
||||
<constraint firstItem="UPz-5x-c1T" firstAttribute="top" secondItem="btS-p8-B7Z" secondAttribute="bottom" id="s8G-Je-7GA"/>
|
||||
</constraints>
|
||||
@ -117,8 +117,8 @@
|
||||
<outlet property="cellTopLabel" destination="afj-rd-iNv" id="bTd-4q-U7e"/>
|
||||
<outlet property="cellTopLabelHeightConstraint" destination="fKS-MR-YPI" id="YWd-Rd-qSL"/>
|
||||
<outlet property="messageBubbleContainerView" destination="btS-p8-B7Z" id="2sk-5p-NEd"/>
|
||||
<outlet property="messageBubbleContainerWidthConstraint" destination="stE-iz-VHo" id="lle-iT-67d"/>
|
||||
<outlet property="messageBubbleImageView" destination="OCS-Fu-acq" id="OuN-5t-30g"/>
|
||||
<outlet property="messageBubbleLeftRightMarginConstraint" destination="k2n-jk-kOg" id="DoB-EE-Ka1"/>
|
||||
<outlet property="messageBubbleTopLabel" destination="Ufa-bF-l1Y" id="VtH-te-blR"/>
|
||||
<outlet property="messageBubbleTopLabelHeightConstraint" destination="fal-sy-hrK" id="kgv-NO-Gud"/>
|
||||
<outlet property="textView" destination="KYU-B8-cUW" id="1Yv-ln-EUZ"/>
|
||||
|
||||
13
JSQMessagesViewController/Views/JSQMessagesCollectionViewCellOutgoing.xib
Executable file → Normal file
@ -1,8 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6250" systemVersion="14C68k" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6245" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6244"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
@ -40,7 +39,7 @@
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="2qm-c6-OZf" userLabel="Bubble Image View">
|
||||
<rect key="frame" x="0.0" y="0.0" width="244" height="94"/>
|
||||
</imageView>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vLY-aM-0Dr" customClass="JSQMessagesCellTextView">
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vLY-aM-0Dr">
|
||||
<rect key="frame" x="0.0" y="0.0" width="238" height="94"/>
|
||||
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
@ -56,7 +55,6 @@
|
||||
<constraint firstItem="vLY-aM-0Dr" firstAttribute="top" secondItem="2zh-vR-QJW" secondAttribute="top" id="RiG-21-Bqc"/>
|
||||
<constraint firstAttribute="bottom" secondItem="vLY-aM-0Dr" secondAttribute="bottom" id="UbF-Bl-Q7v"/>
|
||||
<constraint firstAttribute="trailing" secondItem="vLY-aM-0Dr" secondAttribute="trailing" constant="6" id="aVg-yy-8K7"/>
|
||||
<constraint firstAttribute="width" constant="244" id="imD-52-K45"/>
|
||||
<constraint firstAttribute="bottom" secondItem="2qm-c6-OZf" secondAttribute="bottom" id="lts-Ve-wSh"/>
|
||||
</constraints>
|
||||
</view>
|
||||
@ -104,6 +102,7 @@
|
||||
<constraint firstItem="p52-YN-yLu" firstAttribute="top" secondItem="jxM-YD-sVG" secondAttribute="bottom" id="jBD-JV-AWk"/>
|
||||
<constraint firstItem="jxM-YD-sVG" firstAttribute="leading" secondItem="23f-xH-rkY" secondAttribute="leading" id="qeB-G5-1Wq"/>
|
||||
<constraint firstItem="p52-YN-yLu" firstAttribute="leading" secondItem="23f-xH-rkY" secondAttribute="leading" id="tTj-Mp-0va"/>
|
||||
<constraint firstItem="2zh-vR-QJW" firstAttribute="leading" secondItem="23f-xH-rkY" secondAttribute="leading" constant="40" id="tya-FG-SP6"/>
|
||||
<constraint firstItem="X89-B1-aAd" firstAttribute="leading" secondItem="2zh-vR-QJW" secondAttribute="trailing" constant="2" id="vMz-Yi-B0w"/>
|
||||
</constraints>
|
||||
<size key="customSize" width="317" height="245"/>
|
||||
@ -117,8 +116,8 @@
|
||||
<outlet property="cellTopLabel" destination="jxM-YD-sVG" id="acH-pr-spx"/>
|
||||
<outlet property="cellTopLabelHeightConstraint" destination="9oK-E7-iXA" id="MZM-kV-2dI"/>
|
||||
<outlet property="messageBubbleContainerView" destination="2zh-vR-QJW" id="pu0-GU-eZl"/>
|
||||
<outlet property="messageBubbleContainerWidthConstraint" destination="imD-52-K45" id="Xld-Pa-yJw"/>
|
||||
<outlet property="messageBubbleImageView" destination="2qm-c6-OZf" id="bpy-Gv-jSh"/>
|
||||
<outlet property="messageBubbleLeftRightMarginConstraint" destination="tya-FG-SP6" id="3oJ-6X-GCK"/>
|
||||
<outlet property="messageBubbleTopLabel" destination="p52-YN-yLu" id="SLH-sA-Chu"/>
|
||||
<outlet property="messageBubbleTopLabelHeightConstraint" destination="8TB-va-f8L" id="FNt-BS-Wxi"/>
|
||||
<outlet property="textView" destination="vLY-aM-0Dr" id="YEp-mW-xIY"/>
|
||||
@ -127,7 +126,7 @@
|
||||
<outlet property="textViewMarginHorizontalSpaceConstraint" destination="7rI-Nc-AK3" id="ciu-j6-IpH"/>
|
||||
<outlet property="textViewTopVerticalSpaceConstraint" destination="RiG-21-Bqc" id="i3j-z0-feE"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="371" y="145"/>
|
||||
<point key="canvasLocation" x="283" y="294"/>
|
||||
</collectionViewCell>
|
||||
</objects>
|
||||
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
||||
|
||||
@ -48,22 +48,20 @@
|
||||
CGFloat cornerRadius = 6.0f;
|
||||
|
||||
self.backgroundColor = [UIColor whiteColor];
|
||||
//Signal: Comment out elements of Composer view
|
||||
// self.layer.borderWidth = 0.5f;
|
||||
// self.layer.borderColor = [UIColor lightGrayColor].CGColor;
|
||||
// self.layer.cornerRadius = cornerRadius;
|
||||
self.layer.borderWidth = 0.5f;
|
||||
self.layer.borderColor = [UIColor lightGrayColor].CGColor;
|
||||
self.layer.cornerRadius = cornerRadius;
|
||||
|
||||
self.scrollIndicatorInsets = UIEdgeInsetsMake(cornerRadius, 0.0f, cornerRadius, 0.0f);
|
||||
|
||||
self.textContainerInset = UIEdgeInsetsMake(4.0f, 2.0f, 4.0f, 2.0f);
|
||||
self.contentInset = UIEdgeInsetsMake(1.0f, 0.0f, 1.0f, 0.0f);
|
||||
self.contentInset = UIEdgeInsetsMake(2.0f, 0.0f, 2.0f, 0.0f);
|
||||
|
||||
self.scrollEnabled = YES;
|
||||
self.scrollsToTop = NO;
|
||||
self.userInteractionEnabled = YES;
|
||||
|
||||
self.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:16.0f];
|
||||
// self.font = [UIFont systemFontOfSize:16.0f];
|
||||
self.font = [UIFont systemFontOfSize:16.0f];
|
||||
self.textColor = [UIColor blackColor];
|
||||
self.textAlignment = NSTextAlignmentNatural;
|
||||
|
||||
|
||||
@ -96,7 +96,7 @@ static void * kJSQMessagesInputToolbarKeyValueObservingContext = &kJSQMessagesIn
|
||||
- (void)toggleSendButtonEnabled
|
||||
{
|
||||
BOOL hasText = [self.contentView.textView hasText];
|
||||
|
||||
|
||||
if (self.sendButtonOnRight) {
|
||||
self.contentView.rightBarButtonItem.enabled = hasText;
|
||||
}
|
||||
|
||||
@ -55,10 +55,6 @@
|
||||
|
||||
- (void)setTextInsets:(UIEdgeInsets)textInsets
|
||||
{
|
||||
if (UIEdgeInsetsEqualToEdgeInsets(_textInsets, textInsets)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_textInsets = textInsets;
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
@ -42,61 +42,33 @@ FOUNDATION_EXPORT const CGFloat kJSQMessagesToolbarContentViewHorizontalSpacingD
|
||||
/**
|
||||
* A custom button item displayed on the left of the toolbar content view.
|
||||
*
|
||||
* @discussion The frame height of this button is ignored. When you set this property, the button
|
||||
* is fitted within a pre-defined default content view, the leftBarButtonContainerView,
|
||||
* whose height is determined by the height of the toolbar. However, the width of this button
|
||||
* will be preserved. You may specify a new width using `leftBarButtonItemWidth`.
|
||||
* If the frame of this button is equal to `CGRectZero` when set, then a default frame size will be used.
|
||||
* @discussion The frame of this button is ignored. When you set this property, the button
|
||||
* is fitted within a pre-defined default content view, whose height is determined by the
|
||||
* height of the toolbar. You may specify a new width using `leftBarButtonItemWidth`.
|
||||
* Set this value to `nil` to remove the button.
|
||||
*/
|
||||
@property (weak, nonatomic) UIButton *leftBarButtonItem;
|
||||
|
||||
/**
|
||||
* Specifies the width of the leftBarButtonItem.
|
||||
*
|
||||
* @discussion This property modifies the width of the leftBarButtonContainerView.
|
||||
*/
|
||||
@property (assign, nonatomic) CGFloat leftBarButtonItemWidth;
|
||||
|
||||
/**
|
||||
* The container view for the leftBarButtonItem.
|
||||
*
|
||||
* @discussion
|
||||
* You may use this property to add additional button items to the left side of the toolbar content view.
|
||||
* However, you will be completely responsible for responding to all touch events for these buttons
|
||||
* in your `JSQMessagesViewController` subclass.
|
||||
*/
|
||||
@property (weak, nonatomic, readonly) UIView *leftBarButtonContainerView;
|
||||
|
||||
/**
|
||||
* A custom button item displayed on the right of the toolbar content view.
|
||||
*
|
||||
* @discussion The frame height of this button is ignored. When you set this property, the button
|
||||
* is fitted within a pre-defined default content view, the rightBarButtonContainerView,
|
||||
* whose height is determined by the height of the toolbar. However, the width of this button
|
||||
* will be preserved. You may specify a new width using `rightBarButtonItemWidth`.
|
||||
* If the frame of this button is equal to `CGRectZero` when set, then a default frame size will be used.
|
||||
* @discussion The frame of this button is ignored. When you set this property, the button
|
||||
* is fitted within a pre-defined default content view, whose height is determined by the
|
||||
* height of the toolbar. You may specify a new width using `rightBarButtonItemWidth`.
|
||||
* Set this value to `nil` to remove the button.
|
||||
*/
|
||||
@property (weak, nonatomic) UIButton *rightBarButtonItem;
|
||||
|
||||
/**
|
||||
* Specifies the width of the rightBarButtonItem.
|
||||
*
|
||||
* @discussion This property modifies the width of the rightBarButtonContainerView.
|
||||
*/
|
||||
@property (assign, nonatomic) CGFloat rightBarButtonItemWidth;
|
||||
|
||||
/**
|
||||
* The container view for the rightBarButtonItem.
|
||||
*
|
||||
* @discussion
|
||||
* You may use this property to add additional button items to the right side of the toolbar content view.
|
||||
* However, you will be completely responsible for responding to all touch events for these buttons
|
||||
* in your `JSQMessagesViewController` subclass.
|
||||
*/
|
||||
@property (weak, nonatomic, readonly) UIView *rightBarButtonContainerView;
|
||||
|
||||
#pragma mark - Class methods
|
||||
|
||||
/**
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
|
||||
#import "UIView+JSQMessages.h"
|
||||
|
||||
const CGFloat kJSQMessagesToolbarContentViewHorizontalSpacingDefault = 8.0f;
|
||||
const CGFloat kJSQMessagesToolbarContentViewHorizontalSpacingDefault = 4.0f;
|
||||
|
||||
|
||||
@interface JSQMessagesToolbarContentView ()
|
||||
@ -113,6 +113,10 @@ const CGFloat kJSQMessagesToolbarContentViewHorizontalSpacingDefault = 8.0f;
|
||||
|
||||
- (void)setLeftBarButtonItemWidth:(CGFloat)leftBarButtonItemWidth
|
||||
{
|
||||
self.leftBarButtonItem.frame = CGRectMake(0.0f,
|
||||
0.0f,
|
||||
leftBarButtonItemWidth,
|
||||
CGRectGetHeight(self.leftBarButtonContainerView.frame));
|
||||
self.leftBarButtonContainerViewWidthConstraint.constant = leftBarButtonItemWidth;
|
||||
[self setNeedsUpdateConstraints];
|
||||
}
|
||||
@ -148,6 +152,10 @@ const CGFloat kJSQMessagesToolbarContentViewHorizontalSpacingDefault = 8.0f;
|
||||
|
||||
- (void)setRightBarButtonItemWidth:(CGFloat)rightBarButtonItemWidth
|
||||
{
|
||||
self.rightBarButtonItem.frame = CGRectMake(0.0f,
|
||||
0.0f,
|
||||
rightBarButtonItemWidth,
|
||||
CGRectGetHeight(self.rightBarButtonContainerView.frame));
|
||||
self.rightBarButtonContainerViewWidthConstraint.constant = rightBarButtonItemWidth;
|
||||
[self setNeedsUpdateConstraints];
|
||||
}
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6250" systemVersion="14A389" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6245" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6244"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
@ -12,7 +11,7 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="LEq-G7-jGt" userLabel="Left button container">
|
||||
<rect key="frame" x="8" y="6" width="34" height="32"/>
|
||||
<rect key="frame" x="4" y="6" width="34" height="32"/>
|
||||
<color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="32" id="0sE-GV-joM"/>
|
||||
@ -20,7 +19,7 @@
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Myo-1S-Vg1" userLabel="Right button container">
|
||||
<rect key="frame" x="262" y="6" width="50" height="32"/>
|
||||
<rect key="frame" x="266" y="6" width="50" height="32"/>
|
||||
<color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="32" id="NaR-re-dJ4"/>
|
||||
@ -28,7 +27,7 @@
|
||||
</constraints>
|
||||
</view>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dm4-NT-mvr" customClass="JSQMessagesComposerTextView">
|
||||
<rect key="frame" x="50" y="7" width="204" height="30"/>
|
||||
<rect key="frame" x="42" y="7" width="220" height="30"/>
|
||||
<color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
@ -36,14 +35,14 @@
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Myo-1S-Vg1" firstAttribute="leading" secondItem="dm4-NT-mvr" secondAttribute="trailing" constant="8" id="7Ld-5r-Hp3"/>
|
||||
<constraint firstItem="Myo-1S-Vg1" firstAttribute="leading" secondItem="dm4-NT-mvr" secondAttribute="trailing" constant="4" id="7Ld-5r-Hp3"/>
|
||||
<constraint firstItem="dm4-NT-mvr" firstAttribute="top" secondItem="1" secondAttribute="top" constant="7" id="9Tz-Wq-xIf"/>
|
||||
<constraint firstAttribute="bottom" secondItem="dm4-NT-mvr" secondAttribute="bottom" constant="7" id="CCb-V7-yek"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Myo-1S-Vg1" secondAttribute="bottom" constant="6" id="EaS-Oq-Qp5"/>
|
||||
<constraint firstItem="LEq-G7-jGt" firstAttribute="leading" secondItem="1" secondAttribute="leading" constant="8" id="LAU-fo-GJJ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Myo-1S-Vg1" secondAttribute="trailing" constant="8" id="ds6-61-GNv"/>
|
||||
<constraint firstItem="LEq-G7-jGt" firstAttribute="leading" secondItem="1" secondAttribute="leading" constant="4" id="LAU-fo-GJJ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Myo-1S-Vg1" secondAttribute="trailing" constant="4" id="ds6-61-GNv"/>
|
||||
<constraint firstAttribute="bottom" secondItem="LEq-G7-jGt" secondAttribute="bottom" constant="6" id="oG2-YD-ZZI"/>
|
||||
<constraint firstItem="dm4-NT-mvr" firstAttribute="leading" secondItem="LEq-G7-jGt" secondAttribute="trailing" constant="8" id="owo-gB-gyR"/>
|
||||
<constraint firstItem="dm4-NT-mvr" firstAttribute="leading" secondItem="LEq-G7-jGt" secondAttribute="trailing" constant="4" id="owo-gB-gyR"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
@ -56,7 +55,7 @@
|
||||
<outlet property="rightHorizontalSpacingConstraint" destination="ds6-61-GNv" id="ZQh-8M-QFs"/>
|
||||
<outlet property="textView" destination="dm4-NT-mvr" id="PFw-HO-oT8"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="268" y="548"/>
|
||||
<point key="canvasLocation" x="174" y="567"/>
|
||||
</view>
|
||||
</objects>
|
||||
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
||||
|
||||
@ -10,4 +10,4 @@ SPEC CHECKSUMS:
|
||||
JSQSystemSoundPlayer: c98443b1cbb3b45db09d0d3d6c2355cf78294981
|
||||
OCMock: f6cb8c162ab9d5620dddf411282c7b2c0ee78854
|
||||
|
||||
COCOAPODS: 0.35.0
|
||||
COCOAPODS: 0.34.4
|
||||
|
||||
152
README.md
@ -2,9 +2,9 @@
|
||||
|
||||
[](http://travis-ci.org/jessesquires/JSQMessagesViewController) [][docsLink] [][mitLink]
|
||||
|
||||
![Screenshot0][img0] ![Screenshot1][img1]
|
||||
### Update: 6.0-beta6 is out! See [#476](https://github.com/jessesquires/JSQMessagesViewController/issues/476) for details.
|
||||
|
||||
![Screenshot2][img2] ![Screenshot3][img3]
|
||||
![Messages Screenshot 1][img1] ![Messages Screenshot 2][img2]
|
||||
|
||||
> More screenshots available at [CocoaControls](https://www.cocoacontrols.com/controls/jsqmessagesviewcontroller)
|
||||
|
||||
@ -22,7 +22,7 @@ See the [website](http://www.jessesquires.com/JSQMessagesViewController/) for th
|
||||
* iOS 7.0+
|
||||
* ARC
|
||||
|
||||
*Need support for iOS 6? [You shouldn't](http://www.macrumors.com/2014/12/09/ios-8-on-63-percent-of-ios-devices/). But, there's a branch for that!*
|
||||
*Need support for iOS 6? [You shouldn't](http://www.macrumors.com/2014/07/14/apple-ios-7-adoption-90-percent/). But, there's a branch for that!*
|
||||
````
|
||||
git checkout iOS6_support_stable
|
||||
````
|
||||
@ -31,21 +31,11 @@ git checkout iOS6_support_stable
|
||||
|
||||
## Installation
|
||||
|
||||
````ruby
|
||||
# For latest release in cocoapods
|
||||
pod 'JSQMessagesViewController'
|
||||
|
||||
# Feeling adventurous? Get the latest on develop
|
||||
pod 'JSQMessagesViewController', :git => 'https://github.com/jessesquires/JSQMessagesViewController.git', :branch => 'develop'
|
||||
|
||||
# For version 5.3.2
|
||||
pod 'JSQMessagesViewController', :git => 'https://github.com/jessesquires/JSQMessagesViewController', :branch => 'version_5.3.2_patch'
|
||||
|
||||
# For iOS 6 support
|
||||
pod 'JSMessagesViewController', :git => 'https://github.com/jessesquires/JSQMessagesViewController.git', :branch => 'iOS6_support_stable'
|
||||
````
|
||||
pod 'JSQMessagesViewController'
|
||||
````
|
||||
|
||||
Otherwise, drag the `JSQMessagesViewController/` folder to your project and install [`JSQSystemSoundPlayer`][playerLink].
|
||||
Otherwise, drag the `JSQMessagesViewController/` folder to your project. Install [`JSQSystemSoundPlayer`][playerLink] and add the `QuartzCore.framework`.
|
||||
|
||||
>**NOTE:**
|
||||
>
|
||||
@ -53,115 +43,35 @@ Otherwise, drag the `JSQMessagesViewController/` folder to your project and inst
|
||||
>
|
||||
>And this pod was formerly named `JSMessagesViewController`.
|
||||
|
||||
For iOS 6.0 support:
|
||||
````
|
||||
pod 'JSMessagesViewController', :git => 'https://github.com/jessesquires/JSQMessagesViewController.git', :branch => 'iOS6_support_stable'
|
||||
````
|
||||
|
||||
## Getting Started
|
||||
|
||||
````objective-c
|
||||
````
|
||||
#import <JSQMessagesViewController/JSQMessages.h> // import all the things
|
||||
````
|
||||
|
||||
>Read the [blog post](http://www.jessesquires.com/introducing-jsqmessagesvc-6-0/) about the 6.0 release!
|
||||
|
||||
* **Demo Project**
|
||||
* There's a sweet demo project: `JSQMessages.xcworkspace`.
|
||||
* **Demo project**
|
||||
* There's a fucking sweet demo project: `JSQMessages.xcworkspace`.
|
||||
* Run `pod install` first.
|
||||
|
||||
* **Message Model**
|
||||
* Your message model objects should conform to the `JSQMessageData` protocol.
|
||||
* However, you may use the provided `JSQMessage` class.
|
||||
|
||||
* **Media Attachment Model**
|
||||
* **Model**
|
||||
* Your model objects should conform to the `JSQMessageData` protocol.
|
||||
* Your media attachment model objects should conform to the `JSQMessageMediaData` protocol.
|
||||
* However, you may use the provided classes: `JSQPhotoMediaItem`, `JSQLocationMediaItem`, `JSQVideoMediaItem`.
|
||||
* Creating your own custom media items is easy! Simply follow the pattern used by the built-in media types.
|
||||
* Also see `JSQMessagesMediaViewBubbleImageMasker` for masking your custom media views as message bubbles.
|
||||
|
||||
* **Avatar Model**
|
||||
* Your avatar model objects should conform to the `JSQMessageAvatarImageDataSource` protocol.
|
||||
* However, you may use the provided `JSQMessagesAvatarImage` class.
|
||||
* Also see `JSQMessagesAvatarImageFactory` for easily generating custom avatars.
|
||||
|
||||
* **Message Bubble Model**
|
||||
* Your message bubble model objects should conform to the `JSQMessageBubbleImageDataSource` protocol.
|
||||
* However, you may use the provided `JSQMessagesBubbleImage` class.
|
||||
* Also see `JSQMessagesBubbleImageFactory` and `UIImage+JSQMessages.h` for easily generating custom bubbles.
|
||||
|
||||
* However, you may use the provided classes:
|
||||
* Model: `JSQTextMessage` and `JSQMediaMessage`
|
||||
* Media attachments: `JSQPhotoMediaItem`, `JSQLocationMediaItem`, `JSQVideoMediaItem`
|
||||
|
||||
* **View Controller**
|
||||
* Subclass `JSQMessagesViewController`.
|
||||
* Implement the required methods in the `JSQMessagesCollectionViewDataSource` protocol.
|
||||
* Implement the required methods in the `JSQMessagesCollectionViewDelegateFlowLayout` protocol.
|
||||
* Set your `senderId` and `senderDisplayName`. These properties correspond to the methods found in `JSQMessageData` and determine which messages are incoming or outgoing.
|
||||
|
||||
* **Customizing**
|
||||
* The demo project is well-commented. Please use this as a guide.
|
||||
|
||||
## Quick Tips
|
||||
|
||||
*Springy bubbles?*
|
||||
````objective-c
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
[super viewDidAppear:animated];
|
||||
self.collectionView.collectionViewLayout.springinessEnabled = YES;
|
||||
}
|
||||
````
|
||||
|
||||
*Remove avatars?*
|
||||
````objective-c
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
self.collectionView.collectionViewLayout.incomingAvatarViewSize = CGSizeZero;
|
||||
self.collectionView.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero;
|
||||
}
|
||||
|
||||
- (id<JSQMessageAvatarImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView avatarImageDataForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
````
|
||||
|
||||
*Customize your cells?*
|
||||
````objective-c
|
||||
- (UICollectionViewCell *)collectionView:(JSQMessagesCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
|
||||
|
||||
// Customize the shit out of this cell
|
||||
// See the docs for JSQMessagesCollectionViewCell
|
||||
|
||||
return cell;
|
||||
}
|
||||
````
|
||||
|
||||
*Customize your toolbar buttons?*
|
||||
````objective-c
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
// This button will call the `didPressAccessoryButton:` selector on your JSQMessagesViewController subclass
|
||||
self.inputToolbar.contentView.leftBarButtonItem = /* custom button or nil to remove */
|
||||
|
||||
// This button will call the `didPressSendButton:` selector on your JSQMessagesViewController subclass
|
||||
self.inputToolbar.contentView.rightBarButtonItem = /* custom button or nil to remove */
|
||||
|
||||
// Swap buttons, move send button to the LEFT side and the attachment button to the RIGHT
|
||||
// For RTL language support
|
||||
self.inputToolbar.contentView.leftBarButtonItem = [JSQMessagesToolbarButtonFactory defaultSendButtonItem];
|
||||
self.inputToolbar.contentView.rightBarButtonItem = [JSQMessagesToolbarButtonFactory defaultAccessoryButtonItem];
|
||||
|
||||
// The library will call the correct selector for each button, based on this value
|
||||
self.inputToolbar.sendButtonOnRight = NO;
|
||||
}
|
||||
````
|
||||
|
||||
## Questions & Help
|
||||
|
||||
There's [a label](https://github.com/jessesquires/JSQMessagesViewController/labels/questions%20&%20help) for that. Before asking a question, see if it has [already been answered](https://github.com/jessesquires/JSQMessagesViewController/issues?q=label%3A%22questions+%26+help%22+is%3Aclosed).
|
||||
|
||||
## Migrating from v5.x to v6.x
|
||||
|
||||
If you are upgrading from v5.x to v6.x, see the [6.0 release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/6.0.0) for details about API changes.
|
||||
* The demo project is well-commented. This should help you configure your view however you like.
|
||||
|
||||
## Documentation
|
||||
|
||||
@ -173,15 +83,15 @@ Please follow these sweet [contribution guidelines](https://github.com/jessesqui
|
||||
|
||||
## Donate
|
||||
|
||||
Support the development of this **free** *open-source* library!
|
||||
Support the development of this **free**, open-source library!
|
||||
|
||||
>*Donations made via [Square Cash](https://square.com/cash)*
|
||||
|
||||
><h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$5&body=Thanks for developing JSQMessagesViewController!">Send $5</a> <em>Just saying thanks. Here's a coffee!</em> :coffee:</h4>
|
||||
<h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$10&body=Thanks for developing JSQMessagesViewController!">Send $10</a> <em>This library is great. Lunch is on me!</em> :ramen:</h4>
|
||||
<h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$25&body=Thanks for developing JSQMessagesViewController!">Send $25</a> <em>This totally saved me time. Go get a nice dinner!</em> :fork_and_knife:</h4>
|
||||
<h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$50&body=Thanks for developing JSQMessagesViewController!">Send $50</a> <em>I love this library. I want new features!</em> :clap:</h4>
|
||||
<h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$100&body=Thanks for developing JSQMessagesViewController!">Send $100</a> <em>I really want to support this project!</em> :tada:</h4>
|
||||
><h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$5&body=Thanks for developing JSQMessagesViewController!">Send $5</a> <em>Just saying thanks. Here's a coffee!</em></h4>
|
||||
<h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$10&body=Thanks for developing JSQMessagesViewController!">Send $10</a> <em>This library is great. Lunch is on me!</em></h4>
|
||||
<h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$25&body=Thanks for developing JSQMessagesViewController!">Send $25</a> <em>This totally saved me time. Go get a nice dinner!</em></h4>
|
||||
<h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$50&body=Thanks for developing JSQMessagesViewController!">Send $50</a> <em>I love this library. I want new features!</em></h4>
|
||||
<h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$100&body=Thanks for developing JSQMessagesViewController!">Send $100</a> <em>I really want to support this project!</em></h4>
|
||||
>*You can also send donations via [PayPal](https://www.paypal.com) to jesse.squires.developer@gmail.com*
|
||||
|
||||
## Credits
|
||||
@ -224,8 +134,6 @@ Feel free to check out my work at [Hexed Bits](http://bit.ly/0x29A), or read [my
|
||||
* [AwesomeChat](https://github.com/relatedcode/AwesomeChat)
|
||||
* [ParseChat](https://github.com/relatedcode/ParseChat)
|
||||
* [Jib](http://jibapp.com)
|
||||
* [Onvolo](https://itunes.apple.com/us/app/onvolo/id869332351)
|
||||
* [EVCloudKitDao](https://github.com/evermeer/EVCloudKitDao)
|
||||
* *Your app here*
|
||||
|
||||
## License
|
||||
@ -240,7 +148,5 @@ Feel free to check out my work at [Hexed Bits](http://bit.ly/0x29A), or read [my
|
||||
[mitLink]:http://opensource.org/licenses/MIT
|
||||
[playerLink]:https://github.com/jessesquires/JSQSystemSoundPlayer
|
||||
|
||||
[img0]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot0.png
|
||||
[img1]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot1.png
|
||||
[img2]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot2.png
|
||||
[img3]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot3.png
|
||||
[img1]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot0.png
|
||||
[img2]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot1.png
|
||||
|
||||
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 27 KiB |