Compare commits

..

No commits in common. "master" and "develop-scrollviewperf" have entirely different histories.

84 changed files with 893 additions and 2517 deletions

View File

@ -11,7 +11,7 @@
77CC17A895E6E12BC9CB549A /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 97E6750B77E8A7042BA0754B /* libPods.a */; }; 77CC17A895E6E12BC9CB549A /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 97E6750B77E8A7042BA0754B /* libPods.a */; };
88078A9D19D8FEB5005B4595 /* JSQMessagesMediaPlaceholderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 88078A9C19D8FEB5005B4595 /* JSQMessagesMediaPlaceholderView.m */; }; 88078A9D19D8FEB5005B4595 /* JSQMessagesMediaPlaceholderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 88078A9C19D8FEB5005B4595 /* JSQMessagesMediaPlaceholderView.m */; };
88324C3419F6301C00BC732D /* JSQMessagesMediaViewBubbleImageMaskerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88324C3319F6301C00BC732D /* JSQMessagesMediaViewBubbleImageMaskerTests.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 */; }; 88445B3119E0AE3F0014F889 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88445B3019E0AE3F0014F889 /* UIKit.framework */; };
88445B3319E0AE450014F889 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88445B3219E0AE450014F889 /* Foundation.framework */; }; 88445B3319E0AE450014F889 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88445B3219E0AE450014F889 /* Foundation.framework */; };
88445B3519E0AE4A0014F889 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88445B3419E0AE4A0014F889 /* CoreGraphics.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 */; }; 88A25FC119D8E01A00924534 /* JSQMessagesCollectionViewFlowLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F7119D8E01A00924534 /* JSQMessagesCollectionViewFlowLayout.m */; };
88A25FC219D8E01A00924534 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F7319D8E01A00924534 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m */; }; 88A25FC219D8E01A00924534 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F7319D8E01A00924534 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m */; };
88A25FC319D8E01A00924534 /* JSQMessagesCollectionViewLayoutAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F7519D8E01A00924534 /* JSQMessagesCollectionViewLayoutAttributes.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 */; }; 88A25FC519D8E01A00924534 /* JSQMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F7A19D8E01A00924534 /* JSQMessage.m */; };
88A25FC619D8E01A00924534 /* JSQMessagesAvatarImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8019D8E01A00924534 /* JSQMessagesAvatarImage.m */; }; 88A25FC619D8E01A00924534 /* JSQMessagesAvatarImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8019D8E01A00924534 /* JSQMessagesAvatarImage.m */; };
88A25FC719D8E01A00924534 /* JSQMessagesBubbleImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8219D8E01A00924534 /* JSQMessagesBubbleImage.m */; }; 88A25FC719D8E01A00924534 /* JSQMessagesBubbleImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8219D8E01A00924534 /* JSQMessagesBubbleImage.m */; };
88A25FC819D8E01A00924534 /* JSQPhotoMediaItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8619D8E01A00924534 /* JSQPhotoMediaItem.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 */; }; 88A25FCA19D8E01A00924534 /* JSQMessagesCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8B19D8E01A00924534 /* JSQMessagesCollectionView.m */; };
88A25FCB19D8E01A00924534 /* JSQMessagesCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8D19D8E01A00924534 /* JSQMessagesCollectionViewCell.m */; }; 88A25FCB19D8E01A00924534 /* JSQMessagesCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8D19D8E01A00924534 /* JSQMessagesCollectionViewCell.m */; };
88A25FCC19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8F19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.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 */; }; 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 */; }; 88A25FD019D8E01A00924534 /* JSQMessagesComposerTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F9519D8E01A00924534 /* JSQMessagesComposerTextView.m */; };
88A25FD119D8E01A00924534 /* JSQMessagesInputToolbar.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F9719D8E01A00924534 /* JSQMessagesInputToolbar.m */; }; 88A25FD119D8E01A00924534 /* JSQMessagesInputToolbar.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F9719D8E01A00924534 /* JSQMessagesInputToolbar.m */; };
88A25FD219D8E01A00924534 /* JSQMessagesLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F9919D8E01A00924534 /* JSQMessagesLabel.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 */; }; 88A2600A19D8E18400924534 /* JSQMessagesToolbarButtonFactoryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FEE19D8E18400924534 /* JSQMessagesToolbarButtonFactoryTests.m */; };
88A2600B19D8E18400924534 /* JSQMessagesCollectionViewFlowLayoutTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF019D8E18400924534 /* JSQMessagesCollectionViewFlowLayoutTests.m */; }; 88A2600B19D8E18400924534 /* JSQMessagesCollectionViewFlowLayoutTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF019D8E18400924534 /* JSQMessagesCollectionViewFlowLayoutTests.m */; };
88A2600C19D8E18400924534 /* JSQMessagesCollectionViewLayoutAttributesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF119D8E18400924534 /* JSQMessagesCollectionViewLayoutAttributesTests.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 */; }; 88A2600E19D8E18400924534 /* JSQMessagesAvatarImageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF419D8E18400924534 /* JSQMessagesAvatarImageTests.m */; };
88A2600F19D8E18400924534 /* JSQMessagesBubbleImageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF519D8E18400924534 /* JSQMessagesBubbleImageTests.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 */; }; 88A2601219D8E18400924534 /* JSQMessagesCollectionViewCellTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF919D8E18400924534 /* JSQMessagesCollectionViewCellTests.m */; };
88A2601319D8E18400924534 /* JSQMessagesCollectionViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FFA19D8E18400924534 /* JSQMessagesCollectionViewTests.m */; }; 88A2601319D8E18400924534 /* JSQMessagesCollectionViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FFA19D8E18400924534 /* JSQMessagesCollectionViewTests.m */; };
88A2601419D8E18400924534 /* JSQMessagesComposerTextViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FFB19D8E18400924534 /* JSQMessagesComposerTextViewTests.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 */; }; 88A2601919D8E18400924534 /* JSQMessagesTypingIndicatorFooterViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A2600019D8E18400924534 /* JSQMessagesTypingIndicatorFooterViewTests.m */; };
88A2601B19D8E45600924534 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 88A2601A19D8E45600924534 /* Info.plist */; }; 88A2601B19D8E45600924534 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 88A2601A19D8E45600924534 /* Info.plist */; };
88A901B619F618B100F99777 /* JSQMediaItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A901B519F618B100F99777 /* JSQMediaItem.m */; }; 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 */; }; 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 */; }; 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 */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -140,8 +124,6 @@
88078A9B19D8FEB5005B4595 /* JSQMessagesMediaPlaceholderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesMediaPlaceholderView.h; sourceTree = "<group>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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; }; 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>"; }; 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 */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -375,7 +338,6 @@
88445B3A19E0C0B10014F889 /* XCTest.framework */, 88445B3A19E0C0B10014F889 /* XCTest.framework */,
); );
name = Frameworks; name = Frameworks;
path = ../..;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
8841B88219F4983C00EA16B6 /* Strings */ = { 8841B88219F4983C00EA16B6 /* Strings */ = {
@ -391,6 +353,7 @@
children = ( children = (
886C33FE19F45E30006B4997 /* JSQMessagesViewController.podspec */, 886C33FE19F45E30006B4997 /* JSQMessagesViewController.podspec */,
88A25F3E19D8E01A00924534 /* JSQMessagesViewController */, 88A25F3E19D8E01A00924534 /* JSQMessagesViewController */,
636A8663AEEE5C37B65C515D /* Frameworks */,
88A25F2B19D8DF2500924534 /* JSQMessagesDemo */, 88A25F2B19D8DF2500924534 /* JSQMessagesDemo */,
88A25F1E19D8DEC500924534 /* JSQMessagesTests */, 88A25F1E19D8DEC500924534 /* JSQMessagesTests */,
2BBEF3CD91C31A49E5FF9E3C /* Pods */, 2BBEF3CD91C31A49E5FF9E3C /* Pods */,
@ -470,8 +433,6 @@
88A25F3F19D8E01A00924534 /* Assets */ = { 88A25F3F19D8E01A00924534 /* Assets */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FCA52AFB1A2B9BAD00CCADFA /* InfoError */,
FCA52AF01A2B6F8A00CCADFA /* Calls */,
8841B88219F4983C00EA16B6 /* Strings */, 8841B88219F4983C00EA16B6 /* Strings */,
8861666C19F492B70025B958 /* JSQMessagesAssets.bundle */, 8861666C19F492B70025B958 /* JSQMessagesAssets.bundle */,
); );
@ -546,6 +507,8 @@
88445B3F19E1B4470014F889 /* JSQLocationMediaItem.m */, 88445B3F19E1B4470014F889 /* JSQLocationMediaItem.m */,
88A901B419F618B100F99777 /* JSQMediaItem.h */, 88A901B419F618B100F99777 /* JSQMediaItem.h */,
88A901B519F618B100F99777 /* JSQMediaItem.m */, 88A901B519F618B100F99777 /* JSQMediaItem.m */,
88A25F7719D8E01A00924534 /* JSQMediaMessage.h */,
88A25F7819D8E01A00924534 /* JSQMediaMessage.m */,
88A25F7919D8E01A00924534 /* JSQMessage.h */, 88A25F7919D8E01A00924534 /* JSQMessage.h */,
88A25F7A19D8E01A00924534 /* JSQMessage.m */, 88A25F7A19D8E01A00924534 /* JSQMessage.m */,
88A25F7B19D8E01A00924534 /* JSQMessageAvatarImageDataSource.h */, 88A25F7B19D8E01A00924534 /* JSQMessageAvatarImageDataSource.h */,
@ -560,16 +523,10 @@
88A25F8419D8E01A00924534 /* JSQMessagesCollectionViewDelegateFlowLayout.h */, 88A25F8419D8E01A00924534 /* JSQMessagesCollectionViewDelegateFlowLayout.h */,
88A25F8519D8E01A00924534 /* JSQPhotoMediaItem.h */, 88A25F8519D8E01A00924534 /* JSQPhotoMediaItem.h */,
88A25F8619D8E01A00924534 /* JSQPhotoMediaItem.m */, 88A25F8619D8E01A00924534 /* JSQPhotoMediaItem.m */,
88A25F8719D8E01A00924534 /* JSQTextMessage.h */,
88A25F8819D8E01A00924534 /* JSQTextMessage.m */,
886C33FB19F4371E006B4997 /* JSQVideoMediaItem.h */, 886C33FB19F4371E006B4997 /* JSQVideoMediaItem.h */,
886C33FC19F4371E006B4997 /* JSQVideoMediaItem.m */, 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; path = Model;
sourceTree = "<group>"; sourceTree = "<group>";
@ -577,19 +534,16 @@
88A25F8919D8E01A00924534 /* Views */ = { 88A25F8919D8E01A00924534 /* Views */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
636A8663AEEE5C37B65C515D /* Frameworks */,
883C11761A09FB100092A16D /* JSQMessagesCellTextView.h */,
883C11771A09FB100092A16D /* JSQMessagesCellTextView.m */,
88A25F8A19D8E01A00924534 /* JSQMessagesCollectionView.h */, 88A25F8A19D8E01A00924534 /* JSQMessagesCollectionView.h */,
88A25F8B19D8E01A00924534 /* JSQMessagesCollectionView.m */, 88A25F8B19D8E01A00924534 /* JSQMessagesCollectionView.m */,
88A25F8C19D8E01A00924534 /* JSQMessagesCollectionViewCell.h */, 88A25F8C19D8E01A00924534 /* JSQMessagesCollectionViewCell.h */,
88A25F8D19D8E01A00924534 /* JSQMessagesCollectionViewCell.m */, 88A25F8D19D8E01A00924534 /* JSQMessagesCollectionViewCell.m */,
88A25F8E19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.h */, 88A25F8E19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.h */,
88A25F8F19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.m */, 88A25F8F19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.m */,
FC15B7AE1A1F6AC800F59801 /* JSQMessagesCollectionViewCellIncoming.xib */, 88A25F9019D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.xib */,
88A25F9119D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.h */, 88A25F9119D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.h */,
88A25F9219D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.m */, 88A25F9219D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.m */,
FC15B7AF1A1F6AC800F59801 /* JSQMessagesCollectionViewCellOutgoing.xib */, 88A25F9319D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.xib */,
88A25F9419D8E01A00924534 /* JSQMessagesComposerTextView.h */, 88A25F9419D8E01A00924534 /* JSQMessagesComposerTextView.h */,
88A25F9519D8E01A00924534 /* JSQMessagesComposerTextView.m */, 88A25F9519D8E01A00924534 /* JSQMessagesComposerTextView.m */,
88A25F9619D8E01A00924534 /* JSQMessagesInputToolbar.h */, 88A25F9619D8E01A00924534 /* JSQMessagesInputToolbar.h */,
@ -607,12 +561,6 @@
88A25FA019D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.h */, 88A25FA019D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.h */,
88A25FA119D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.m */, 88A25FA119D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.m */,
88A25FA219D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.xib */, 88A25FA219D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.xib */,
FC4FA03B1A1E81AF00DA100A /* JSQCallCollectionViewCell.h */,
FC4FA03C1A1E81AF00DA100A /* JSQCallCollectionViewCell.m */,
FC15B7A81A1E880900F59801 /* JSQCallCollectionViewCell.xib */,
FCFA5E1A1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.h */,
FCFA5E1B1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.m */,
FCFA5E1C1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.xib */,
); );
path = Views; path = Views;
sourceTree = "<group>"; sourceTree = "<group>";
@ -661,13 +609,11 @@
88A25FF219D8E18400924534 /* ModelTests */ = { 88A25FF219D8E18400924534 /* ModelTests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
88C00A4D1A44D4C600B004B3 /* JSQLocationMediaItemTests.m */, 88A25FF319D8E18400924534 /* JSQMediaMessageTests.m */,
88A25FF319D8E18400924534 /* JSQMessageMediaTests.m */,
88A25FF419D8E18400924534 /* JSQMessagesAvatarImageTests.m */, 88A25FF419D8E18400924534 /* JSQMessagesAvatarImageTests.m */,
88A25FF519D8E18400924534 /* JSQMessagesBubbleImageTests.m */, 88A25FF519D8E18400924534 /* JSQMessagesBubbleImageTests.m */,
88A25FF619D8E18400924534 /* JSQMessageTextTests.m */, 88A25FF619D8E18400924534 /* JSQMessageTests.m */,
88C00A4F1A44D4D800B004B3 /* JSQPhotoMediaItemTests.m */, 88A25FF719D8E18400924534 /* JSQTextMessageTests.m */,
88C00A511A44D4E500B004B3 /* JSQVideoMediaItemTests.m */,
); );
path = ModelTests; path = ModelTests;
sourceTree = "<group>"; sourceTree = "<group>";
@ -687,27 +633,6 @@
path = ViewTests; path = ViewTests;
sourceTree = "<group>"; 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 */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
@ -805,26 +730,17 @@
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
88E4D7131A0DBD6B000CC061 /* JSQMessages.strings in Resources */,
886C33FF19F45E30006B4997 /* JSQMessagesViewController.podspec in Resources */, 886C33FF19F45E30006B4997 /* JSQMessagesViewController.podspec in Resources */,
8861666D19F492B70025B958 /* JSQMessagesAssets.bundle 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 */, 88A25FD619D8E01A00924534 /* JSQMessagesToolbarContentView.xib in Resources */,
FCA52AF71A2B6FAE00CCADFA /* call_incoming@2x.png in Resources */,
88A25F3A19D8DF2500924534 /* Images.xcassets in Resources */, 88A25F3A19D8DF2500924534 /* Images.xcassets in Resources */,
88A25FBC19D8E01A00924534 /* JSQMessagesViewController.xib 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 */, 88A25FD819D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.xib in Resources */,
FCFA5E1E1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.xib in Resources */,
88A25F3919D8DF2500924534 /* Main.storyboard in Resources */, 88A25F3919D8DF2500924534 /* Main.storyboard in Resources */,
FC15B7B01A1F6AC800F59801 /* JSQMessagesCollectionViewCellIncoming.xib in Resources */,
88A25FD419D8E01A00924534 /* JSQMessagesLoadEarlierHeaderView.xib in Resources */, 88A25FD419D8E01A00924534 /* JSQMessagesLoadEarlierHeaderView.xib in Resources */,
FC15B7A91A1E880900F59801 /* JSQCallCollectionViewCell.xib in Resources */,
FCA52AF61A2B6FAE00CCADFA /* call_failed@2x.png in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -912,9 +828,7 @@
88A25FCB19D8E01A00924534 /* JSQMessagesCollectionViewCell.m in Sources */, 88A25FCB19D8E01A00924534 /* JSQMessagesCollectionViewCell.m in Sources */,
88A25FBB19D8E01A00924534 /* JSQMessagesViewController.m in Sources */, 88A25FBB19D8E01A00924534 /* JSQMessagesViewController.m in Sources */,
8885734D19DE55D000E89D20 /* NSUserDefaults+DemoSettings.m in Sources */, 8885734D19DE55D000E89D20 /* NSUserDefaults+DemoSettings.m in Sources */,
883C11781A09FB100092A16D /* JSQMessagesCellTextView.m in Sources */,
88A25FB919D8E01A00924534 /* UIView+JSQMessages.m in Sources */, 88A25FB919D8E01A00924534 /* UIView+JSQMessages.m in Sources */,
FCFA5E131A29FC1000C8E32E /* JSQDisplayedMessage.m in Sources */,
88A25FCA19D8E01A00924534 /* JSQMessagesCollectionView.m in Sources */, 88A25FCA19D8E01A00924534 /* JSQMessagesCollectionView.m in Sources */,
88A25FD219D8E01A00924534 /* JSQMessagesLabel.m in Sources */, 88A25FD219D8E01A00924534 /* JSQMessagesLabel.m in Sources */,
88445B4019E1B4470014F889 /* JSQLocationMediaItem.m in Sources */, 88445B4019E1B4470014F889 /* JSQLocationMediaItem.m in Sources */,
@ -922,23 +836,19 @@
88A25FD519D8E01A00924534 /* JSQMessagesToolbarContentView.m in Sources */, 88A25FD519D8E01A00924534 /* JSQMessagesToolbarContentView.m in Sources */,
88A25FC119D8E01A00924534 /* JSQMessagesCollectionViewFlowLayout.m in Sources */, 88A25FC119D8E01A00924534 /* JSQMessagesCollectionViewFlowLayout.m in Sources */,
8885734A19DE540400E89D20 /* DemoSettingsViewController.m in Sources */, 8885734A19DE540400E89D20 /* DemoSettingsViewController.m in Sources */,
FC4FA03A1A1E1BD100DA100A /* JSQCall.m in Sources */,
88A25FC719D8E01A00924534 /* JSQMessagesBubbleImage.m in Sources */, 88A25FC719D8E01A00924534 /* JSQMessagesBubbleImage.m in Sources */,
88A25FC519D8E01A00924534 /* JSQMessage.m in Sources */, 88A25FC519D8E01A00924534 /* JSQMessage.m in Sources */,
88A25FD719D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.m in Sources */, 88A25FD719D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.m in Sources */,
88A25FD319D8E01A00924534 /* JSQMessagesLoadEarlierHeaderView.m in Sources */, 88A25FD319D8E01A00924534 /* JSQMessagesLoadEarlierHeaderView.m in Sources */,
FC4FA03D1A1E81AF00DA100A /* JSQCallCollectionViewCell.m in Sources */,
88A25FC819D8E01A00924534 /* JSQPhotoMediaItem.m in Sources */, 88A25FC819D8E01A00924534 /* JSQPhotoMediaItem.m in Sources */,
88C4583019F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.m in Sources */, 88C4583019F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.m in Sources */,
88A25FB819D8E01A00924534 /* UIImage+JSQMessages.m in Sources */, 88A25FB819D8E01A00924534 /* UIImage+JSQMessages.m in Sources */,
88A25FBF19D8E01A00924534 /* JSQMessagesTimestampFormatter.m in Sources */, 88A25FBF19D8E01A00924534 /* JSQMessagesTimestampFormatter.m in Sources */,
88A25FE019D8E0C400924534 /* DemoModelData.m in Sources */, 88A25FE019D8E0C400924534 /* DemoModelData.m in Sources */,
FCFA5E1D1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.m in Sources */,
88A25F3C19D8DF2500924534 /* main.m in Sources */, 88A25F3C19D8DF2500924534 /* main.m in Sources */,
88A25F3719D8DF2500924534 /* AppDelegate.m in Sources */, 88A25F3719D8DF2500924534 /* AppDelegate.m in Sources */,
886FFD2E19E9A65D00EB8485 /* UIDevice+JSQMessages.m in Sources */, 886FFD2E19E9A65D00EB8485 /* UIDevice+JSQMessages.m in Sources */,
88A25FB619D8E01A00924534 /* NSString+JSQMessages.m in Sources */, 88A25FB619D8E01A00924534 /* NSString+JSQMessages.m in Sources */,
FCFA5E191A2A044500C8E32E /* JSQErrorMessage.m in Sources */,
88A901B619F618B100F99777 /* JSQMediaItem.m in Sources */, 88A901B619F618B100F99777 /* JSQMediaItem.m in Sources */,
88A25FCC19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.m in Sources */, 88A25FCC19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.m in Sources */,
88A25FBE19D8E01A00924534 /* JSQMessagesBubbleImageFactory.m in Sources */, 88A25FBE19D8E01A00924534 /* JSQMessagesBubbleImageFactory.m in Sources */,
@ -946,8 +856,9 @@
88A25FB719D8E01A00924534 /* UIColor+JSQMessages.m in Sources */, 88A25FB719D8E01A00924534 /* UIColor+JSQMessages.m in Sources */,
886C33FD19F4371E006B4997 /* JSQVideoMediaItem.m in Sources */, 886C33FD19F4371E006B4997 /* JSQVideoMediaItem.m in Sources */,
88A25FBA19D8E01A00924534 /* JSQMessagesKeyboardController.m in Sources */, 88A25FBA19D8E01A00924534 /* JSQMessagesKeyboardController.m in Sources */,
FCFA5E161A29FE3B00C8E32E /* JSQInfoMessage.m in Sources */,
88A25FC019D8E01A00924534 /* JSQMessagesToolbarButtonFactory.m in Sources */, 88A25FC019D8E01A00924534 /* JSQMessagesToolbarButtonFactory.m in Sources */,
88A25FC919D8E01A00924534 /* JSQTextMessage.m in Sources */,
88A25FC419D8E01A00924534 /* JSQMediaMessage.m in Sources */,
88A25FC219D8E01A00924534 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m in Sources */, 88A25FC219D8E01A00924534 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m in Sources */,
88A25FE119D8E0C400924534 /* TableViewController.m in Sources */, 88A25FE119D8E0C400924534 /* TableViewController.m in Sources */,
88A25FBD19D8E01A00924534 /* JSQMessagesAvatarImageFactory.m in Sources */, 88A25FBD19D8E01A00924534 /* JSQMessagesAvatarImageFactory.m in Sources */,
@ -963,14 +874,13 @@
files = ( files = (
88A2600219D8E18400924534 /* JSQMessagesUIColorTests.m in Sources */, 88A2600219D8E18400924534 /* JSQMessagesUIColorTests.m in Sources */,
88A2601819D8E18400924534 /* JSQMessagesToolbarContentViewTests.m in Sources */, 88A2601819D8E18400924534 /* JSQMessagesToolbarContentViewTests.m in Sources */,
88C00A521A44D4E500B004B3 /* JSQVideoMediaItemTests.m in Sources */,
88A2601519D8E18400924534 /* JSQMessagesInputToolbarTests.m in Sources */, 88A2601519D8E18400924534 /* JSQMessagesInputToolbarTests.m in Sources */,
88A2601719D8E18400924534 /* JSQMessagesLoadEarlierHeaderViewTests.m in Sources */, 88A2601719D8E18400924534 /* JSQMessagesLoadEarlierHeaderViewTests.m in Sources */,
88A2601219D8E18400924534 /* JSQMessagesCollectionViewCellTests.m in Sources */, 88A2601219D8E18400924534 /* JSQMessagesCollectionViewCellTests.m in Sources */,
88A2601619D8E18400924534 /* JSQMessagesLabelTests.m in Sources */, 88A2601619D8E18400924534 /* JSQMessagesLabelTests.m in Sources */,
88A2600B19D8E18400924534 /* JSQMessagesCollectionViewFlowLayoutTests.m in Sources */, 88A2600B19D8E18400924534 /* JSQMessagesCollectionViewFlowLayoutTests.m in Sources */,
88A2601019D8E18400924534 /* JSQMessageTextTests.m in Sources */, 88A2601019D8E18400924534 /* JSQMessageTests.m in Sources */,
88A2600D19D8E18400924534 /* JSQMessageMediaTests.m in Sources */, 88A2600D19D8E18400924534 /* JSQMediaMessageTests.m in Sources */,
88A2600719D8E18400924534 /* JSQMessagesAvatarImageFactoryTests.m in Sources */, 88A2600719D8E18400924534 /* JSQMessagesAvatarImageFactoryTests.m in Sources */,
88A2600419D8E18400924534 /* JSQMessagesUIViewTests.m in Sources */, 88A2600419D8E18400924534 /* JSQMessagesUIViewTests.m in Sources */,
88A2600F19D8E18400924534 /* JSQMessagesBubbleImageTests.m in Sources */, 88A2600F19D8E18400924534 /* JSQMessagesBubbleImageTests.m in Sources */,
@ -979,12 +889,11 @@
88A2601419D8E18400924534 /* JSQMessagesComposerTextViewTests.m in Sources */, 88A2601419D8E18400924534 /* JSQMessagesComposerTextViewTests.m in Sources */,
88A2601319D8E18400924534 /* JSQMessagesCollectionViewTests.m in Sources */, 88A2601319D8E18400924534 /* JSQMessagesCollectionViewTests.m in Sources */,
88A2600119D8E18400924534 /* JSQMessagesNSStringTests.m in Sources */, 88A2600119D8E18400924534 /* JSQMessagesNSStringTests.m in Sources */,
88A2601119D8E18400924534 /* JSQTextMessageTests.m in Sources */,
88A2600A19D8E18400924534 /* JSQMessagesToolbarButtonFactoryTests.m in Sources */, 88A2600A19D8E18400924534 /* JSQMessagesToolbarButtonFactoryTests.m in Sources */,
88C00A501A44D4D800B004B3 /* JSQPhotoMediaItemTests.m in Sources */,
88324C3419F6301C00BC732D /* JSQMessagesMediaViewBubbleImageMaskerTests.m in Sources */, 88324C3419F6301C00BC732D /* JSQMessagesMediaViewBubbleImageMaskerTests.m in Sources */,
88A2601919D8E18400924534 /* JSQMessagesTypingIndicatorFooterViewTests.m in Sources */, 88A2601919D8E18400924534 /* JSQMessagesTypingIndicatorFooterViewTests.m in Sources */,
88A2600319D8E18400924534 /* JSQMessagesUIImageTests.m in Sources */, 88A2600319D8E18400924534 /* JSQMessagesUIImageTests.m in Sources */,
88C00A4E1A44D4C600B004B3 /* JSQLocationMediaItemTests.m in Sources */,
88A2600C19D8E18400924534 /* JSQMessagesCollectionViewLayoutAttributesTests.m in Sources */, 88A2600C19D8E18400924534 /* JSQMessagesCollectionViewLayoutAttributesTests.m in Sources */,
88A2600619D8E18400924534 /* JSQMessagesViewControllerTests.m in Sources */, 88A2600619D8E18400924534 /* JSQMessagesViewControllerTests.m in Sources */,
88A2600519D8E18400924534 /* JSQMessagesKeyboardControllerTests.m in Sources */, 88A2600519D8E18400924534 /* JSQMessagesKeyboardControllerTests.m in Sources */,
@ -1121,14 +1030,11 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; 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"; INFOPLIST_FILE = "$(SRCROOT)/JSQMessagesDemo/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 7.0; IPHONEOS_DEPLOYMENT_TARGET = 7.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = "$(inherited)"; OTHER_LDFLAGS = "$(inherited)";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
}; };
name = Debug; name = Debug;
}; };
@ -1139,14 +1045,11 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; 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"; INFOPLIST_FILE = "$(SRCROOT)/JSQMessagesDemo/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 7.0; IPHONEOS_DEPLOYMENT_TARGET = 7.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = "$(inherited)"; OTHER_LDFLAGS = "$(inherited)";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
}; };
name = Release; name = Release;
}; };

View File

@ -45,4 +45,6 @@
- (void)closePressed:(UIBarButtonItem *)sender; - (void)closePressed:(UIBarButtonItem *)sender;
// TODO: example of async avatar loading
@end @end

View File

@ -18,12 +18,6 @@
#import "DemoMessagesViewController.h" #import "DemoMessagesViewController.h"
#import "JSQCallCollectionViewCell.h"
#import "JSQCall.h"
#import "JSQDisplayedMessageCollectionViewCell.h"
#import "JSQErrorMessage.h"
#import "JSQInfoMessage.h"
@implementation DemoMessagesViewController @implementation DemoMessagesViewController
@ -49,7 +43,7 @@
*/ */
self.senderId = kJSQDemoAvatarIdSquires; self.senderId = kJSQDemoAvatarIdSquires;
self.senderDisplayName = kJSQDemoAvatarDisplayNameSquires; self.senderDisplayName = kJSQDemoAvatarDisplayNameSquires;
/** /**
* Load up our fake data for the demo * Load up our fake data for the demo
@ -74,13 +68,6 @@
style:UIBarButtonItemStyleBordered style:UIBarButtonItemStyleBordered
target:self target:self
action:@selector(receiveMessagePressed:)]; 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 - (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 #pragma mark - Actions
- (void)receiveMessagePressed:(UIBarButtonItem *)sender - (void)receiveMessagePressed:(UIBarButtonItem *)sender
@ -146,9 +123,9 @@
JSQMessage *copyMessage = [[self.demoData.messages lastObject] copy]; JSQMessage *copyMessage = [[self.demoData.messages lastObject] copy];
if (!copyMessage) { if (!copyMessage) {
copyMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdJobs copyMessage = [JSQTextMessage messageWithSenderId:kJSQDemoAvatarIdJobs
displayName:kJSQDemoAvatarDisplayNameJobs displayName:kJSQDemoAvatarDisplayNameJobs
text:@"First received!"]; text:@"First received!"];
} }
/** /**
@ -164,7 +141,7 @@
id<JSQMessageMediaData> newMediaData = nil; id<JSQMessageMediaData> newMediaData = nil;
id newMediaAttachmentCopy = nil; id newMediaAttachmentCopy = nil;
if ([copyMessage isKindOfClass:[JSQMessage class]]) { if ([copyMessage isKindOfClass:[JSQMediaMessage class]]) {
/** /**
* Last message was a media message * Last message was a media message
*/ */
@ -212,17 +189,17 @@
NSLog(@"%s error: unrecognized media item", __PRETTY_FUNCTION__); NSLog(@"%s error: unrecognized media item", __PRETTY_FUNCTION__);
} }
newMessage = [JSQMessage messageWithSenderId:randomUserId newMessage = [JSQMediaMessage messageWithSenderId:randomUserId
displayName:self.demoData.users[randomUserId] displayName:self.demoData.users[randomUserId]
media:newMediaData]; media:newMediaData];
} }
else { else {
/** /**
* Last message was a text message * Last message was a text message
*/ */
newMessage = [JSQMessage messageWithSenderId:randomUserId newMessage = [JSQTextMessage messageWithSenderId:randomUserId
displayName:self.demoData.users[randomUserId] displayName:self.demoData.users[randomUserId]
text:copyMessage.text]; text:copyMessage.text];
} }
/** /**
@ -234,10 +211,10 @@
*/ */
[JSQSystemSoundPlayer jsq_playMessageReceivedSound]; [JSQSystemSoundPlayer jsq_playMessageReceivedSound];
[self.demoData.messages addObject:newMessage]; [self.demoData.messages addObject:newMessage];
[self finishReceivingMessageAnimated:YES]; [self finishReceivingMessage];
if (newMessage.isMediaMessage) { if ([newMessage isKindOfClass:[JSQMediaMessage class]]) {
/** /**
* Simulate "downloading" media * Simulate "downloading" media
*/ */
@ -299,14 +276,13 @@
*/ */
[JSQSystemSoundPlayer jsq_playMessageSentSound]; [JSQSystemSoundPlayer jsq_playMessageSentSound];
JSQMessage *message = [[JSQMessage alloc] initWithSenderId:senderId JSQTextMessage *message = [[JSQTextMessage alloc] initWithSenderId:senderId
senderDisplayName:senderDisplayName senderDisplayName:senderDisplayName
date:date date:date
text:text]; text:text];
[self.demoData.messages addObject:message]; [self.demoData.messages addObject:message];
[self finishSendingMessage];
[self finishSendingMessageAnimated:YES];
} }
- (void)didPressAccessoryButton:(UIButton *)sender - (void)didPressAccessoryButton:(UIButton *)sender
@ -347,8 +323,7 @@
} }
[JSQSystemSoundPlayer jsq_playMessageSentSound]; [JSQSystemSoundPlayer jsq_playMessageSentSound];
[self finishSendingMessage];
[self finishSendingMessageAnimated:YES];
} }
@ -374,7 +349,7 @@
if ([message.senderId isEqualToString:self.senderId]) { if ([message.senderId isEqualToString:self.senderId]) {
return self.demoData.outgoingBubbleImageData; return self.demoData.outgoingBubbleImageData;
} }
return self.demoData.incomingBubbleImageData; return self.demoData.incomingBubbleImageData;
} }
@ -402,8 +377,6 @@
*/ */
JSQMessage *message = [self.demoData.messages objectAtIndex:indexPath.item]; 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 ([message.senderId isEqualToString:self.senderId]) {
if (![NSUserDefaults outgoingAvatarSetting]) { if (![NSUserDefaults outgoingAvatarSetting]) {
return nil; return nil;
@ -414,7 +387,8 @@
return nil; return nil;
} }
} }
return [self.demoData.avatars objectForKey:message.senderId]; return [self.demoData.avatars objectForKey:message.senderId];
} }
@ -475,34 +449,38 @@
/** /**
* Override point for customizing cells * 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]; JSQMessage *msg = [self.demoData.messages objectAtIndex:indexPath.item];
if ([msg isKindOfClass:[JSQMessage class]]) if ([msg isKindOfClass:[JSQTextMessage class]]) {
{
JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath]; if ([msg.senderId isEqualToString:self.senderId]) {
if (!msg.isMediaMessage) { cell.textView.textColor = [UIColor blackColor];
if ([msg.senderId isEqualToString:self.senderId]) { }
cell.textView.textColor = [UIColor blackColor]; else {
} cell.textView.textColor = [UIColor whiteColor];
else {
cell.textView.textColor = [UIColor whiteColor];
}
cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor,
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };
} }
return cell; cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor,
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };
} 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;
} }
return cell;
} }
@ -524,9 +502,9 @@
* *
* Show a timestamp for every 3rd message * Show a timestamp for every 3rd message
*/ */
// if (indexPath.item % 3 == 0) { if (indexPath.item % 3 == 0) {
// return kJSQMessagesCollectionViewCellLabelHeightDefault; return kJSQMessagesCollectionViewCellLabelHeightDefault;
// } }
return 0.0f; return 0.0f;
} }

View File

@ -20,9 +20,6 @@
#import "NSUserDefaults+DemoSettings.h" #import "NSUserDefaults+DemoSettings.h"
#import "JSQCall.h"
#import "JSQInfoMessage.h"
#import "JSQErrorMessage.h"
/** /**
* This is for demo/testing purposes only. * This is for demo/testing purposes only.
@ -36,7 +33,7 @@
{ {
self = [super init]; self = [super init];
if (self) { if (self) {
if ([NSUserDefaults emptyMessagesSetting]) { if ([NSUserDefaults emptyMessagesSetting]) {
self.messages = [NSMutableArray new]; self.messages = [NSMutableArray new];
} }
@ -85,7 +82,7 @@
* Be sure to create your bubble images one time and reuse them for good performance. * 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.outgoingBubbleImageData = [bubbleFactory outgoingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleLightGrayColor]];
self.incomingBubbleImageData = [bubbleFactory incomingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleGreenColor]]; self.incomingBubbleImageData = [bubbleFactory incomingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleGreenColor]];
@ -102,75 +99,35 @@
* You should have a mutable array or orderedSet, or something. * You should have a mutable array or orderedSet, or something.
*/ */
self.messages = [[NSMutableArray alloc] initWithObjects: self.messages = [[NSMutableArray alloc] initWithObjects:
[[JSQCall alloc] initWithCallerId:kJSQDemoAvatarIdWoz [[JSQTextMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
callerDisplayName:kJSQDemoAvatarDisplayNameWoz
date:[NSDate date]
status:kCallOutgoing],
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
senderDisplayName:kJSQDemoAvatarDisplayNameSquires senderDisplayName:kJSQDemoAvatarDisplayNameSquires
date:[NSDate distantPast] date:[NSDate distantPast]
text:@"Welcome to JSQMessages: A messaging UI framework for iOS."], 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 [[JSQTextMessage alloc] initWithSenderId:kJSQDemoAvatarIdWoz
senderDisplayName:kJSQDemoAvatarDisplayNameSquires senderDisplayName:kJSQDemoAvatarDisplayNameWoz
date:[NSDate distantPast] 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."], 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 [[JSQTextMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
senderDisplayName:kJSQDemoAvatarDisplayNameJobs senderDisplayName:kJSQDemoAvatarDisplayNameSquires
date:[NSDate date] date:[NSDate distantPast]
text:@"JSQMessagesViewController is nearly an exact replica of the iOS Messages App. And perhaps, better."], 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 [[JSQTextMessage alloc] initWithSenderId:kJSQDemoAvatarIdJobs
senderDisplayName:kJSQDemoAvatarDisplayNameCook senderDisplayName:kJSQDemoAvatarDisplayNameJobs
date:[NSDate date] date:[NSDate date]
text:@"It is unit-tested, free, open-source, and documented."], 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 senderDisplayName:kJSQDemoAvatarDisplayNameSquires
date:[NSDate date] date:[NSDate date]
text:@"Now with media messages!"], 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]; nil];
[self addPhotoMediaMessage]; [self addPhotoMediaMessage];
@ -191,9 +148,9 @@
* You should see "END" twice * You should see "END" twice
*/ */
if ([NSUserDefaults longMessageSetting]) { if ([NSUserDefaults longMessageSetting]) {
JSQMessage *reallyLongMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires JSQTextMessage *reallyLongMessage = [JSQTextMessage messageWithSenderId:kJSQDemoAvatarIdSquires
displayName:kJSQDemoAvatarDisplayNameSquires 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"]; 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]; [self.messages addObject:reallyLongMessage];
} }
@ -202,9 +159,9 @@
- (void)addPhotoMediaMessage - (void)addPhotoMediaMessage
{ {
JSQPhotoMediaItem *photoItem = [[JSQPhotoMediaItem alloc] initWithImage:[UIImage imageNamed:@"goldengate"]]; JSQPhotoMediaItem *photoItem = [[JSQPhotoMediaItem alloc] initWithImage:[UIImage imageNamed:@"goldengate"]];
JSQMessage *photoMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires JSQMediaMessage *photoMessage = [JSQMediaMessage messageWithSenderId:kJSQDemoAvatarIdSquires
displayName:kJSQDemoAvatarDisplayNameSquires displayName:kJSQDemoAvatarDisplayNameSquires
media:photoItem]; media:photoItem];
[self.messages addObject:photoMessage]; [self.messages addObject:photoMessage];
} }
@ -215,9 +172,9 @@
JSQLocationMediaItem *locationItem = [[JSQLocationMediaItem alloc] init]; JSQLocationMediaItem *locationItem = [[JSQLocationMediaItem alloc] init];
[locationItem setLocation:ferryBuildingInSF withCompletionHandler:completion]; [locationItem setLocation:ferryBuildingInSF withCompletionHandler:completion];
JSQMessage *locationMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires JSQMediaMessage *locationMessage = [JSQMediaMessage messageWithSenderId:kJSQDemoAvatarIdSquires
displayName:kJSQDemoAvatarDisplayNameSquires displayName:kJSQDemoAvatarDisplayNameSquires
media:locationItem]; media:locationItem];
[self.messages addObject:locationMessage]; [self.messages addObject:locationMessage];
} }
@ -227,9 +184,9 @@
NSURL *videoURL = [NSURL URLWithString:@"file://"]; NSURL *videoURL = [NSURL URLWithString:@"file://"];
JSQVideoMediaItem *videoItem = [[JSQVideoMediaItem alloc] initWithFileURL:videoURL isReadyToPlay:YES]; JSQVideoMediaItem *videoItem = [[JSQVideoMediaItem alloc] initWithFileURL:videoURL isReadyToPlay:YES];
JSQMessage *videoMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires JSQMediaMessage *videoMessage = [JSQMediaMessage messageWithSenderId:kJSQDemoAvatarIdSquires
displayName:kJSQDemoAvatarDisplayNameSquires displayName:kJSQDemoAvatarDisplayNameSquires
media:videoItem]; media:videoItem];
[self.messages addObject:videoMessage]; [self.messages addObject:videoMessage];
} }

View File

@ -15,11 +15,11 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>6.1.1</string> <string>6.0.0</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>6.1.1</string> <string>6.0.0</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -16,22 +16,56 @@
@interface JSQMessagesToolbarButtonFactoryTests : XCTestCase @interface JSQMessagesToolbarButtonFactoryTests : XCTestCase
@end @end
@implementation JSQMessagesToolbarButtonFactoryTests @implementation JSQMessagesToolbarButtonFactoryTests
- (void)setUp
{
[super setUp];
}
- (void)tearDown
{
[super tearDown];
}
- (void)testDefaultSendButtonItem - (void)testDefaultSendButtonItem
{ {
UIButton *button = [JSQMessagesToolbarButtonFactory defaultSendButtonItem]; UIButton *button = [JSQMessagesToolbarButtonFactory defaultSendButtonItem];
XCTAssertNotNil(button, @"Button should not be nil"); 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 - (void)testDefaultAccessoryButtonItem
{ {
UIButton *button = [JSQMessagesToolbarButtonFactory defaultAccessoryButtonItem]; UIButton *button = [JSQMessagesToolbarButtonFactory defaultAccessoryButtonItem];
XCTAssertNotNil(button, @"Button should not be nil"); 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 @end

View File

@ -34,7 +34,7 @@
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0]; NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
JSQMessagesCollectionViewLayoutAttributes *attrs = [JSQMessagesCollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; JSQMessagesCollectionViewLayoutAttributes *attrs = [JSQMessagesCollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attrs.messageBubbleFont = [UIFont systemFontOfSize:15.0f]; 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.textViewTextContainerInsets = UIEdgeInsetsMake(10.0f, 8.0f, 10.0f, 8.0f);
attrs.textViewFrameInsets = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 6.0f); attrs.textViewFrameInsets = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 6.0f);
attrs.incomingAvatarViewSize = CGSizeMake(34.0f, 34.0f); attrs.incomingAvatarViewSize = CGSizeMake(34.0f, 34.0f);

View File

@ -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

View File

@ -12,7 +12,7 @@
#import <OCMock/OCMock.h> #import <OCMock/OCMock.h>
#import "JSQMessage.h" #import "JSQMediaMessage.h"
// Fake media object for testing // Fake media object for testing
@ -35,7 +35,7 @@
@interface JSQMessageMediaTests : XCTestCase @interface JSQMediaMessageTests : XCTestCase
@property (strong, nonatomic) NSString *senderId; @property (strong, nonatomic) NSString *senderId;
@property (strong, nonatomic) NSString *senderDisplayName; @property (strong, nonatomic) NSString *senderDisplayName;
@ -45,7 +45,7 @@
@end @end
@implementation JSQMessageMediaTests @implementation JSQMediaMessageTests
- (void)setUp - (void)setUp
{ {
@ -65,46 +65,46 @@
[super tearDown]; [super tearDown];
} }
- (void)testMediaMessageInit - (void)testTextMessageInit
{ {
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId JSQMediaMessage *msg = [[JSQMediaMessage alloc] initWithSenderId:self.senderId
senderDisplayName:self.senderDisplayName senderDisplayName:self.senderDisplayName
date:self.date date:self.date
media:self.mockMediaData]; media:self.mockMediaData];
XCTAssertNotNil(msg, @"Message should not be nil"); XCTAssertNotNil(msg, @"Message should not be nil");
} }
- (void)testMediaMessageInvalidInit - (void)testMessageInvalidInit
{ {
XCTAssertThrows([[JSQMessage alloc] init], @"Invalid init should throw"); XCTAssertThrows([[JSQMediaMessage alloc] init], @"Invalid init should throw");
XCTAssertThrows([[JSQMessage alloc] initWithSenderId:nil senderDisplayName:nil date:nil media:nil], @"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 JSQMediaMessage *msg = [[JSQMediaMessage alloc] initWithSenderId:self.senderId
senderDisplayName:self.senderDisplayName senderDisplayName:self.senderDisplayName
date:self.date date:self.date
media:self.mockMediaData]; media:self.mockMediaData];
JSQMessage *copy = [msg copy]; JSQMediaMessage *copy = [msg copy];
XCTAssertEqualObjects(msg, copy, @"Copied messages should be equal"); XCTAssertEqualObjects(msg, copy, @"Copied messages should be equal");
XCTAssertEqual([msg hash], [copy hash], @"Copied messages hashes 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"); XCTAssertEqualObjects(msg, msg, @"Messages should be equal to itself");
} }
- (void)testMediaMessageArchiving - (void)testMessageArchiving
{ {
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId JSQMediaMessage *msg = [[JSQMediaMessage alloc] initWithSenderId:self.senderId
senderDisplayName:self.senderDisplayName senderDisplayName:self.senderDisplayName
date:self.date date:self.date
media:[FakeMedia new]]; media:[FakeMedia new]];
NSData *msgData = [NSKeyedArchiver archivedDataWithRootObject:msg]; NSData *msgData = [NSKeyedArchiver archivedDataWithRootObject:msg];
JSQMessage *unarchivedMsg = [NSKeyedUnarchiver unarchiveObjectWithData:msgData]; JSQMediaMessage *unarchivedMsg = [NSKeyedUnarchiver unarchiveObjectWithData:msgData];
XCTAssertEqualObjects(msg, unarchivedMsg, @"Message should be equal"); XCTAssertEqualObjects(msg, unarchivedMsg, @"Message should be equal");
} }

View File

@ -13,29 +13,23 @@
#import "JSQMessage.h" #import "JSQMessage.h"
@interface JSQMessageTextTests : XCTestCase @interface JSQMessageTests : XCTestCase
@property (strong, nonatomic) NSString *senderId; @property (strong, nonatomic) NSString *senderId;
@property (strong, nonatomic) NSString *senderDisplayName; @property (strong, nonatomic) NSString *senderDisplayName;
@property (strong, nonatomic) NSDate *date; @property (strong, nonatomic) NSDate *date;
@property (strong, nonatomic) NSString *text;
@end @end
@implementation JSQMessageTextTests @implementation JSQMessageTests
- (void)setUp - (void)setUp
{ {
[super setUp]; [super setUp];
self.senderId = @"324543-43556-212343"; self.senderId = @"324543-43556-212343";
self.senderDisplayName = @"Jesse Squires"; self.senderDisplayName = @"Jesse Squires";
self.date = [NSDate date]; 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 - (void)tearDown
@ -43,48 +37,39 @@
self.senderId = nil; self.senderId = nil;
self.senderDisplayName = nil; self.senderDisplayName = nil;
self.date = nil; self.date = nil;
self.text = nil;
[super tearDown]; [super tearDown];
} }
#pragma mark - Text messages - (void)testMessageInit
- (void)testTextMessageInit
{ {
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId senderDisplayName:self.senderDisplayName date:self.date isMedia:NO];
senderDisplayName:self.senderDisplayName
date:self.date
text:self.text];
XCTAssertNotNil(msg, @"Message should not be nil"); XCTAssertNotNil(msg, @"Message should not be nil");
} }
- (void)testTextMessageInvalidInit - (void)testMessageInvalidInit
{ {
XCTAssertThrows([[JSQMessage alloc] init], @"Invalid init should throw"); 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 JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId senderDisplayName:self.senderDisplayName date:self.date isMedia:NO];
senderDisplayName:self.senderDisplayName
date:self.date
text:self.text];
JSQMessage *copy = [msg copy]; JSQMessage *copy = [msg copy];
XCTAssertEqualObjects(msg, copy, @"Copied messages should be equal"); XCTAssertEqualObjects(msg, copy, @"Copied messages should be equal");
XCTAssertEqual([msg hash], [copy hash], @"Copied messages hashes 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"); XCTAssertEqualObjects(msg, msg, @"Messages should be equal to itself");
} }
- (void)testTextMessageArchiving - (void)testMessageArchiving
{ {
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId senderDisplayName:self.senderDisplayName date:self.date isMedia:YES];
senderDisplayName:self.senderDisplayName
date:self.date
text:self.text];
NSData *msgData = [NSKeyedArchiver archivedDataWithRootObject:msg]; NSData *msgData = [NSKeyedArchiver archivedDataWithRootObject:msg];
JSQMessage *unarchivedMsg = [NSKeyedUnarchiver unarchiveObjectWithData:msgData]; JSQMessage *unarchivedMsg = [NSKeyedUnarchiver unarchiveObjectWithData:msgData];

View File

@ -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

View 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

View File

@ -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

View File

@ -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.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.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.scrollEnabled, YES, @"Property should be equal to default value");
XCTAssertEqual(self.textView.scrollsToTop, NO, @"Property should be equal to default value"); XCTAssertEqual(self.textView.scrollsToTop, NO, @"Property should be equal to default value");

View File

@ -1,13 +1,11 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'JSQMessagesViewController' s.name = 'JSQMessagesViewController'
s.version = '6.1.1' s.version = '6.0-beta6'
s.summary = 'An elegant messages UI library for iOS.' s.summary = 'An elegant messages UI library for iOS.'
s.homepage = 'http://jessesquires.github.io/JSQMessagesViewController' s.homepage = 'http://jessesquires.github.io/JSQMessagesViewController'
s.license = 'MIT' s.license = 'MIT'
s.screenshots = ['https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot0.png', 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/screenshot1.png']
'https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot2.png',
'https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot3.png']
s.author = { 'Jesse Squires' => 'jesse.squires.developer@gmail.com' } s.author = { 'Jesse Squires' => 'jesse.squires.developer@gmail.com' }
s.social_media_url = 'https://twitter.com/jesse_squires' s.social_media_url = 'https://twitter.com/jesse_squires'
s.source = { :git => 'https://github.com/jessesquires/JSQMessagesViewController.git', :tag => s.version.to_s } s.source = { :git => 'https://github.com/jessesquires/JSQMessagesViewController.git', :tag => s.version.to_s }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -32,32 +32,11 @@
*/ */
+ (UIColor *)jsq_messageBubbleBlueColor; + (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. * @return A color object containing HSB values similar to the iOS 7 messages app light gray bubble color.
*/ */
+ (UIColor *)jsq_messageBubbleLightGrayColor; + (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 #pragma mark - Utilities
/** /**

View File

@ -26,7 +26,7 @@
{ {
return [UIColor colorWithHue:130.0f / 360.0f return [UIColor colorWithHue:130.0f / 360.0f
saturation:0.68f saturation:0.68f
brightness:0.84f brightness:0.80f
alpha:1.0f]; alpha:1.0f];
} }
@ -38,14 +38,6 @@
alpha:1.0f]; 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 + (UIColor *)jsq_messageBubbleLightGrayColor
{ {
return [UIColor colorWithHue:240.0f / 360.0f return [UIColor colorWithHue:240.0f / 360.0f
@ -54,23 +46,6 @@
alpha:1.0f]; 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 #pragma mark - Utilities
- (UIColor *)jsq_colorByDarkeningColorWithValue:(CGFloat)value - (UIColor *)jsq_colorByDarkeningColorWithValue:(CGFloat)value

View File

@ -95,5 +95,4 @@
return [UIImage jsq_bubbleImageFromBundleWithName:@"play"]; return [UIImage jsq_bubbleImageFromBundleWithName:@"play"];
} }
@end @end

View File

@ -59,13 +59,6 @@ FOUNDATION_EXPORT NSString * const JSQMessagesKeyboardControllerUserInfoKeyKeybo
*/ */
- (void)keyboardController:(JSQMessagesKeyboardController *)keyboardController keyboardDidChangeFrame:(CGRect)keyboardFrame; - (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 @end

View File

@ -138,15 +138,14 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
- (void)beginListeningForKeyboard - (void)beginListeningForKeyboard
{ {
if (self.textView.inputAccessoryView == nil) { self.textView.inputAccessoryView = [[UIView alloc] init];
self.textView.inputAccessoryView = [[UIView alloc] init];
}
[self jsq_registerForNotifications]; [self jsq_registerForNotifications];
} }
- (void)endListeningForKeyboard - (void)endListeningForKeyboard
{ {
self.textView.inputAccessoryView = nil;
[self jsq_unregisterForNotifications]; [self jsq_unregisterForNotifications];
[self jsq_setKeyboardViewHidden:NO]; [self jsq_setKeyboardViewHidden:NO];
@ -213,8 +212,6 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
[self jsq_handleKeyboardNotification:notification completion:^(BOOL finished) { [self jsq_handleKeyboardNotification:notification completion:^(BOOL finished) {
[self.panGestureRecognizer removeTarget:self action:NULL]; [self.panGestureRecognizer removeTarget:self action:NULL];
[self.delegate keyboardControllerKeyboardDidHide:self];
}]; }];
} }

View File

@ -143,28 +143,6 @@
*/ */
@property (copy, nonatomic) NSString *incomingMediaCellIdentifier; @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. * Specifies whether or not the view controller should show the typing indicator for an incoming message.
* *
@ -239,46 +217,32 @@
- (void)didPressAccessoryButton:(UIButton *)sender; - (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; - (void)finishSendingMessage;
/** /**
* Completes the "sending" of a new message by resetting the `inputToolbar`, adding a new collection view cell in the collection view, * Completes the "receiving" of a new message by animating the typing indicator,
* reloading the collection view, and scrolling to the newly sent message as specified by `automaticallyScrollsToMostRecentMessage`. * animating the addition of a new collection view cell in the collection view,
* Scrolling to the new message can be animated as specified by the animated parameter. * 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 after adding a new "received" message
* * to your data source and performing any related tasks.
* @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.
* *
* @see `automaticallyScrollsToMostRecentMessage`. * @see `automaticallyScrollsToMostRecentMessage`.
*/ */
- (void)finishSendingMessageAnimated:(BOOL)animated;
/**
* Animates the receiving of a new message. See `finishReceivingMessageAnimated:` for more details.
*
* @see `finishReceivingMessageAnimated:`.
*/
- (void)finishReceivingMessage; - (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`. * Scrolls the collection view such that the bottom most cell is completely visible, above the `inputToolbar`.
* *

View File

@ -42,16 +42,11 @@
#import "UIColor+JSQMessages.h" #import "UIColor+JSQMessages.h"
#import "UIDevice+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; static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObservingContext;
@interface JSQMessagesViewController () <JSQMessagesInputToolbarDelegate, @interface JSQMessagesViewController () <JSQMessagesInputToolbarDelegate,
JSQMessagesKeyboardControllerDelegate> JSQMessagesKeyboardControllerDelegate>
@ -124,7 +119,6 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
- (void)jsq_configureMessagesViewController - (void)jsq_configureMessagesViewController
{ {
self.view.backgroundColor = [UIColor whiteColor]; self.view.backgroundColor = [UIColor whiteColor];
;
self.jsq_isObserving = NO; self.jsq_isObserving = NO;
@ -148,10 +142,6 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
self.incomingCellIdentifier = [JSQMessagesCollectionViewCellIncoming cellReuseIdentifier]; self.incomingCellIdentifier = [JSQMessagesCollectionViewCellIncoming cellReuseIdentifier];
self.incomingMediaCellIdentifier = [JSQMessagesCollectionViewCellIncoming mediaCellReuseIdentifier]; self.incomingMediaCellIdentifier = [JSQMessagesCollectionViewCellIncoming mediaCellReuseIdentifier];
self.callCellIndentifier = [JSQCallCollectionViewCell cellReuseIdentifier];
self.displayedMessageCellIndentifier = [JSQDisplayedMessageCollectionViewCell cellReuseIdentifier];
self.showTypingIndicator = NO; self.showTypingIndicator = NO;
self.showLoadEarlierMessagesHeader = NO; self.showLoadEarlierMessagesHeader = NO;
@ -213,12 +203,6 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
[self.collectionView reloadData]; [self.collectionView reloadData];
} }
- (void)setTopContentAdditionalInset:(CGFloat)topContentAdditionalInset
{
_topContentAdditionalInset = topContentAdditionalInset;
[self jsq_updateCollectionViewInsets];
}
#pragma mark - View lifecycle #pragma mark - View lifecycle
- (void)viewDidLoad - (void)viewDidLoad
@ -300,6 +284,13 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
[self.collectionView.collectionViewLayout invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]]; [self.collectionView.collectionViewLayout invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
} }
#pragma mark - UIResponder
- (BOOL)canBecomeFirstResponder
{
return YES;
}
#pragma mark - Messages view controller #pragma mark - Messages view controller
- (void)didPressSendButton:(UIButton *)button - (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__); NSAssert(NO, @"Error! required method not implemented in subclass. Need to implement %s", __PRETTY_FUNCTION__);
} }
- (void)didPressAccessoryButton:(UIButton *)sender - (void)didPressAccessoryButton:(UIButton *)sender { }
{
NSAssert(NO, @"Error! required method not implemented in subclass. Need to implement %s", __PRETTY_FUNCTION__);
}
- (void)finishSendingMessage - (void)finishSendingMessage
{ {
[self finishSendingMessageAnimated:YES];
}
- (void)finishSendingMessageAnimated:(BOOL)animated {
UITextView *textView = self.inputToolbar.contentView.textView; UITextView *textView = self.inputToolbar.contentView.textView;
textView.text = nil; textView.text = nil;
[textView.undoManager removeAllActions]; [textView.undoManager removeAllActions];
@ -335,24 +318,19 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
[self.collectionView reloadData]; [self.collectionView reloadData];
if (self.automaticallyScrollsToMostRecentMessage) { if (self.automaticallyScrollsToMostRecentMessage) {
[self scrollToBottomAnimated:animated]; [self scrollToBottomAnimated:YES];
} }
} }
- (void)finishReceivingMessage - (void)finishReceivingMessage
{ {
[self finishReceivingMessageAnimated:YES];
}
- (void)finishReceivingMessageAnimated:(BOOL)animated {
self.showTypingIndicator = NO; self.showTypingIndicator = NO;
[self.collectionView.collectionViewLayout invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]]; [self.collectionView.collectionViewLayout invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
[self.collectionView reloadData]; [self.collectionView reloadData];
if (self.automaticallyScrollsToMostRecentMessage) { if (self.automaticallyScrollsToMostRecentMessage && ![self jsq_isMenuVisible]) {
[self scrollToBottomAnimated:animated]; [self scrollToBottomAnimated:YES];
} }
} }
@ -364,36 +342,11 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
NSInteger items = [self.collectionView numberOfItemsInSection:0]; NSInteger items = [self.collectionView numberOfItemsInSection:0];
if (items == 0) { if (items > 0) {
return; [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 #pragma mark - JSQMessages collection view data source
@ -452,102 +405,14 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
NSParameterAssert(messageSenderId != nil); NSParameterAssert(messageSenderId != nil);
BOOL isOutgoingMessage = [messageSenderId isEqualToString:self.senderId]; BOOL isOutgoingMessage = [messageSenderId isEqualToString:self.senderId];
BOOL isCall = [messageItem messageType] == TSCallAdapter; BOOL isMediaMessage = [messageItem isMediaMessage];
BOOL isInfoMessage = [messageItem messageType] == TSInfoMessageAdapter;
BOOL isErrorMessage = [messageItem messageType] == TSErrorMessageAdapter;
BOOL isMediaMessage = NO;
if (!isCall && !isInfoMessage && !isErrorMessage )
{
isMediaMessage = [messageItem isMediaMessage];
}
NSString *cellIdentifier = nil; NSString *cellIdentifier = nil;
if (isMediaMessage) {
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) {
cellIdentifier = isOutgoingMessage ? self.outgoingMediaCellIdentifier : self.incomingMediaCellIdentifier; cellIdentifier = isOutgoingMessage ? self.outgoingMediaCellIdentifier : self.incomingMediaCellIdentifier;
}
} else { else {
cellIdentifier = isOutgoingMessage ? self.outgoingCellIdentifier : self.incomingCellIdentifier; cellIdentifier = isOutgoingMessage ? self.outgoingCellIdentifier : self.incomingCellIdentifier;
} }
JSQMessagesCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath]; JSQMessagesCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
@ -581,16 +446,8 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
if (needsAvatar) { if (needsAvatar) {
avatarImageDataSource = [collectionView.dataSource collectionView:collectionView avatarImageDataForItemAtIndexPath:indexPath]; avatarImageDataSource = [collectionView.dataSource collectionView:collectionView avatarImageDataForItemAtIndexPath:indexPath];
if (avatarImageDataSource != nil) { if (avatarImageDataSource != nil) {
cell.avatarImageView.image = [avatarImageDataSource avatarImage] ?: [avatarImageDataSource avatarPlaceholderImage];
UIImage *avatarImage = [avatarImageDataSource avatarImage]; cell.avatarImageView.highlightedImage = [avatarImageDataSource avatarHighlightedImage];
if (avatarImage == nil) {
cell.avatarImageView.image = [avatarImageDataSource avatarPlaceholderImage];
cell.avatarImageView.highlightedImage = nil;
}
else {
cell.avatarImageView.image = avatarImage;
cell.avatarImageView.highlightedImage = [avatarImageDataSource avatarHighlightedImage];
}
} }
} }
@ -598,6 +455,8 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
cell.messageBubbleTopLabel.attributedText = [collectionView.dataSource collectionView:collectionView attributedTextForMessageBubbleTopLabelAtIndexPath:indexPath]; cell.messageBubbleTopLabel.attributedText = [collectionView.dataSource collectionView:collectionView attributedTextForMessageBubbleTopLabelAtIndexPath:indexPath];
cell.cellBottomLabel.attributedText = [collectionView.dataSource collectionView:collectionView attributedTextForCellBottomLabelAtIndexPath:indexPath]; cell.cellBottomLabel.attributedText = [collectionView.dataSource collectionView:collectionView attributedTextForCellBottomLabelAtIndexPath:indexPath];
cell.backgroundColor = [UIColor whiteColor];
CGFloat bubbleTopLabelInset = (avatarImageDataSource != nil) ? 60.0f : 15.0f; CGFloat bubbleTopLabelInset = (avatarImageDataSource != nil) ? 60.0f : 15.0f;
if (isOutgoingMessage) { if (isOutgoingMessage) {
@ -609,8 +468,8 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
cell.textView.dataDetectorTypes = UIDataDetectorTypeAll; cell.textView.dataDetectorTypes = UIDataDetectorTypeAll;
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale; cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
cell.layer.shouldRasterize = YES;
return cell; return cell;
} }
@ -653,16 +512,8 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
- (BOOL)collectionView:(JSQMessagesCollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath - (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]; 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]) { if ([messageItem isMediaMessage]) {
return NO; return NO;
} }
@ -732,8 +583,6 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
didTapCellAtIndexPath:(NSIndexPath *)indexPath didTapCellAtIndexPath:(NSIndexPath *)indexPath
touchLocation:(CGPoint)touchLocation { } touchLocation:(CGPoint)touchLocation { }
#pragma mark - Input toolbar delegate #pragma mark - Input toolbar delegate
- (void)messagesInputToolbar:(JSQMessagesInputToolbar *)toolbar didPressLeftBarButton:(UIButton *)sender - (void)messagesInputToolbar:(JSQMessagesInputToolbar *)toolbar didPressLeftBarButton:(UIButton *)sender
@ -879,10 +728,6 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
- (void)keyboardController:(JSQMessagesKeyboardController *)keyboardController keyboardDidChangeFrame:(CGRect)keyboardFrame - (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); CGFloat heightFromBottom = CGRectGetMaxY(self.collectionView.frame) - CGRectGetMinY(keyboardFrame);
heightFromBottom = MAX(0.0f, heightFromBottom); heightFromBottom = MAX(0.0f, heightFromBottom);
@ -890,16 +735,6 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
[self jsq_setToolbarBottomLayoutGuideConstant:heightFromBottom]; [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 - (void)jsq_setToolbarBottomLayoutGuideConstant:(CGFloat)constant
{ {
self.toolbarBottomLayoutGuide.constant = constant; self.toolbarBottomLayoutGuide.constant = constant;

View File

@ -73,7 +73,4 @@
*/ */
- (JSQMessagesBubbleImage *)incomingMessagesBubbleImageWithColor:(UIColor *)color; - (JSQMessagesBubbleImage *)incomingMessagesBubbleImageWithColor:(UIColor *)color;
- (JSQMessagesBubbleImage *)outgoingMessageFailedBubbleImageWithColor:(UIColor *)color;
@end @end

View File

@ -83,11 +83,6 @@
return [self jsq_messagesBubbleImageWithColor:color flippedForIncoming:YES]; return [self jsq_messagesBubbleImageWithColor:color flippedForIncoming:YES];
} }
- (JSQMessagesBubbleImage *)outgoingMessageFailedBubbleImageWithColor:(UIColor *)color
{
return [self jsq_messagesBubbleImageWithColor:color flippedForIncoming:NO];
}
#pragma mark - Private #pragma mark - Private
- (UIEdgeInsets)jsq_centerPointEdgeInsetsForImageSize:(CGSize)bubbleImageSize - (UIEdgeInsets)jsq_centerPointEdgeInsetsForImageSize:(CGSize)bubbleImageSize

View File

@ -27,16 +27,16 @@
+ (UIButton *)defaultAccessoryButtonItem + (UIButton *)defaultAccessoryButtonItem
{ {
UIImage *accessoryImage = [UIImage jsq_defaultAccessoryImage]; 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]]; 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:normalImage forState:UIControlStateNormal];
[accessoryButton setImage:highlightedImage forState:UIControlStateHighlighted]; [accessoryButton setImage:highlightedImage forState:UIControlStateHighlighted];
accessoryButton.contentMode = UIViewContentModeScaleAspectFit; accessoryButton.contentMode = UIViewContentModeScaleAspectFit;
accessoryButton.backgroundColor = [UIColor clearColor]; accessoryButton.backgroundColor = [UIColor clearColor];
//accessoryButton.tintColor = [UIColor lightGrayColor]; accessoryButton.tintColor = [UIColor lightGrayColor];
return accessoryButton; return accessoryButton;
} }
@ -51,25 +51,13 @@
[sendButton setTitleColor:[[UIColor jsq_messageBubbleBlueColor] jsq_colorByDarkeningColorWithValue:0.1f] forState:UIControlStateHighlighted]; [sendButton setTitleColor:[[UIColor jsq_messageBubbleBlueColor] jsq_colorByDarkeningColorWithValue:0.1f] forState:UIControlStateHighlighted];
[sendButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled]; [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.adjustsFontSizeToFitWidth = YES;
sendButton.titleLabel.minimumScaleFactor = 0.85f; sendButton.titleLabel.minimumScaleFactor = 0.85f;
sendButton.contentMode = UIViewContentModeCenter; sendButton.contentMode = UIViewContentModeCenter;
sendButton.backgroundColor = [UIColor clearColor]; sendButton.backgroundColor = [UIColor clearColor];
sendButton.tintColor = [UIColor jsq_messageBubbleBlueColor]; 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; return sendButton;
} }

View File

@ -40,6 +40,8 @@
// Model // Model
#import "JSQMessage.h" #import "JSQMessage.h"
#import "JSQTextMessage.h"
#import "JSQMediaMessage.h"
#import "JSQMediaItem.h" #import "JSQMediaItem.h"
#import "JSQPhotoMediaItem.h" #import "JSQPhotoMediaItem.h"

View File

@ -167,13 +167,6 @@ FOUNDATION_EXPORT const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault;
*/ */
@property (assign, nonatomic) CGSize outgoingAvatarViewSize; @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` * 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. * at the specified indexPath. The returned size contains the required dimensions to display the entire message contents.

View File

@ -33,15 +33,6 @@
#import "UIImage+JSQMessages.h" #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 kJSQMessagesCollectionViewCellLabelHeightDefault = 20.0f;
const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f; const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
@ -49,7 +40,7 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
@interface JSQMessagesCollectionViewFlowLayout () @interface JSQMessagesCollectionViewFlowLayout ()
@property (strong, nonatomic) NSCache *messageBubbleCache; @property (strong, nonatomic) NSMutableDictionary *messageBubbleSizes;
@property (strong, nonatomic) UIDynamicAnimator *dynamicAnimator; @property (strong, nonatomic) UIDynamicAnimator *dynamicAnimator;
@property (strong, nonatomic) NSMutableSet *visibleIndexPaths; @property (strong, nonatomic) NSMutableSet *visibleIndexPaths;
@ -90,9 +81,7 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
_bubbleImageAssetWidth = [UIImage jsq_bubbleCompactImage].size.width; _bubbleImageAssetWidth = [UIImage jsq_bubbleCompactImage].size.width;
_messageBubbleCache = [NSCache new]; _messageBubbleSizes = [NSMutableDictionary new];
_messageBubbleCache.name = @"JSQMessagesCollectionViewFlowLayout.messageBubbleCache";
_messageBubbleCache.countLimit = 200;
_messageBubbleFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; _messageBubbleFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
@ -100,7 +89,7 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
_messageBubbleLeftRightMargin = 240.0f; _messageBubbleLeftRightMargin = 240.0f;
} }
else { else {
_messageBubbleLeftRightMargin = 50.0f; _messageBubbleLeftRightMargin = 40.0f;
} }
_messageBubbleTextViewFrameInsets = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 6.0f); _messageBubbleTextViewFrameInsets = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 6.0f);
@ -155,8 +144,8 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
_messageBubbleFont = nil; _messageBubbleFont = nil;
[_messageBubbleCache removeAllObjects]; [_messageBubbleSizes removeAllObjects];
_messageBubbleCache = nil; _messageBubbleSizes = nil;
[_dynamicAnimator removeAllBehaviors]; [_dynamicAnimator removeAllBehaviors];
_dynamicAnimator = nil; _dynamicAnimator = nil;
@ -230,11 +219,6 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
[self invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]]; [self invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
} }
- (void)setCacheLimit:(NSUInteger)cacheLimit
{
self.messageBubbleCache.countLimit = cacheLimit;
}
#pragma mark - Getters #pragma mark - Getters
- (CGFloat)itemWidth - (CGFloat)itemWidth
@ -258,11 +242,6 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
return _visibleIndexPaths; return _visibleIndexPaths;
} }
- (NSUInteger)cacheLimit
{
return self.messageBubbleCache.countLimit;
}
#pragma mark - Notifications #pragma mark - Notifications
- (void)jsq_didReceiveApplicationMemoryWarningNotification:(NSNotification *)notification - (void)jsq_didReceiveApplicationMemoryWarningNotification:(NSNotification *)notification
@ -287,10 +266,6 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
if (context.invalidateFlowLayoutAttributes if (context.invalidateFlowLayoutAttributes
|| context.invalidateFlowLayoutDelegateMetrics) { || context.invalidateFlowLayoutDelegateMetrics) {
[self jsq_resetDynamicAnimator];
}
if (context.emptyCache) {
[self jsq_resetLayout]; [self jsq_resetLayout];
} }
@ -323,8 +298,8 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
NSMutableArray *attributesInRectCopy = [attributesInRect mutableCopy]; NSMutableArray *attributesInRectCopy = [attributesInRect mutableCopy];
NSArray *dynamicAttributes = [self.dynamicAnimator itemsInRect:rect]; NSArray *dynamicAttributes = [self.dynamicAnimator itemsInRect:rect];
// avoid duplicate attributes // avoid duplicate attributes
// use dynamic animator attribute item instead of regular item, if it exists // use dynamic animator attribute item instead of regular item, if it exists
for (UICollectionViewLayoutAttributes *eachItem in attributesInRect) { for (UICollectionViewLayoutAttributes *eachItem in attributesInRect) {
for (UICollectionViewLayoutAttributes *eachDynamicItem in dynamicAttributes) { for (UICollectionViewLayoutAttributes *eachDynamicItem in dynamicAttributes) {
@ -424,7 +399,7 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
- (void)jsq_resetLayout - (void)jsq_resetLayout
{ {
[self.messageBubbleCache removeAllObjects]; [self.messageBubbleSizes removeAllObjects];
[self jsq_resetDynamicAnimator]; [self jsq_resetDynamicAnimator];
} }
@ -440,58 +415,49 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
- (CGSize)messageBubbleSizeForItemAtIndexPath:(NSIndexPath *)indexPath - (CGSize)messageBubbleSizeForItemAtIndexPath:(NSIndexPath *)indexPath
{ {
id<JSQMessageData> messageItem = [self.collectionView.dataSource collectionView:self.collectionView messageDataForItemAtIndexPath:indexPath]; NSValue *cachedSize = [self.messageBubbleSizes objectForKey:indexPath];
if (cachedSize) {
NSValue *cachedSize = [self.messageBubbleCache objectForKey:@(messageItem.hash)];
if (cachedSize != nil) {
return [cachedSize CGSizeValue]; return [cachedSize CGSizeValue];
} }
id<JSQMessageData> messageItem = [self.collectionView.dataSource collectionView:self.collectionView messageDataForItemAtIndexPath:indexPath];
CGSize finalSize = CGSizeZero; CGSize finalSize = CGSizeZero;
if (messageItem.messageType != TSCallAdapter && messageItem.messageType != TSErrorMessageAdapter && messageItem.messageType != TSInfoMessageAdapter) { if ([messageItem isMediaMessage]) {
if ([messageItem isMediaMessage]) { finalSize = [[messageItem media] mediaViewDisplaySize];
finalSize = [[messageItem media] mediaViewDisplaySize]; }
} else {
else { CGSize avatarSize = [self jsq_avatarSizeForIndexPath:indexPath];
CGSize avatarSize = [self jsq_avatarSizeForIndexPath:indexPath];
// from the cell xibs, there is a 2 point space between avatar and bubble // from the cell xibs, there is a 2 point space between avatar and bubble
CGFloat spacingBetweenAvatarAndBubble = 2.0f; CGFloat spacingBetweenAvatarAndBubble = 2.0f;
CGFloat horizontalContainerInsets = self.messageBubbleTextViewTextContainerInsets.left + self.messageBubbleTextViewTextContainerInsets.right; CGFloat horizontalContainerInsets = self.messageBubbleTextViewTextContainerInsets.left + self.messageBubbleTextViewTextContainerInsets.right;
CGFloat horizontalFrameInsets = self.messageBubbleTextViewFrameInsets.left + self.messageBubbleTextViewFrameInsets.right; CGFloat horizontalFrameInsets = self.messageBubbleTextViewFrameInsets.left + self.messageBubbleTextViewFrameInsets.right;
CGFloat horizontalInsetsTotal = horizontalContainerInsets + horizontalFrameInsets + spacingBetweenAvatarAndBubble; CGFloat horizontalInsetsTotal = horizontalContainerInsets + horizontalFrameInsets + spacingBetweenAvatarAndBubble;
CGFloat maximumTextWidth = self.itemWidth - avatarSize.width - self.messageBubbleLeftRightMargin - horizontalInsetsTotal; 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) options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:@{ NSFontAttributeName : self.messageBubbleFont } attributes:@{ NSFontAttributeName : self.messageBubbleFont }
context:nil]; context:nil];
CGSize stringSize = CGRectIntegral(stringRect).size; CGSize stringSize = CGRectIntegral(stringRect).size;
CGFloat verticalContainerInsets = self.messageBubbleTextViewTextContainerInsets.top + self.messageBubbleTextViewTextContainerInsets.bottom; CGFloat verticalContainerInsets = self.messageBubbleTextViewTextContainerInsets.top + self.messageBubbleTextViewTextContainerInsets.bottom;
CGFloat verticalFrameInsets = self.messageBubbleTextViewFrameInsets.top + self.messageBubbleTextViewFrameInsets.bottom; CGFloat verticalFrameInsets = self.messageBubbleTextViewFrameInsets.top + self.messageBubbleTextViewFrameInsets.bottom;
// add extra 2 points of space, because `boundingRectWithSize:` is slightly off // add extra 2 points of space, because `boundingRectWithSize:` is slightly off
// not sure why. magix. (shrug) if you know, submit a PR // 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 // 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); finalSize = CGSizeMake(finalWidth, stringSize.height + verticalInsets);
}
}
else if (messageItem.messageType == TSCallAdapter)
{
finalSize = CGSizeMake(kCallCellWidth, kCallCellHeight);
} else {
finalSize = CGSizeMake(kDisplayedMessageCellWidth, kDisplayedMessageCellHeight);
} }
[self.messageBubbleCache setObject:[NSValue valueWithCGSize:finalSize] forKey:@(messageItem.hash)]; [self.messageBubbleSizes setObject:[NSValue valueWithCGSize:finalSize] forKey:indexPath];
return finalSize; return finalSize;
} }
@ -514,8 +480,11 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
NSIndexPath *indexPath = layoutAttributes.indexPath; NSIndexPath *indexPath = layoutAttributes.indexPath;
CGSize messageBubbleSize = [self messageBubbleSizeForItemAtIndexPath: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; layoutAttributes.textViewFrameInsets = self.messageBubbleTextViewFrameInsets;

View File

@ -27,12 +27,6 @@
*/ */
@interface JSQMessagesCollectionViewFlowLayoutInvalidationContext : UICollectionViewFlowLayoutInvalidationContext @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. * Creates and returns a new `JSQMessagesCollectionViewFlowLayoutInvalidationContext` object.
* *

View File

@ -28,7 +28,6 @@
if (self) { if (self) {
self.invalidateFlowLayoutDelegateMetrics = NO; self.invalidateFlowLayoutDelegateMetrics = NO;
self.invalidateFlowLayoutAttributes = NO; self.invalidateFlowLayoutAttributes = NO;
_emptyCache = NO;
} }
return self; return self;
} }
@ -45,8 +44,11 @@
- (NSString *)description - (NSString *)description
{ {
return [NSString stringWithFormat:@"<%@: invalidateFlowLayoutDelegateMetrics=%@, invalidateFlowLayoutAttributes=%@, invalidateDataSourceCounts=%@, emptyCache=%@>", return [NSString stringWithFormat:@"<%@: invalidateFlowLayoutDelegateMetrics=%d, invalidateFlowLayoutAttributes=%d, invalidateDataSourceCounts=%d>",
[self class], @(self.invalidateFlowLayoutDelegateMetrics), @(self.invalidateFlowLayoutAttributes), @(self.invalidateDataSourceCounts), @(self.emptyCache)]; [self class],
self.invalidateFlowLayoutDelegateMetrics,
self.invalidateFlowLayoutAttributes,
self.invalidateDataSourceCounts];
} }
@end @end

View File

@ -31,12 +31,16 @@
@property (strong, nonatomic) UIFont *messageBubbleFont; @property (strong, nonatomic) UIFont *messageBubbleFont;
/** /**
* The width of the `messageBubbleContainerView` of a `JSQMessagesCollectionViewCell`. * The horizontal spacing between the message bubble and the edge of the collection
* This value should be greater than `0.0`. * 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`. * The inset of the text container's layout area within the text view's content area in a `JSQMessagesCollectionViewCell`.

View File

@ -45,10 +45,10 @@
_messageBubbleFont = messageBubbleFont; _messageBubbleFont = messageBubbleFont;
} }
- (void)setMessageBubbleContainerViewWidth:(CGFloat)messageBubbleContainerViewWidth - (void)setMessageBubbleLeftRightMargin:(CGFloat)messageBubbleLeftRightMargin
{ {
NSParameterAssert(messageBubbleContainerViewWidth > 0.0f); NSParameterAssert(messageBubbleLeftRightMargin >= 0.0f);
_messageBubbleContainerViewWidth = ceilf(messageBubbleContainerViewWidth); _messageBubbleLeftRightMargin = ceilf(messageBubbleLeftRightMargin);
} }
- (void)setIncomingAvatarViewSize:(CGSize)incomingAvatarViewSize - (void)setIncomingAvatarViewSize:(CGSize)incomingAvatarViewSize
@ -121,7 +121,7 @@
|| !UIEdgeInsetsEqualToEdgeInsets(layoutAttributes.textViewTextContainerInsets, self.textViewTextContainerInsets) || !UIEdgeInsetsEqualToEdgeInsets(layoutAttributes.textViewTextContainerInsets, self.textViewTextContainerInsets)
|| !CGSizeEqualToSize(layoutAttributes.incomingAvatarViewSize, self.incomingAvatarViewSize) || !CGSizeEqualToSize(layoutAttributes.incomingAvatarViewSize, self.incomingAvatarViewSize)
|| !CGSizeEqualToSize(layoutAttributes.outgoingAvatarViewSize, self.outgoingAvatarViewSize) || !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.cellTopLabelHeight != (int)self.cellTopLabelHeight
|| (int)layoutAttributes.messageBubbleTopLabelHeight != (int)self.messageBubbleTopLabelHeight || (int)layoutAttributes.messageBubbleTopLabelHeight != (int)self.messageBubbleTopLabelHeight
|| (int)layoutAttributes.cellBottomLabelHeight != (int)self.cellBottomLabelHeight) { || (int)layoutAttributes.cellBottomLabelHeight != (int)self.cellBottomLabelHeight) {
@ -148,7 +148,7 @@
} }
copy.messageBubbleFont = self.messageBubbleFont; copy.messageBubbleFont = self.messageBubbleFont;
copy.messageBubbleContainerViewWidth = self.messageBubbleContainerViewWidth; copy.messageBubbleLeftRightMargin = self.messageBubbleLeftRightMargin;
copy.textViewFrameInsets = self.textViewFrameInsets; copy.textViewFrameInsets = self.textViewFrameInsets;
copy.textViewTextContainerInsets = self.textViewTextContainerInsets; copy.textViewTextContainerInsets = self.textViewTextContainerInsets;
copy.incomingAvatarViewSize = self.incomingAvatarViewSize; copy.incomingAvatarViewSize = self.incomingAvatarViewSize;
@ -156,7 +156,6 @@
copy.cellTopLabelHeight = self.cellTopLabelHeight; copy.cellTopLabelHeight = self.cellTopLabelHeight;
copy.messageBubbleTopLabelHeight = self.messageBubbleTopLabelHeight; copy.messageBubbleTopLabelHeight = self.messageBubbleTopLabelHeight;
copy.cellBottomLabelHeight = self.cellBottomLabelHeight; copy.cellBottomLabelHeight = self.cellBottomLabelHeight;
return copy; return copy;
} }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -170,7 +170,7 @@
- (NSUInteger)hash - (NSUInteger)hash
{ {
return super.hash ^ self.location.hash; return self.location.hash;
} }
- (NSString *)description - (NSString *)description

View 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

View 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

View File

@ -20,21 +20,14 @@
#import "JSQMessageData.h" #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 `JSQMessage` class is an abstract base 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 contains the senderId, senderDisplayName, and the date that the message was sent.
* 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, * @warning This class is intended to be subclassed. You should not use it directly.
* otherwise it contains the message text. *
* @see JSQTextMessage.
* @see JSQMediaMessage.
*/ */
@interface JSQMessage : NSObject <JSQMessageData, NSCoding, NSCopying> @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. * 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 default value is `NO`, meaning that is message contains text, not media.
* The value of this property depends on how the object was initialized.
*/ */
@property (assign, nonatomic, readonly) BOOL isMediaMessage; @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 #pragma mark - Initialization
/** /**
* Initializes and returns a message object having the given senderId, displayName, text, * Initializes and returns a message object having the given senderId, senderDisplayName, and date.
* 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.
* *
* @param senderId The unique identifier for the user who sent the message. This value must not be `nil`. * @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 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 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`. * @param isMedia A boolean value specifying whether or not the message contains media.
*
* @discussion Initializing a `JSQMessage` with this method will set `isMediaMessage` to `NO`.
* *
* @return An initialized `JSQMessage` object if successful, `nil` otherwise. * @return An initialized `JSQMessage` object if successful, `nil` otherwise.
*/ */
- (instancetype)initWithSenderId:(NSString *)senderId - (instancetype)initWithSenderId:(NSString *)senderId
senderDisplayName:(NSString *)senderDisplayName senderDisplayName:(NSString *)senderDisplayName
date:(NSDate *)date date:(NSDate *)date
text:(NSString *)text; isMedia:(BOOL)isMedia;
/**
* 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;
@end @end

View File

@ -18,70 +18,10 @@
#import "JSQMessage.h" #import "JSQMessage.h"
@interface JSQMessage ()
- (instancetype)initWithSenderId:(NSString *)senderId
senderDisplayName:(NSString *)senderDisplayName
date:(NSDate *)date
isMedia:(BOOL)isMedia;
@end
@implementation JSQMessage @implementation JSQMessage
#pragma mark - Initialization #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 - (instancetype)initWithSenderId:(NSString *)senderId
senderDisplayName:(NSString *)senderDisplayName senderDisplayName:(NSString *)senderDisplayName
date:(NSDate *)date date:(NSDate *)date
@ -97,14 +37,14 @@
_senderDisplayName = [senderDisplayName copy]; _senderDisplayName = [senderDisplayName copy];
_date = [date copy]; _date = [date copy];
_isMediaMessage = isMedia; _isMediaMessage = isMedia;
_messageType = TSGenericTextMessageAdapter;
} }
return self; return self;
} }
- (id)init - (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; return nil;
} }
@ -113,9 +53,6 @@
_senderId = nil; _senderId = nil;
_senderDisplayName = nil; _senderDisplayName = nil;
_date = nil; _date = nil;
_status = kMessageNone;
_text = nil;
_media = nil;
} }
#pragma mark - NSObject #pragma mark - NSObject
@ -132,34 +69,21 @@
JSQMessage *aMessage = (JSQMessage *)object; 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] return [self.senderId isEqualToString:aMessage.senderId]
&& [self.senderDisplayName isEqualToString:aMessage.senderDisplayName] && [self.senderDisplayName isEqualToString:aMessage.senderDisplayName]
&& ([self.date compare:aMessage.date] == NSOrderedSame) && ([self.date compare:aMessage.date] == NSOrderedSame)
&& hasEqualContent; && self.isMediaMessage == aMessage.isMediaMessage;
} }
- (NSUInteger)hash - (NSUInteger)hash
{ {
NSUInteger contentHash = self.isMediaMessage ? self.media.hash : self.text.hash; return self.senderId.hash ^ self.date.hash;
return self.senderId.hash ^ self.date.hash ^ contentHash;
} }
- (NSString *)description - (NSString *)description
{ {
return [NSString stringWithFormat:@"<%@: senderId=%@, senderDisplayName=%@, date=%@, isMediaMessage=%@, text=%@, media=%@>", return [NSString stringWithFormat:@"<%@: senderId=%@, senderDisplayName=%@, date=%@, isMediaMessage=%@>",
[self class], self.senderId, self.senderDisplayName, self.date, @(self.isMediaMessage), self.text, self.media]; [self class], self.senderId, self.senderDisplayName, self.date, @(self.isMediaMessage)];
}
- (id)debugQuickLookObject
{
return [self.media mediaView] ?: [self.media mediaPlaceholderView];
} }
#pragma mark - NSCoding #pragma mark - NSCoding
@ -172,8 +96,6 @@
_senderDisplayName = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(senderDisplayName))]; _senderDisplayName = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(senderDisplayName))];
_date = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(date))]; _date = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(date))];
_isMediaMessage = [aDecoder decodeBoolForKey:NSStringFromSelector(@selector(isMediaMessage))]; _isMediaMessage = [aDecoder decodeBoolForKey:NSStringFromSelector(@selector(isMediaMessage))];
_text = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(text))];
_media = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(media))];
} }
return self; return self;
} }
@ -184,28 +106,16 @@
[aCoder encodeObject:self.senderDisplayName forKey:NSStringFromSelector(@selector(senderDisplayName))]; [aCoder encodeObject:self.senderDisplayName forKey:NSStringFromSelector(@selector(senderDisplayName))];
[aCoder encodeObject:self.date forKey:NSStringFromSelector(@selector(date))]; [aCoder encodeObject:self.date forKey:NSStringFromSelector(@selector(date))];
[aCoder encodeBool:self.isMediaMessage forKey:NSStringFromSelector(@selector(isMediaMessage))]; [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 #pragma mark - NSCopying
- (instancetype)copyWithZone:(NSZone *)zone - (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 return [[[self class] allocWithZone:zone] initWithSenderId:self.senderId
senderDisplayName:self.senderDisplayName senderDisplayName:self.senderDisplayName
date:self.date date:self.date
text:self.text]; isMedia:self.isMediaMessage];
} }
@end @end

View File

@ -20,16 +20,6 @@
#import "JSQMessageMediaData.h" #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 * The `JSQMessageData` protocol defines the common interface through which
* a `JSQMessagesViewController` and `JSQMessagesCollectionView` interact with message model objects. * a `JSQMessagesViewController` and `JSQMessagesCollectionView` interact with message model objects.
@ -71,12 +61,19 @@ typedef NS_ENUM(NSInteger, TSMessageAdapterType) {
*/ */
- (NSDate *)date; - (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 @optional
@ -94,38 +91,4 @@ typedef NS_ENUM(NSInteger, TSMessageAdapterType) {
*/ */
- (id<JSQMessageMediaData>)media; - (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 @end

View File

@ -70,9 +70,4 @@
*/ */
- (UIView *)mediaPlaceholderView; - (UIView *)mediaPlaceholderView;
/**
* @return An integer that can be used as a table address in a hash table structure.
*/
- (NSUInteger)hash;
@end @end

View File

@ -49,7 +49,6 @@
_cachedImageView = nil; _cachedImageView = nil;
} }
#pragma mark - Setters #pragma mark - Setters
- (void)setImage:(UIImage *)image - (void)setImage:(UIImage *)image
@ -87,9 +86,20 @@
#pragma mark - NSObject #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 - (NSUInteger)hash
{ {
return super.hash ^ self.image.hash; return self.image.hash;
} }
- (NSString *)description - (NSString *)description

View 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

View 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

View File

@ -112,7 +112,7 @@
- (NSUInteger)hash - (NSUInteger)hash
{ {
return super.hash ^ self.fileURL.hash; return self.fileURL.hash;
} }
- (NSString *)description - (NSString *)description

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -22,8 +22,6 @@
#import "JSQMessagesCollectionViewDelegateFlowLayout.h" #import "JSQMessagesCollectionViewDelegateFlowLayout.h"
#import "JSQMessagesCollectionViewDataSource.h" #import "JSQMessagesCollectionViewDataSource.h"
#import "JSQMessagesCollectionViewCell.h" #import "JSQMessagesCollectionViewCell.h"
#import "JSQDisplayedMessageCollectionViewCell.h"
@class JSQMessagesTypingIndicatorFooterView; @class JSQMessagesTypingIndicatorFooterView;
@class JSQMessagesLoadEarlierHeaderView; @class JSQMessagesLoadEarlierHeaderView;
@ -33,7 +31,7 @@
* The `JSQMessagesCollectionView` class manages an ordered collection of message data items and presents * The `JSQMessagesCollectionView` class manages an ordered collection of message data items and presents
* them using a specialized layout for messages. * 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. * The object that provides the data for the collection view.

View File

@ -27,7 +27,6 @@
#import "UIColor+JSQMessages.h" #import "UIColor+JSQMessages.h"
#import "JSQCallCollectionViewCell.h"
@interface JSQMessagesCollectionView () <JSQMessagesLoadEarlierHeaderViewDelegate> @interface JSQMessagesCollectionView () <JSQMessagesLoadEarlierHeaderViewDelegate>
@ -68,12 +67,6 @@
[self registerNib:[JSQMessagesLoadEarlierHeaderView nib] [self registerNib:[JSQMessagesLoadEarlierHeaderView nib]
forSupplementaryViewOfKind:UICollectionElementKindSectionHeader forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
withReuseIdentifier:[JSQMessagesLoadEarlierHeaderView headerReuseIdentifier]]; withReuseIdentifier:[JSQMessagesLoadEarlierHeaderView headerReuseIdentifier]];
[self registerNib:[JSQCallCollectionViewCell nib]
forCellWithReuseIdentifier:[JSQCallCollectionViewCell cellReuseIdentifier]];
[self registerNib:[JSQDisplayedMessageCollectionViewCell nib]
forCellWithReuseIdentifier:[JSQDisplayedMessageCollectionViewCell cellReuseIdentifier]];
_typingIndicatorDisplaysOnLeft = YES; _typingIndicatorDisplaysOnLeft = YES;
_typingIndicatorMessageBubbleColor = [UIColor jsq_messageBubbleLightGrayColor]; _typingIndicatorMessageBubbleColor = [UIColor jsq_messageBubbleLightGrayColor];
@ -140,47 +133,21 @@
- (void)messagesCollectionViewCellDidTapAvatar:(JSQMessagesCollectionViewCell *)cell - (void)messagesCollectionViewCellDidTapAvatar:(JSQMessagesCollectionViewCell *)cell
{ {
NSIndexPath *indexPath = [self indexPathForCell:cell];
if (indexPath == nil) {
return;
}
[self.delegate collectionView:self [self.delegate collectionView:self
didTapAvatarImageView:cell.avatarImageView didTapAvatarImageView:cell.avatarImageView
atIndexPath:indexPath]; atIndexPath:[self indexPathForCell:cell]];
} }
- (void)messagesCollectionViewCellDidTapMessageBubble:(JSQMessagesCollectionViewCell *)cell - (void)messagesCollectionViewCellDidTapMessageBubble:(JSQMessagesCollectionViewCell *)cell
{ {
NSIndexPath *indexPath = [self indexPathForCell:cell]; [self.delegate collectionView:self didTapMessageBubbleAtIndexPath:[self indexPathForCell:cell]];
if (indexPath == nil) {
return;
}
[self.delegate collectionView:self didTapMessageBubbleAtIndexPath:indexPath];
} }
- (void)messagesCollectionViewCellDidTapCell:(JSQMessagesCollectionViewCell *)cell atPosition:(CGPoint)position - (void)messagesCollectionViewCellDidTapCell:(JSQMessagesCollectionViewCell *)cell atPosition:(CGPoint)position
{ {
NSIndexPath *indexPath = [self indexPathForCell:cell];
if (indexPath == nil) {
return;
}
[self.delegate collectionView:self [self.delegate collectionView:self
didTapCellAtIndexPath:indexPath didTapCellAtIndexPath:[self indexPathForCell:cell]
touchLocation:position]; touchLocation:position];
} }
- (void)displayedCollectionViewCellDidTapMessage:(JSQDisplayedMessageCollectionViewCell *)cell
{
NSIndexPath * indexPath = [self indexPathForCell:cell];
if (indexPath == nil) {
return;
}
[self.delegate collectionView:self didTapMessageBubbleAtIndexPath:indexPath];
}
@end @end

View File

@ -19,7 +19,6 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "JSQMessagesLabel.h" #import "JSQMessagesLabel.h"
#import "JSQMessagesCellTextView.h"
@class JSQMessagesCollectionViewCell; @class JSQMessagesCollectionViewCell;
@ -103,7 +102,7 @@
* *
* @warning If mediaView returns a non-nil view, then this value will be `nil`. * @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. * Returns the bubble image view of the cell that is responsible for displaying message bubble images.

View File

@ -24,7 +24,6 @@
#import "UIView+JSQMessages.h" #import "UIView+JSQMessages.h"
#import "UIDevice+JSQMessages.h" #import "UIDevice+JSQMessages.h"
#import "UIColor+JSQMessages.h"
@interface JSQMessagesCollectionViewCell () @interface JSQMessagesCollectionViewCell ()
@ -35,13 +34,11 @@
@property (weak, nonatomic) IBOutlet UIView *messageBubbleContainerView; @property (weak, nonatomic) IBOutlet UIView *messageBubbleContainerView;
@property (weak, nonatomic) IBOutlet UIImageView *messageBubbleImageView; @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 UIImageView *avatarImageView;
@property (weak, nonatomic) IBOutlet UIView *avatarContainerView; @property (weak, nonatomic) IBOutlet UIView *avatarContainerView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *messageBubbleContainerWidthConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewTopVerticalSpaceConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewTopVerticalSpaceConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewBottomVerticalSpaceConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewBottomVerticalSpaceConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewAvatarHorizontalSpaceConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewAvatarHorizontalSpaceConstraint;
@ -54,6 +51,8 @@
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *avatarContainerViewWidthConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *avatarContainerViewWidthConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *avatarContainerViewHeightConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *avatarContainerViewHeightConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *messageBubbleLeftRightMarginConstraint;
@property (assign, nonatomic) UIEdgeInsets textViewFrameInsets; @property (assign, nonatomic) UIEdgeInsets textViewFrameInsets;
@property (assign, nonatomic) CGSize avatarViewSize; @property (assign, nonatomic) CGSize avatarViewSize;
@ -94,8 +93,11 @@
[super awakeFromNib]; [super awakeFromNib];
[self setTranslatesAutoresizingMaskIntoConstraints:NO]; [self setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.messageBubbleContainerView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.avatarContainerView setTranslatesAutoresizingMaskIntoConstraints:NO];
self.backgroundColor = [UIColor whiteColor]; self.backgroundColor = [UIColor whiteColor];
self.cellTopLabelHeightConstraint.constant = 0.0f; self.cellTopLabelHeightConstraint.constant = 0.0f;
self.messageBubbleTopLabelHeightConstraint.constant = 0.0f; self.messageBubbleTopLabelHeightConstraint.constant = 0.0f;
self.cellBottomLabelHeightConstraint.constant = 0.0f; self.cellBottomLabelHeightConstraint.constant = 0.0f;
@ -112,6 +114,23 @@
self.cellBottomLabel.font = [UIFont systemFontOfSize:11.0f]; self.cellBottomLabel.font = [UIFont systemFontOfSize:11.0f];
self.cellBottomLabel.textColor = [UIColor lightGrayColor]; 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:)]; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(jsq_handleTapGesture:)];
[self addGestureRecognizer:tap]; [self addGestureRecognizer:tap];
self.tapGestureRecognizer = tap; self.tapGestureRecognizer = tap;
@ -140,7 +159,7 @@
- (void)prepareForReuse - (void)prepareForReuse
{ {
[super prepareForReuse]; [super prepareForReuse];
self.cellTopLabel.text = nil; self.cellTopLabel.text = nil;
self.messageBubbleTopLabel.text = nil; self.messageBubbleTopLabel.text = nil;
self.cellBottomLabel.text = nil; self.cellBottomLabel.text = nil;
@ -168,9 +187,9 @@
} }
self.textViewFrameInsets = customAttributes.textViewFrameInsets; self.textViewFrameInsets = customAttributes.textViewFrameInsets;
[self jsq_updateConstraint:self.messageBubbleContainerWidthConstraint [self jsq_updateConstraint:self.messageBubbleLeftRightMarginConstraint
withConstant:customAttributes.messageBubbleContainerViewWidth]; withConstant:customAttributes.messageBubbleLeftRightMargin];
[self jsq_updateConstraint:self.cellTopLabelHeightConstraint [self jsq_updateConstraint:self.cellTopLabelHeightConstraint
withConstant:customAttributes.cellTopLabelHeight]; withConstant:customAttributes.cellTopLabelHeight];
@ -260,7 +279,7 @@
if ([_mediaView isEqual:mediaView]) { if ([_mediaView isEqual:mediaView]) {
return; return;
} }
[self.messageBubbleImageView removeFromSuperview]; [self.messageBubbleImageView removeFromSuperview];
[self.textView removeFromSuperview]; [self.textView removeFromSuperview];
@ -274,13 +293,11 @@
// because of cell re-use (and caching media views, if using built-in library media item) // 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 // 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 // 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++) {
for (NSUInteger i = 0; i < self.messageBubbleContainerView.subviews.count; i++) { if (self.messageBubbleContainerView.subviews[i] != _mediaView) {
if (self.messageBubbleContainerView.subviews[i] != _mediaView) { [self.messageBubbleContainerView.subviews[i] removeFromSuperview];
[self.messageBubbleContainerView.subviews[i] removeFromSuperview];
}
} }
}); }
} }
#pragma mark - Getters #pragma mark - Getters

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?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> <dependencies>
<deployment identifier="iOS"/> <deployment defaultVersion="1792" identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6244"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
</dependencies> </dependencies>
<objects> <objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> <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"> <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"/> <rect key="frame" x="0.0" y="0.0" width="244" height="94"/>
</imageView> </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"/> <rect key="frame" x="6" y="0.0" width="238" height="94"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/> <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/> <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 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 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 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"/> <constraint firstItem="OCS-Fu-acq" firstAttribute="top" secondItem="btS-p8-B7Z" secondAttribute="top" id="zTa-8g-VY4"/>
</constraints> </constraints>
</view> </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="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="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 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 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"/> <constraint firstItem="UPz-5x-c1T" firstAttribute="top" secondItem="btS-p8-B7Z" secondAttribute="bottom" id="s8G-Je-7GA"/>
</constraints> </constraints>
@ -117,8 +117,8 @@
<outlet property="cellTopLabel" destination="afj-rd-iNv" id="bTd-4q-U7e"/> <outlet property="cellTopLabel" destination="afj-rd-iNv" id="bTd-4q-U7e"/>
<outlet property="cellTopLabelHeightConstraint" destination="fKS-MR-YPI" id="YWd-Rd-qSL"/> <outlet property="cellTopLabelHeightConstraint" destination="fKS-MR-YPI" id="YWd-Rd-qSL"/>
<outlet property="messageBubbleContainerView" destination="btS-p8-B7Z" id="2sk-5p-NEd"/> <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="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="messageBubbleTopLabel" destination="Ufa-bF-l1Y" id="VtH-te-blR"/>
<outlet property="messageBubbleTopLabelHeightConstraint" destination="fal-sy-hrK" id="kgv-NO-Gud"/> <outlet property="messageBubbleTopLabelHeightConstraint" destination="fal-sy-hrK" id="kgv-NO-Gud"/>
<outlet property="textView" destination="KYU-B8-cUW" id="1Yv-ln-EUZ"/> <outlet property="textView" destination="KYU-B8-cUW" id="1Yv-ln-EUZ"/>

View File

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?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> <dependencies>
<deployment identifier="iOS"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6244"/>
</dependencies> </dependencies>
<objects> <objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> <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"> <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"/> <rect key="frame" x="0.0" y="0.0" width="244" height="94"/>
</imageView> </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"/> <rect key="frame" x="0.0" y="0.0" width="238" height="94"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/> <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/> <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 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="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="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"/> <constraint firstAttribute="bottom" secondItem="2qm-c6-OZf" secondAttribute="bottom" id="lts-Ve-wSh"/>
</constraints> </constraints>
</view> </view>
@ -104,6 +102,7 @@
<constraint firstItem="p52-YN-yLu" firstAttribute="top" secondItem="jxM-YD-sVG" secondAttribute="bottom" id="jBD-JV-AWk"/> <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="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="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"/> <constraint firstItem="X89-B1-aAd" firstAttribute="leading" secondItem="2zh-vR-QJW" secondAttribute="trailing" constant="2" id="vMz-Yi-B0w"/>
</constraints> </constraints>
<size key="customSize" width="317" height="245"/> <size key="customSize" width="317" height="245"/>
@ -117,8 +116,8 @@
<outlet property="cellTopLabel" destination="jxM-YD-sVG" id="acH-pr-spx"/> <outlet property="cellTopLabel" destination="jxM-YD-sVG" id="acH-pr-spx"/>
<outlet property="cellTopLabelHeightConstraint" destination="9oK-E7-iXA" id="MZM-kV-2dI"/> <outlet property="cellTopLabelHeightConstraint" destination="9oK-E7-iXA" id="MZM-kV-2dI"/>
<outlet property="messageBubbleContainerView" destination="2zh-vR-QJW" id="pu0-GU-eZl"/> <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="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="messageBubbleTopLabel" destination="p52-YN-yLu" id="SLH-sA-Chu"/>
<outlet property="messageBubbleTopLabelHeightConstraint" destination="8TB-va-f8L" id="FNt-BS-Wxi"/> <outlet property="messageBubbleTopLabelHeightConstraint" destination="8TB-va-f8L" id="FNt-BS-Wxi"/>
<outlet property="textView" destination="vLY-aM-0Dr" id="YEp-mW-xIY"/> <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="textViewMarginHorizontalSpaceConstraint" destination="7rI-Nc-AK3" id="ciu-j6-IpH"/>
<outlet property="textViewTopVerticalSpaceConstraint" destination="RiG-21-Bqc" id="i3j-z0-feE"/> <outlet property="textViewTopVerticalSpaceConstraint" destination="RiG-21-Bqc" id="i3j-z0-feE"/>
</connections> </connections>
<point key="canvasLocation" x="371" y="145"/> <point key="canvasLocation" x="283" y="294"/>
</collectionViewCell> </collectionViewCell>
</objects> </objects>
<simulatedMetricsContainer key="defaultSimulatedMetrics"> <simulatedMetricsContainer key="defaultSimulatedMetrics">

View File

@ -48,22 +48,20 @@
CGFloat cornerRadius = 6.0f; CGFloat cornerRadius = 6.0f;
self.backgroundColor = [UIColor whiteColor]; self.backgroundColor = [UIColor whiteColor];
//Signal: Comment out elements of Composer view self.layer.borderWidth = 0.5f;
// self.layer.borderWidth = 0.5f; self.layer.borderColor = [UIColor lightGrayColor].CGColor;
// self.layer.borderColor = [UIColor lightGrayColor].CGColor; self.layer.cornerRadius = cornerRadius;
// self.layer.cornerRadius = cornerRadius;
self.scrollIndicatorInsets = UIEdgeInsetsMake(cornerRadius, 0.0f, cornerRadius, 0.0f); self.scrollIndicatorInsets = UIEdgeInsetsMake(cornerRadius, 0.0f, cornerRadius, 0.0f);
self.textContainerInset = UIEdgeInsetsMake(4.0f, 2.0f, 4.0f, 2.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.scrollEnabled = YES;
self.scrollsToTop = NO; self.scrollsToTop = NO;
self.userInteractionEnabled = YES; 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.textColor = [UIColor blackColor];
self.textAlignment = NSTextAlignmentNatural; self.textAlignment = NSTextAlignmentNatural;

View File

@ -96,7 +96,7 @@ static void * kJSQMessagesInputToolbarKeyValueObservingContext = &kJSQMessagesIn
- (void)toggleSendButtonEnabled - (void)toggleSendButtonEnabled
{ {
BOOL hasText = [self.contentView.textView hasText]; BOOL hasText = [self.contentView.textView hasText];
if (self.sendButtonOnRight) { if (self.sendButtonOnRight) {
self.contentView.rightBarButtonItem.enabled = hasText; self.contentView.rightBarButtonItem.enabled = hasText;
} }

View File

@ -55,10 +55,6 @@
- (void)setTextInsets:(UIEdgeInsets)textInsets - (void)setTextInsets:(UIEdgeInsets)textInsets
{ {
if (UIEdgeInsetsEqualToEdgeInsets(_textInsets, textInsets)) {
return;
}
_textInsets = textInsets; _textInsets = textInsets;
[self setNeedsDisplay]; [self setNeedsDisplay];
} }

View File

@ -42,61 +42,33 @@ FOUNDATION_EXPORT const CGFloat kJSQMessagesToolbarContentViewHorizontalSpacingD
/** /**
* A custom button item displayed on the left of the toolbar content view. * 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 * @discussion The frame of this button is ignored. When you set this property, the button
* is fitted within a pre-defined default content view, the leftBarButtonContainerView, * is fitted within a pre-defined default content view, whose height is determined by the
* whose height is determined by the height of the toolbar. However, the width of this button * height of the toolbar. You may specify a new width using `leftBarButtonItemWidth`.
* 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.
* Set this value to `nil` to remove the button. * Set this value to `nil` to remove the button.
*/ */
@property (weak, nonatomic) UIButton *leftBarButtonItem; @property (weak, nonatomic) UIButton *leftBarButtonItem;
/** /**
* Specifies the width of the leftBarButtonItem. * Specifies the width of the leftBarButtonItem.
*
* @discussion This property modifies the width of the leftBarButtonContainerView.
*/ */
@property (assign, nonatomic) CGFloat leftBarButtonItemWidth; @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. * 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 * @discussion The frame of this button is ignored. When you set this property, the button
* is fitted within a pre-defined default content view, the rightBarButtonContainerView, * is fitted within a pre-defined default content view, whose height is determined by the
* whose height is determined by the height of the toolbar. However, the width of this button * height of the toolbar. You may specify a new width using `rightBarButtonItemWidth`.
* 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.
* Set this value to `nil` to remove the button. * Set this value to `nil` to remove the button.
*/ */
@property (weak, nonatomic) UIButton *rightBarButtonItem; @property (weak, nonatomic) UIButton *rightBarButtonItem;
/** /**
* Specifies the width of the rightBarButtonItem. * Specifies the width of the rightBarButtonItem.
*
* @discussion This property modifies the width of the rightBarButtonContainerView.
*/ */
@property (assign, nonatomic) CGFloat rightBarButtonItemWidth; @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 #pragma mark - Class methods
/** /**

View File

@ -20,7 +20,7 @@
#import "UIView+JSQMessages.h" #import "UIView+JSQMessages.h"
const CGFloat kJSQMessagesToolbarContentViewHorizontalSpacingDefault = 8.0f; const CGFloat kJSQMessagesToolbarContentViewHorizontalSpacingDefault = 4.0f;
@interface JSQMessagesToolbarContentView () @interface JSQMessagesToolbarContentView ()
@ -113,6 +113,10 @@ const CGFloat kJSQMessagesToolbarContentViewHorizontalSpacingDefault = 8.0f;
- (void)setLeftBarButtonItemWidth:(CGFloat)leftBarButtonItemWidth - (void)setLeftBarButtonItemWidth:(CGFloat)leftBarButtonItemWidth
{ {
self.leftBarButtonItem.frame = CGRectMake(0.0f,
0.0f,
leftBarButtonItemWidth,
CGRectGetHeight(self.leftBarButtonContainerView.frame));
self.leftBarButtonContainerViewWidthConstraint.constant = leftBarButtonItemWidth; self.leftBarButtonContainerViewWidthConstraint.constant = leftBarButtonItemWidth;
[self setNeedsUpdateConstraints]; [self setNeedsUpdateConstraints];
} }
@ -148,6 +152,10 @@ const CGFloat kJSQMessagesToolbarContentViewHorizontalSpacingDefault = 8.0f;
- (void)setRightBarButtonItemWidth:(CGFloat)rightBarButtonItemWidth - (void)setRightBarButtonItemWidth:(CGFloat)rightBarButtonItemWidth
{ {
self.rightBarButtonItem.frame = CGRectMake(0.0f,
0.0f,
rightBarButtonItemWidth,
CGRectGetHeight(self.rightBarButtonContainerView.frame));
self.rightBarButtonContainerViewWidthConstraint.constant = rightBarButtonItemWidth; self.rightBarButtonContainerViewWidthConstraint.constant = rightBarButtonItemWidth;
[self setNeedsUpdateConstraints]; [self setNeedsUpdateConstraints];
} }

View File

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?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> <dependencies>
<deployment identifier="iOS"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6244"/>
</dependencies> </dependencies>
<objects> <objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
@ -12,7 +11,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="LEq-G7-jGt" userLabel="Left button container"> <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"/> <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<constraints> <constraints>
<constraint firstAttribute="height" constant="32" id="0sE-GV-joM"/> <constraint firstAttribute="height" constant="32" id="0sE-GV-joM"/>
@ -20,7 +19,7 @@
</constraints> </constraints>
</view> </view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Myo-1S-Vg1" userLabel="Right button container"> <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"/> <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<constraints> <constraints>
<constraint firstAttribute="height" constant="32" id="NaR-re-dJ4"/> <constraint firstAttribute="height" constant="32" id="NaR-re-dJ4"/>
@ -28,7 +27,7 @@
</constraints> </constraints>
</view> </view>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dm4-NT-mvr" customClass="JSQMessagesComposerTextView"> <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"/> <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/> <fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/> <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
@ -36,14 +35,14 @@
</subviews> </subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints> <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 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="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 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 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="8" id="ds6-61-GNv"/> <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 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> </constraints>
<nil key="simulatedStatusBarMetrics"/> <nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
@ -56,7 +55,7 @@
<outlet property="rightHorizontalSpacingConstraint" destination="ds6-61-GNv" id="ZQh-8M-QFs"/> <outlet property="rightHorizontalSpacingConstraint" destination="ds6-61-GNv" id="ZQh-8M-QFs"/>
<outlet property="textView" destination="dm4-NT-mvr" id="PFw-HO-oT8"/> <outlet property="textView" destination="dm4-NT-mvr" id="PFw-HO-oT8"/>
</connections> </connections>
<point key="canvasLocation" x="268" y="548"/> <point key="canvasLocation" x="174" y="567"/>
</view> </view>
</objects> </objects>
<simulatedMetricsContainer key="defaultSimulatedMetrics"> <simulatedMetricsContainer key="defaultSimulatedMetrics">

View File

@ -10,4 +10,4 @@ SPEC CHECKSUMS:
JSQSystemSoundPlayer: c98443b1cbb3b45db09d0d3d6c2355cf78294981 JSQSystemSoundPlayer: c98443b1cbb3b45db09d0d3d6c2355cf78294981
OCMock: f6cb8c162ab9d5620dddf411282c7b2c0ee78854 OCMock: f6cb8c162ab9d5620dddf411282c7b2c0ee78854
COCOAPODS: 0.35.0 COCOAPODS: 0.34.4

152
README.md
View File

@ -2,9 +2,9 @@
[![Build Status](https://secure.travis-ci.org/jessesquires/JSQMessagesViewController.svg)](http://travis-ci.org/jessesquires/JSQMessagesViewController) [![Version Status](http://img.shields.io/cocoapods/v/JSQMessagesViewController.png)][docsLink] [![license MIT](http://img.shields.io/badge/license-MIT-orange.png)][mitLink] [![Build Status](https://secure.travis-ci.org/jessesquires/JSQMessagesViewController.svg)](http://travis-ci.org/jessesquires/JSQMessagesViewController) [![Version Status](http://img.shields.io/cocoapods/v/JSQMessagesViewController.png)][docsLink] [![license MIT](http://img.shields.io/badge/license-MIT-orange.png)][mitLink]
![Screenshot0][img0] &nbsp;&nbsp; ![Screenshot1][img1] &nbsp;&nbsp; ### Update: 6.0-beta6 is out! See [#476](https://github.com/jessesquires/JSQMessagesViewController/issues/476) for details.
![Screenshot2][img2] &nbsp;&nbsp; ![Screenshot3][img3] ![Messages Screenshot 1][img1] &nbsp;&nbsp;&nbsp; ![Messages Screenshot 2][img2]
> More screenshots available at [CocoaControls](https://www.cocoacontrols.com/controls/jsqmessagesviewcontroller) > 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+ * iOS 7.0+
* ARC * 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 git checkout iOS6_support_stable
```` ````
@ -31,21 +31,11 @@ git checkout iOS6_support_stable
## Installation ## Installation
````ruby ````
# For latest release in cocoapods pod 'JSQMessagesViewController'
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'
```` ````
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:** >**NOTE:**
> >
@ -53,115 +43,35 @@ Otherwise, drag the `JSQMessagesViewController/` folder to your project and inst
> >
>And this pod was formerly named `JSMessagesViewController`. >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 ## Getting Started
````objective-c ````
#import <JSQMessagesViewController/JSQMessages.h> // import all the things #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 fucking sweet demo project: `JSQMessages.xcworkspace`.
* **Demo Project**
* There's a sweet demo project: `JSQMessages.xcworkspace`.
* Run `pod install` first. * Run `pod install` first.
* **Message Model** * **Model**
* Your message model objects should conform to the `JSQMessageData` protocol. * Your model objects should conform to the `JSQMessageData` protocol.
* However, you may use the provided `JSQMessage` class.
* **Media Attachment Model**
* Your media attachment model objects should conform to the `JSQMessageMediaData` protocol. * Your media attachment model objects should conform to the `JSQMessageMediaData` protocol.
* However, you may use the provided classes: `JSQPhotoMediaItem`, `JSQLocationMediaItem`, `JSQVideoMediaItem`. * However, you may use the provided classes:
* Creating your own custom media items is easy! Simply follow the pattern used by the built-in media types. * Model: `JSQTextMessage` and `JSQMediaMessage`
* Also see `JSQMessagesMediaViewBubbleImageMasker` for masking your custom media views as message bubbles. * Media attachments: `JSQPhotoMediaItem`, `JSQLocationMediaItem`, `JSQVideoMediaItem`
* **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.
* **View Controller** * **View Controller**
* Subclass `JSQMessagesViewController`. * Subclass `JSQMessagesViewController`.
* Implement the required methods in the `JSQMessagesCollectionViewDataSource` protocol. * Implement the required methods in the `JSQMessagesCollectionViewDataSource` protocol.
* Implement the required methods in the `JSQMessagesCollectionViewDelegateFlowLayout` 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** * **Customizing**
* The demo project is well-commented. Please use this as a guide. * The demo project is well-commented. This should help you configure your view however you like.
## 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.
## Documentation ## Documentation
@ -173,15 +83,15 @@ Please follow these sweet [contribution guidelines](https://github.com/jessesqui
## Donate ## 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)* >*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=$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> :ramen:</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> :fork_and_knife:</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> :clap:</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> :tada:</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* >*You can also send donations via [PayPal](https://www.paypal.com) to jesse.squires.developer@gmail.com*
## Credits ## 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) * [AwesomeChat](https://github.com/relatedcode/AwesomeChat)
* [ParseChat](https://github.com/relatedcode/ParseChat) * [ParseChat](https://github.com/relatedcode/ParseChat)
* [Jib](http://jibapp.com) * [Jib](http://jibapp.com)
* [Onvolo](https://itunes.apple.com/us/app/onvolo/id869332351)
* [EVCloudKitDao](https://github.com/evermeer/EVCloudKitDao)
* *Your app here* * *Your app here*
## License ## 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 [mitLink]:http://opensource.org/licenses/MIT
[playerLink]:https://github.com/jessesquires/JSQSystemSoundPlayer [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/screenshot0.png
[img1]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot1.png [img2]: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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB