Compare commits
130 Commits
develop-sc
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26fb5cbcf4 | ||
|
|
c8262eee36 | ||
|
|
184f53b07b | ||
|
|
ed9858bd6d | ||
|
|
9dffc05aa7 | ||
|
|
cb5c4facbc | ||
|
|
84d1b659f3 | ||
|
|
b73b5d9983 | ||
|
|
6a30411791 | ||
|
|
395b1342a9 | ||
|
|
ea3b8cc6fc | ||
|
|
697c839c80 | ||
|
|
d6c9dd0ce9 | ||
|
|
16c42a11e5 | ||
|
|
9980266b62 | ||
|
|
38c14c19e7 | ||
|
|
736d110eba | ||
|
|
7c57677738 | ||
|
|
69e2518345 | ||
|
|
3a50f7f9c2 | ||
|
|
6e4857ab8d | ||
|
|
260e51ce2c | ||
|
|
a81bfa2277 | ||
|
|
847f49e6e7 | ||
|
|
8703ce020c | ||
|
|
7d8cd7b867 | ||
|
|
8d9f241038 | ||
|
|
fcbbfdc43f | ||
|
|
66fb14161d | ||
|
|
bc976a04d9 | ||
|
|
4ab13ad7ac | ||
|
|
d5f8d4291b | ||
|
|
43f6e75bbf | ||
|
|
59ea2b6920 | ||
|
|
dee758a3ff | ||
|
|
17153bdd38 | ||
|
|
82482a1fc5 | ||
|
|
442b597c95 | ||
|
|
1bb258691b | ||
|
|
7c2cec63f9 | ||
|
|
91fbb4dce7 | ||
|
|
681b6d329b | ||
|
|
0d8fabe142 | ||
|
|
4049f54789 | ||
|
|
54ae40b07a | ||
|
|
bcf0ac6e1f | ||
|
|
e70cec697f | ||
|
|
7234f10f81 | ||
|
|
fd7f27b74b | ||
|
|
b22b7a4caf | ||
|
|
b8b3fb9122 | ||
|
|
5fc12f5cba | ||
|
|
4cad607ae2 | ||
|
|
276e9f94a6 | ||
|
|
6a04d7585d | ||
|
|
28b17896cc | ||
|
|
8f28bc513e | ||
|
|
512d2a9394 | ||
|
|
81488d5ee6 | ||
|
|
08ebf9b608 | ||
|
|
56f0d40214 | ||
|
|
5d83de37cd | ||
|
|
2626e8419b | ||
|
|
597670e446 | ||
|
|
881ddddeb4 | ||
|
|
32395453ff | ||
|
|
5c6dce5a04 | ||
|
|
3d248e4af0 | ||
|
|
6bbef1949b | ||
|
|
1031a89858 | ||
|
|
21d877492e | ||
|
|
5670accd2c | ||
|
|
d138d4f3a3 | ||
|
|
cddbbf2c75 | ||
|
|
104ba0e023 | ||
|
|
a27fa1091e | ||
|
|
a7a9cd7c64 | ||
|
|
7446b63cbb | ||
|
|
73482f6ace | ||
|
|
2dad6e3036 | ||
|
|
b20af9e524 | ||
|
|
5ba9d2ee09 | ||
|
|
fe0540167b | ||
|
|
45ce02baa6 | ||
|
|
7722bce9d8 | ||
|
|
ea74142adb | ||
|
|
ae9869d7ff | ||
|
|
36b066fbdc | ||
|
|
387a7544b3 | ||
|
|
484a4b59bd | ||
|
|
f6e96e9a07 | ||
|
|
cdc86cc0a3 | ||
|
|
03b74fe77e | ||
|
|
280ff293f1 | ||
|
|
3b8cf0fa35 | ||
|
|
591e9198bb | ||
|
|
0d20dadb8e | ||
|
|
72a4b5b970 | ||
|
|
b291898161 | ||
|
|
5627228464 | ||
|
|
4281751534 | ||
|
|
c81aa93726 | ||
|
|
468e102a7c | ||
|
|
b3a80d9afc | ||
|
|
dbfe58fc6d | ||
|
|
2070cde22d | ||
|
|
e99b127694 | ||
|
|
08a9ec95fa | ||
|
|
0d8667d14e | ||
|
|
5c8dee520c | ||
|
|
42c29ce4a1 | ||
|
|
66a7d47ff3 | ||
|
|
049035cdb6 | ||
|
|
4aedb062cc | ||
|
|
c0edc6f7aa | ||
|
|
9b579e91b9 | ||
|
|
e88501ed61 | ||
|
|
49f2c24533 | ||
|
|
74965225f0 | ||
|
|
99971a8d38 | ||
|
|
da7203dee2 | ||
|
|
88e16ac830 | ||
|
|
41dddfea3a | ||
|
|
ebea4ef0b8 | ||
|
|
f115194efa | ||
|
|
06e7c2bec9 | ||
|
|
6dded2cce9 | ||
|
|
f03bac13a0 | ||
|
|
33b81ca6b0 | ||
|
|
752edc4f0f |
@ -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 */; };
|
||||||
8841B88519F4988800EA16B6 /* JSQMessages.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8841B88719F4988800EA16B6 /* JSQMessages.strings */; };
|
883C11781A09FB100092A16D /* JSQMessagesCellTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 883C11771A09FB100092A16D /* JSQMessagesCellTextView.m */; };
|
||||||
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,18 +51,14 @@
|
|||||||
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 */; };
|
||||||
@ -87,11 +83,10 @@
|
|||||||
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 /* JSQMediaMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF319D8E18400924534 /* JSQMediaMessageTests.m */; };
|
88A2600D19D8E18400924534 /* JSQMessageMediaTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF319D8E18400924534 /* JSQMessageMediaTests.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 /* JSQMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF619D8E18400924534 /* JSQMessageTests.m */; };
|
88A2601019D8E18400924534 /* JSQMessageTextTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25FF619D8E18400924534 /* JSQMessageTextTests.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 */; };
|
||||||
@ -102,8 +97,29 @@
|
|||||||
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 */
|
||||||
@ -124,6 +140,8 @@
|
|||||||
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>"; };
|
||||||
@ -196,8 +214,6 @@
|
|||||||
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>"; };
|
||||||
@ -212,18 +228,14 @@
|
|||||||
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>"; };
|
||||||
@ -257,11 +269,10 @@
|
|||||||
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 /* JSQMediaMessageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMediaMessageTests.m; sourceTree = "<group>"; };
|
88A25FF319D8E18400924534 /* JSQMessageMediaTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessageMediaTests.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 /* JSQMessageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessageTests.m; sourceTree = "<group>"; };
|
88A25FF619D8E18400924534 /* JSQMessageTextTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessageTextTests.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>"; };
|
||||||
@ -273,10 +284,36 @@
|
|||||||
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 */
|
||||||
@ -338,6 +375,7 @@
|
|||||||
88445B3A19E0C0B10014F889 /* XCTest.framework */,
|
88445B3A19E0C0B10014F889 /* XCTest.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
|
path = ../..;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
8841B88219F4983C00EA16B6 /* Strings */ = {
|
8841B88219F4983C00EA16B6 /* Strings */ = {
|
||||||
@ -353,7 +391,6 @@
|
|||||||
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 */,
|
||||||
@ -433,6 +470,8 @@
|
|||||||
88A25F3F19D8E01A00924534 /* Assets */ = {
|
88A25F3F19D8E01A00924534 /* Assets */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
FCA52AFB1A2B9BAD00CCADFA /* InfoError */,
|
||||||
|
FCA52AF01A2B6F8A00CCADFA /* Calls */,
|
||||||
8841B88219F4983C00EA16B6 /* Strings */,
|
8841B88219F4983C00EA16B6 /* Strings */,
|
||||||
8861666C19F492B70025B958 /* JSQMessagesAssets.bundle */,
|
8861666C19F492B70025B958 /* JSQMessagesAssets.bundle */,
|
||||||
);
|
);
|
||||||
@ -507,8 +546,6 @@
|
|||||||
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 */,
|
||||||
@ -523,10 +560,16 @@
|
|||||||
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>";
|
||||||
@ -534,16 +577,19 @@
|
|||||||
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 */,
|
||||||
88A25F9019D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.xib */,
|
FC15B7AE1A1F6AC800F59801 /* JSQMessagesCollectionViewCellIncoming.xib */,
|
||||||
88A25F9119D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.h */,
|
88A25F9119D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.h */,
|
||||||
88A25F9219D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.m */,
|
88A25F9219D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.m */,
|
||||||
88A25F9319D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.xib */,
|
FC15B7AF1A1F6AC800F59801 /* JSQMessagesCollectionViewCellOutgoing.xib */,
|
||||||
88A25F9419D8E01A00924534 /* JSQMessagesComposerTextView.h */,
|
88A25F9419D8E01A00924534 /* JSQMessagesComposerTextView.h */,
|
||||||
88A25F9519D8E01A00924534 /* JSQMessagesComposerTextView.m */,
|
88A25F9519D8E01A00924534 /* JSQMessagesComposerTextView.m */,
|
||||||
88A25F9619D8E01A00924534 /* JSQMessagesInputToolbar.h */,
|
88A25F9619D8E01A00924534 /* JSQMessagesInputToolbar.h */,
|
||||||
@ -561,6 +607,12 @@
|
|||||||
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>";
|
||||||
@ -609,11 +661,13 @@
|
|||||||
88A25FF219D8E18400924534 /* ModelTests */ = {
|
88A25FF219D8E18400924534 /* ModelTests */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
88A25FF319D8E18400924534 /* JSQMediaMessageTests.m */,
|
88C00A4D1A44D4C600B004B3 /* JSQLocationMediaItemTests.m */,
|
||||||
|
88A25FF319D8E18400924534 /* JSQMessageMediaTests.m */,
|
||||||
88A25FF419D8E18400924534 /* JSQMessagesAvatarImageTests.m */,
|
88A25FF419D8E18400924534 /* JSQMessagesAvatarImageTests.m */,
|
||||||
88A25FF519D8E18400924534 /* JSQMessagesBubbleImageTests.m */,
|
88A25FF519D8E18400924534 /* JSQMessagesBubbleImageTests.m */,
|
||||||
88A25FF619D8E18400924534 /* JSQMessageTests.m */,
|
88A25FF619D8E18400924534 /* JSQMessageTextTests.m */,
|
||||||
88A25FF719D8E18400924534 /* JSQTextMessageTests.m */,
|
88C00A4F1A44D4D800B004B3 /* JSQPhotoMediaItemTests.m */,
|
||||||
|
88C00A511A44D4E500B004B3 /* JSQVideoMediaItemTests.m */,
|
||||||
);
|
);
|
||||||
path = ModelTests;
|
path = ModelTests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -633,6 +687,27 @@
|
|||||||
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 */
|
||||||
@ -730,17 +805,26 @@
|
|||||||
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 */,
|
||||||
88A25FCF19D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.xib in Resources */,
|
FC15B7B11A1F6AC800F59801 /* 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;
|
||||||
};
|
};
|
||||||
@ -828,7 +912,9 @@
|
|||||||
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 */,
|
||||||
@ -836,19 +922,23 @@
|
|||||||
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 */,
|
||||||
@ -856,9 +946,8 @@
|
|||||||
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 */,
|
||||||
@ -874,13 +963,14 @@
|
|||||||
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 /* JSQMessageTests.m in Sources */,
|
88A2601019D8E18400924534 /* JSQMessageTextTests.m in Sources */,
|
||||||
88A2600D19D8E18400924534 /* JSQMediaMessageTests.m in Sources */,
|
88A2600D19D8E18400924534 /* JSQMessageMediaTests.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 */,
|
||||||
@ -889,11 +979,12 @@
|
|||||||
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 */,
|
||||||
@ -1030,11 +1121,14 @@
|
|||||||
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;
|
||||||
};
|
};
|
||||||
@ -1045,11 +1139,14 @@
|
|||||||
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;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -45,6 +45,4 @@
|
|||||||
|
|
||||||
- (void)closePressed:(UIBarButtonItem *)sender;
|
- (void)closePressed:(UIBarButtonItem *)sender;
|
||||||
|
|
||||||
// TODO: example of async avatar loading
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -18,6 +18,12 @@
|
|||||||
|
|
||||||
#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
|
||||||
|
|
||||||
@ -43,7 +49,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
|
||||||
@ -68,6 +74,13 @@
|
|||||||
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
|
||||||
@ -95,6 +108,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#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
|
||||||
@ -123,9 +146,9 @@
|
|||||||
JSQMessage *copyMessage = [[self.demoData.messages lastObject] copy];
|
JSQMessage *copyMessage = [[self.demoData.messages lastObject] copy];
|
||||||
|
|
||||||
if (!copyMessage) {
|
if (!copyMessage) {
|
||||||
copyMessage = [JSQTextMessage messageWithSenderId:kJSQDemoAvatarIdJobs
|
copyMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdJobs
|
||||||
displayName:kJSQDemoAvatarDisplayNameJobs
|
displayName:kJSQDemoAvatarDisplayNameJobs
|
||||||
text:@"First received!"];
|
text:@"First received!"];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -141,7 +164,7 @@
|
|||||||
id<JSQMessageMediaData> newMediaData = nil;
|
id<JSQMessageMediaData> newMediaData = nil;
|
||||||
id newMediaAttachmentCopy = nil;
|
id newMediaAttachmentCopy = nil;
|
||||||
|
|
||||||
if ([copyMessage isKindOfClass:[JSQMediaMessage class]]) {
|
if ([copyMessage isKindOfClass:[JSQMessage class]]) {
|
||||||
/**
|
/**
|
||||||
* Last message was a media message
|
* Last message was a media message
|
||||||
*/
|
*/
|
||||||
@ -189,17 +212,17 @@
|
|||||||
NSLog(@"%s error: unrecognized media item", __PRETTY_FUNCTION__);
|
NSLog(@"%s error: unrecognized media item", __PRETTY_FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
newMessage = [JSQMediaMessage messageWithSenderId:randomUserId
|
newMessage = [JSQMessage 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 = [JSQTextMessage messageWithSenderId:randomUserId
|
newMessage = [JSQMessage messageWithSenderId:randomUserId
|
||||||
displayName:self.demoData.users[randomUserId]
|
displayName:self.demoData.users[randomUserId]
|
||||||
text:copyMessage.text];
|
text:copyMessage.text];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -211,10 +234,10 @@
|
|||||||
*/
|
*/
|
||||||
[JSQSystemSoundPlayer jsq_playMessageReceivedSound];
|
[JSQSystemSoundPlayer jsq_playMessageReceivedSound];
|
||||||
[self.demoData.messages addObject:newMessage];
|
[self.demoData.messages addObject:newMessage];
|
||||||
[self finishReceivingMessage];
|
[self finishReceivingMessageAnimated:YES];
|
||||||
|
|
||||||
|
|
||||||
if ([newMessage isKindOfClass:[JSQMediaMessage class]]) {
|
if (newMessage.isMediaMessage) {
|
||||||
/**
|
/**
|
||||||
* Simulate "downloading" media
|
* Simulate "downloading" media
|
||||||
*/
|
*/
|
||||||
@ -276,13 +299,14 @@
|
|||||||
*/
|
*/
|
||||||
[JSQSystemSoundPlayer jsq_playMessageSentSound];
|
[JSQSystemSoundPlayer jsq_playMessageSentSound];
|
||||||
|
|
||||||
JSQTextMessage *message = [[JSQTextMessage alloc] initWithSenderId:senderId
|
JSQMessage *message = [[JSQMessage 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
|
||||||
@ -323,7 +347,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
[JSQSystemSoundPlayer jsq_playMessageSentSound];
|
[JSQSystemSoundPlayer jsq_playMessageSentSound];
|
||||||
[self finishSendingMessage];
|
|
||||||
|
[self finishSendingMessageAnimated:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -349,7 +374,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,6 +402,8 @@
|
|||||||
*/
|
*/
|
||||||
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;
|
||||||
@ -387,8 +414,7 @@
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return [self.demoData.avatars objectForKey:message.senderId];
|
return [self.demoData.avatars objectForKey:message.senderId];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,38 +475,34 @@
|
|||||||
/**
|
/**
|
||||||
* 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:[JSQTextMessage class]]) {
|
if ([msg isKindOfClass:[JSQMessage class]])
|
||||||
|
{
|
||||||
if ([msg.senderId isEqualToString:self.senderId]) {
|
JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
|
||||||
cell.textView.textColor = [UIColor blackColor];
|
if (!msg.isMediaMessage) {
|
||||||
}
|
if ([msg.senderId isEqualToString:self.senderId]) {
|
||||||
else {
|
cell.textView.textColor = [UIColor blackColor];
|
||||||
cell.textView.textColor = [UIColor whiteColor];
|
}
|
||||||
|
else {
|
||||||
|
cell.textView.textColor = [UIColor whiteColor];
|
||||||
|
}
|
||||||
|
|
||||||
|
cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor,
|
||||||
|
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };
|
||||||
}
|
}
|
||||||
|
|
||||||
cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor,
|
return cell;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -502,9 +524,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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,9 @@
|
|||||||
|
|
||||||
#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.
|
||||||
@ -33,7 +36,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];
|
||||||
}
|
}
|
||||||
@ -82,7 +85,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]];
|
||||||
@ -99,35 +102,75 @@
|
|||||||
* 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:
|
||||||
[[JSQTextMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
|
[[JSQCall alloc] initWithCallerId:kJSQDemoAvatarIdWoz
|
||||||
|
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."],
|
||||||
|
|
||||||
[[JSQTextMessage alloc] initWithSenderId:kJSQDemoAvatarIdWoz
|
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
|
||||||
senderDisplayName:kJSQDemoAvatarDisplayNameWoz
|
senderDisplayName:kJSQDemoAvatarDisplayNameSquires
|
||||||
date:[NSDate distantPast]
|
date:[NSDate distantPast]
|
||||||
text:@"It is simple, elegant, and easy to use. There are super sweet default settings, but you can customize like crazy."],
|
text:@"It even has data detectors. You can call me tonight. My cell number is 123-456-7890. My website is www.hexedbits.com."],
|
||||||
|
|
||||||
[[JSQTextMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
|
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdJobs
|
||||||
senderDisplayName:kJSQDemoAvatarDisplayNameSquires
|
senderDisplayName:kJSQDemoAvatarDisplayNameJobs
|
||||||
date:[NSDate distantPast]
|
date:[NSDate date]
|
||||||
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:@"JSQMessagesViewController is nearly an exact replica of the iOS Messages App. And perhaps, better."],
|
||||||
|
|
||||||
[[JSQTextMessage alloc] initWithSenderId:kJSQDemoAvatarIdJobs
|
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdCook
|
||||||
senderDisplayName:kJSQDemoAvatarDisplayNameJobs
|
senderDisplayName:kJSQDemoAvatarDisplayNameCook
|
||||||
date:[NSDate date]
|
date:[NSDate date]
|
||||||
text:@"JSQMessagesViewController is nearly an exact replica of the iOS Messages App. And perhaps, better."],
|
text:@"It is unit-tested, free, open-source, and documented."],
|
||||||
|
|
||||||
[[JSQTextMessage alloc] initWithSenderId:kJSQDemoAvatarIdCook
|
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
|
||||||
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];
|
||||||
@ -148,9 +191,9 @@
|
|||||||
* You should see "END" twice
|
* You should see "END" twice
|
||||||
*/
|
*/
|
||||||
if ([NSUserDefaults longMessageSetting]) {
|
if ([NSUserDefaults longMessageSetting]) {
|
||||||
JSQTextMessage *reallyLongMessage = [JSQTextMessage messageWithSenderId:kJSQDemoAvatarIdSquires
|
JSQMessage *reallyLongMessage = [JSQMessage 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];
|
||||||
}
|
}
|
||||||
@ -159,9 +202,9 @@
|
|||||||
- (void)addPhotoMediaMessage
|
- (void)addPhotoMediaMessage
|
||||||
{
|
{
|
||||||
JSQPhotoMediaItem *photoItem = [[JSQPhotoMediaItem alloc] initWithImage:[UIImage imageNamed:@"goldengate"]];
|
JSQPhotoMediaItem *photoItem = [[JSQPhotoMediaItem alloc] initWithImage:[UIImage imageNamed:@"goldengate"]];
|
||||||
JSQMediaMessage *photoMessage = [JSQMediaMessage messageWithSenderId:kJSQDemoAvatarIdSquires
|
JSQMessage *photoMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires
|
||||||
displayName:kJSQDemoAvatarDisplayNameSquires
|
displayName:kJSQDemoAvatarDisplayNameSquires
|
||||||
media:photoItem];
|
media:photoItem];
|
||||||
[self.messages addObject:photoMessage];
|
[self.messages addObject:photoMessage];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,9 +215,9 @@
|
|||||||
JSQLocationMediaItem *locationItem = [[JSQLocationMediaItem alloc] init];
|
JSQLocationMediaItem *locationItem = [[JSQLocationMediaItem alloc] init];
|
||||||
[locationItem setLocation:ferryBuildingInSF withCompletionHandler:completion];
|
[locationItem setLocation:ferryBuildingInSF withCompletionHandler:completion];
|
||||||
|
|
||||||
JSQMediaMessage *locationMessage = [JSQMediaMessage messageWithSenderId:kJSQDemoAvatarIdSquires
|
JSQMessage *locationMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires
|
||||||
displayName:kJSQDemoAvatarDisplayNameSquires
|
displayName:kJSQDemoAvatarDisplayNameSquires
|
||||||
media:locationItem];
|
media:locationItem];
|
||||||
[self.messages addObject:locationMessage];
|
[self.messages addObject:locationMessage];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,9 +227,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];
|
||||||
JSQMediaMessage *videoMessage = [JSQMediaMessage messageWithSenderId:kJSQDemoAvatarIdSquires
|
JSQMessage *videoMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires
|
||||||
displayName:kJSQDemoAvatarDisplayNameSquires
|
displayName:kJSQDemoAvatarDisplayNameSquires
|
||||||
media:videoItem];
|
media:videoItem];
|
||||||
[self.messages addObject:videoMessage];
|
[self.messages addObject:videoMessage];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,11 +15,11 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>6.0.0</string>
|
<string>6.1.1</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>6.0.0</string>
|
<string>6.1.1</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UILaunchStoryboardName</key>
|
||||||
|
|||||||
BIN
JSQMessagesDemo/call_missed@2x.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
@ -16,56 +16,22 @@
|
|||||||
|
|
||||||
|
|
||||||
@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
|
||||||
|
|||||||
@ -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.messageBubbleLeftRightMargin = 40.0f;
|
attrs.messageBubbleContainerViewWidth = 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);
|
||||||
|
|||||||
64
JSQMessagesTests/ModelTests/JSQLocationMediaItemTests.m
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
//
|
||||||
|
// Created by Jesse Squires
|
||||||
|
// http://www.jessesquires.com
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// MIT License
|
||||||
|
// Copyright (c) 2014 Jesse Squires
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <XCTest/XCTest.h>
|
||||||
|
|
||||||
|
#import "JSQLocationMediaItem.h"
|
||||||
|
|
||||||
|
|
||||||
|
@interface JSQLocationMediaItemTests : XCTestCase
|
||||||
|
|
||||||
|
@property (strong, nonatomic) CLLocation *location;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation JSQLocationMediaItemTests
|
||||||
|
|
||||||
|
- (void)setUp
|
||||||
|
{
|
||||||
|
[super setUp];
|
||||||
|
self.location = [[CLLocation alloc] initWithLatitude:37.795313 longitude:-122.393757];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tearDown
|
||||||
|
{
|
||||||
|
self.location = nil;
|
||||||
|
[super tearDown];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testLocationItemInit
|
||||||
|
{
|
||||||
|
JSQLocationMediaItem *item = [[JSQLocationMediaItem alloc] initWithLocation:self.location];
|
||||||
|
XCTAssertNotNil(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testMediaDataProtocol
|
||||||
|
{
|
||||||
|
JSQLocationMediaItem *item = [[JSQLocationMediaItem alloc] init];
|
||||||
|
|
||||||
|
XCTAssertTrue(!CGSizeEqualToSize([item mediaViewDisplaySize], CGSizeZero));
|
||||||
|
XCTAssertNotNil([item mediaPlaceholderView]);
|
||||||
|
XCTAssertNil([item mediaView], @"Media view should be nil if location is nil");
|
||||||
|
|
||||||
|
XCTestExpectation *expectation = [self expectationWithDescription:[NSString stringWithFormat:@"%s", __PRETTY_FUNCTION__]];
|
||||||
|
|
||||||
|
[item setLocation:self.location withCompletionHandler:^{
|
||||||
|
[expectation fulfill];
|
||||||
|
}];
|
||||||
|
|
||||||
|
[self waitForExpectationsWithTimeout:5 handler:^(NSError *error) {
|
||||||
|
XCTAssertNil(error, @"Expectation should not error");
|
||||||
|
}];
|
||||||
|
|
||||||
|
XCTAssertNotNil([item mediaView], @"Media view should NOT be nil once item has media data");
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
#import <OCMock/OCMock.h>
|
#import <OCMock/OCMock.h>
|
||||||
|
|
||||||
#import "JSQMediaMessage.h"
|
#import "JSQMessage.h"
|
||||||
|
|
||||||
|
|
||||||
// Fake media object for testing
|
// Fake media object for testing
|
||||||
@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@interface JSQMediaMessageTests : XCTestCase
|
@interface JSQMessageMediaTests : 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 JSQMediaMessageTests
|
@implementation JSQMessageMediaTests
|
||||||
|
|
||||||
- (void)setUp
|
- (void)setUp
|
||||||
{
|
{
|
||||||
@ -65,46 +65,46 @@
|
|||||||
[super tearDown];
|
[super tearDown];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testTextMessageInit
|
- (void)testMediaMessageInit
|
||||||
{
|
{
|
||||||
JSQMediaMessage *msg = [[JSQMediaMessage alloc] initWithSenderId:self.senderId
|
JSQMessage *msg = [[JSQMessage 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)testMessageInvalidInit
|
- (void)testMediaMessageInvalidInit
|
||||||
{
|
{
|
||||||
XCTAssertThrows([[JSQMediaMessage alloc] init], @"Invalid init should throw");
|
XCTAssertThrows([[JSQMessage alloc] init], @"Invalid init should throw");
|
||||||
XCTAssertThrows([[JSQMediaMessage alloc] initWithSenderId:nil senderDisplayName:nil date:nil media:nil], @"Invalid init should throw");
|
XCTAssertThrows([[JSQMessage alloc] initWithSenderId:nil senderDisplayName:nil date:nil media:nil], @"Invalid init should throw");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testMessageIsEqual
|
- (void)testMediaMessageIsEqual
|
||||||
{
|
{
|
||||||
JSQMediaMessage *msg = [[JSQMediaMessage alloc] initWithSenderId:self.senderId
|
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId
|
||||||
senderDisplayName:self.senderDisplayName
|
senderDisplayName:self.senderDisplayName
|
||||||
date:self.date
|
date:self.date
|
||||||
media:self.mockMediaData];
|
media:self.mockMediaData];
|
||||||
JSQMediaMessage *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)testMessageArchiving
|
- (void)testMediaMessageArchiving
|
||||||
{
|
{
|
||||||
JSQMediaMessage *msg = [[JSQMediaMessage alloc] initWithSenderId:self.senderId
|
JSQMessage *msg = [[JSQMessage 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];
|
||||||
|
|
||||||
JSQMediaMessage *unarchivedMsg = [NSKeyedUnarchiver unarchiveObjectWithData:msgData];
|
JSQMessage *unarchivedMsg = [NSKeyedUnarchiver unarchiveObjectWithData:msgData];
|
||||||
|
|
||||||
XCTAssertEqualObjects(msg, unarchivedMsg, @"Message should be equal");
|
XCTAssertEqualObjects(msg, unarchivedMsg, @"Message should be equal");
|
||||||
}
|
}
|
||||||
@ -13,23 +13,29 @@
|
|||||||
#import "JSQMessage.h"
|
#import "JSQMessage.h"
|
||||||
|
|
||||||
|
|
||||||
@interface JSQMessageTests : XCTestCase
|
@interface JSQMessageTextTests : 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 JSQMessageTests
|
@implementation JSQMessageTextTests
|
||||||
|
|
||||||
- (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
|
||||||
@ -37,39 +43,48 @@
|
|||||||
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];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testMessageInit
|
#pragma mark - Text messages
|
||||||
|
|
||||||
|
- (void)testTextMessageInit
|
||||||
{
|
{
|
||||||
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId senderDisplayName:self.senderDisplayName date:self.date isMedia:NO];
|
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId
|
||||||
|
senderDisplayName:self.senderDisplayName
|
||||||
|
date:self.date
|
||||||
|
text:self.text];
|
||||||
XCTAssertNotNil(msg, @"Message should not be nil");
|
XCTAssertNotNil(msg, @"Message should not be nil");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testMessageInvalidInit
|
- (void)testTextMessageInvalidInit
|
||||||
{
|
{
|
||||||
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 isMedia:NO], @"Invalid init should throw");
|
XCTAssertThrows([[JSQMessage alloc] initWithSenderId:nil senderDisplayName:nil date:nil text:nil], @"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)testMessageIsEqual
|
- (void)testTextMessageIsEqual
|
||||||
{
|
{
|
||||||
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId senderDisplayName:self.senderDisplayName date:self.date isMedia:NO];
|
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId
|
||||||
|
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)testMessageArchiving
|
- (void)testTextMessageArchiving
|
||||||
{
|
{
|
||||||
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId senderDisplayName:self.senderDisplayName date:self.date isMedia:YES];
|
JSQMessage *msg = [[JSQMessage alloc] initWithSenderId:self.senderId
|
||||||
|
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];
|
||||||
76
JSQMessagesTests/ModelTests/JSQPhotoMediaItemTests.m
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
@ -1,91 +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 "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
|
|
||||||
77
JSQMessagesTests/ModelTests/JSQVideoMediaItemTests.m
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
//
|
||||||
|
// Created by Jesse Squires
|
||||||
|
// http://www.jessesquires.com
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// MIT License
|
||||||
|
// Copyright (c) 2014 Jesse Squires
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <XCTest/XCTest.h>
|
||||||
|
|
||||||
|
#import "JSQVideoMediaItem.h"
|
||||||
|
|
||||||
|
|
||||||
|
@interface JSQVideoMediaItemTests : XCTestCase
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation JSQVideoMediaItemTests
|
||||||
|
|
||||||
|
- (void)setUp
|
||||||
|
{
|
||||||
|
[super setUp];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tearDown
|
||||||
|
{
|
||||||
|
[super tearDown];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testVideoMediaItemInit
|
||||||
|
{
|
||||||
|
JSQVideoMediaItem *item = [[JSQVideoMediaItem alloc] initWithFileURL:[NSURL URLWithString:@"file://"] isReadyToPlay:NO];
|
||||||
|
XCTAssertNotNil(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testVideoItemIsEqual
|
||||||
|
{
|
||||||
|
JSQVideoMediaItem *item = [[JSQVideoMediaItem alloc] initWithFileURL:[NSURL URLWithString:@"file://"] isReadyToPlay:YES];
|
||||||
|
|
||||||
|
JSQVideoMediaItem *copy = [item copy];
|
||||||
|
|
||||||
|
XCTAssertEqualObjects(item, copy, @"Copied items should be equal");
|
||||||
|
|
||||||
|
XCTAssertEqual([item hash], [copy hash], @"Copied item hashes should be equal");
|
||||||
|
|
||||||
|
XCTAssertEqualObjects(item, item, @"Item should be equal to itself");
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testVideoItemArchiving
|
||||||
|
{
|
||||||
|
JSQVideoMediaItem *item = [[JSQVideoMediaItem alloc] initWithFileURL:[NSURL URLWithString:@"file://"] isReadyToPlay:YES];
|
||||||
|
|
||||||
|
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:item];
|
||||||
|
|
||||||
|
JSQVideoMediaItem *unarchivedItem = [NSKeyedUnarchiver unarchiveObjectWithData:data];
|
||||||
|
|
||||||
|
XCTAssertEqualObjects(item, unarchivedItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testMediaDataProtocol
|
||||||
|
{
|
||||||
|
JSQVideoMediaItem *item = [[JSQVideoMediaItem alloc] init];
|
||||||
|
|
||||||
|
XCTAssertTrue(!CGSizeEqualToSize([item mediaViewDisplaySize], CGSizeZero));
|
||||||
|
XCTAssertNotNil([item mediaPlaceholderView]);
|
||||||
|
XCTAssertNil([item mediaView], @"Media view should be nil if fileURL is nil, and readyToPlay is NO");
|
||||||
|
|
||||||
|
item.fileURL = [NSURL URLWithString:@"file://"];
|
||||||
|
item.isReadyToPlay = YES;
|
||||||
|
|
||||||
|
XCTAssertNotNil([item mediaView], @"Media view should NOT be nil once item has media data");
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@ -54,7 +54,7 @@
|
|||||||
XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.textView.scrollIndicatorInsets, UIEdgeInsetsMake(6.0f, 0.0f, 6.0f, 0.0f)), @"Property should be equal to default value");
|
XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.textView.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(2.0f, 0.0f, 2.0f, 0.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");
|
||||||
|
|
||||||
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");
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
Pod::Spec.new do |s|
|
Pod::Spec.new do |s|
|
||||||
s.name = 'JSQMessagesViewController'
|
s.name = 'JSQMessagesViewController'
|
||||||
s.version = '6.0-beta6'
|
s.version = '6.1.1'
|
||||||
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 }
|
||||||
|
|||||||
BIN
JSQMessagesViewController/Assets/call_canceled@2x.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
JSQMessagesViewController/Assets/call_failed@2x.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
JSQMessagesViewController/Assets/call_incoming@2x.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
JSQMessagesViewController/Assets/call_outgoing@2x.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
JSQMessagesViewController/Assets/error_white@2x.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
JSQMessagesViewController/Assets/warning_white@2x.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
@ -32,11 +32,32 @@
|
|||||||
*/
|
*/
|
||||||
+ (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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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.80f
|
brightness:0.84f
|
||||||
alpha:1.0f];
|
alpha:1.0f];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,6 +38,14 @@
|
|||||||
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
|
||||||
@ -46,6 +54,23 @@
|
|||||||
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
|
||||||
|
|||||||
@ -95,4 +95,5 @@
|
|||||||
return [UIImage jsq_bubbleImageFromBundleWithName:@"play"];
|
return [UIImage jsq_bubbleImageFromBundleWithName:@"play"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -59,6 +59,13 @@ 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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -138,14 +138,15 @@ typedef void (^JSQAnimationCompletionBlock)(BOOL finished);
|
|||||||
|
|
||||||
- (void)beginListeningForKeyboard
|
- (void)beginListeningForKeyboard
|
||||||
{
|
{
|
||||||
self.textView.inputAccessoryView = [[UIView alloc] init];
|
if (self.textView.inputAccessoryView == nil) {
|
||||||
|
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];
|
||||||
@ -212,6 +213,8 @@ 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];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -143,6 +143,28 @@
|
|||||||
*/
|
*/
|
||||||
@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.
|
||||||
*
|
*
|
||||||
@ -217,32 +239,46 @@
|
|||||||
- (void)didPressAccessoryButton:(UIButton *)sender;
|
- (void)didPressAccessoryButton:(UIButton *)sender;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Completes the "sending" of a new message by animating and resetting the `inputToolbar`,
|
* Animates the sending of a new message. See `finishSendingMessageAnimated:` for more details.
|
||||||
* 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`.
|
|
||||||
*
|
*
|
||||||
* @discussion You should call this method at the end of `didPressSendButton:withMessage:`
|
* @see `finishSendingMessageAnimated:`.
|
||||||
* 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 "receiving" of a new message by animating the typing indicator,
|
* Completes the "sending" of a new message by resetting the `inputToolbar`, adding a new collection view cell in the collection view,
|
||||||
* 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`.
|
||||||
* reloading the collection view, and scrolling to the newly sent message
|
* Scrolling to the new message can be animated as specified by the animated parameter.
|
||||||
* as specified by `automaticallyScrollsToMostRecentMessage`.
|
|
||||||
*
|
*
|
||||||
* @discussion You should call this method after adding a new "received" message
|
* @param animated Specifies whether the sending of a message should be animated or not. Pass `YES` to animate changes, `NO` otherwise.
|
||||||
* 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`.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -42,11 +42,16 @@
|
|||||||
#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>
|
||||||
|
|
||||||
@ -119,6 +124,7 @@ 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;
|
||||||
|
|
||||||
@ -142,6 +148,10 @@ 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;
|
||||||
@ -203,6 +213,12 @@ 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
|
||||||
@ -284,13 +300,6 @@ 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
|
||||||
@ -302,10 +311,18 @@ 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];
|
||||||
@ -318,19 +335,24 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
|||||||
[self.collectionView reloadData];
|
[self.collectionView reloadData];
|
||||||
|
|
||||||
if (self.automaticallyScrollsToMostRecentMessage) {
|
if (self.automaticallyScrollsToMostRecentMessage) {
|
||||||
[self scrollToBottomAnimated:YES];
|
[self scrollToBottomAnimated:animated];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (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 && ![self jsq_isMenuVisible]) {
|
if (self.automaticallyScrollsToMostRecentMessage) {
|
||||||
[self scrollToBottomAnimated:YES];
|
[self scrollToBottomAnimated:animated];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,11 +364,36 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
|||||||
|
|
||||||
NSInteger items = [self.collectionView numberOfItemsInSection:0];
|
NSInteger items = [self.collectionView numberOfItemsInSection:0];
|
||||||
|
|
||||||
if (items > 0) {
|
if (items == 0) {
|
||||||
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:items - 1 inSection:0]
|
return;
|
||||||
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
|
||||||
@ -405,14 +452,102 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
|||||||
NSParameterAssert(messageSenderId != nil);
|
NSParameterAssert(messageSenderId != nil);
|
||||||
|
|
||||||
BOOL isOutgoingMessage = [messageSenderId isEqualToString:self.senderId];
|
BOOL isOutgoingMessage = [messageSenderId isEqualToString:self.senderId];
|
||||||
BOOL isMediaMessage = [messageItem isMediaMessage];
|
BOOL isCall = [messageItem messageType] == TSCallAdapter;
|
||||||
|
BOOL isInfoMessage = [messageItem messageType] == TSInfoMessageAdapter;
|
||||||
|
BOOL isErrorMessage = [messageItem messageType] == TSErrorMessageAdapter;
|
||||||
|
|
||||||
|
BOOL isMediaMessage = NO;
|
||||||
|
|
||||||
|
if (!isCall && !isInfoMessage && !isErrorMessage )
|
||||||
|
{
|
||||||
|
isMediaMessage = [messageItem isMediaMessage];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
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];
|
||||||
@ -446,8 +581,16 @@ 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];
|
|
||||||
cell.avatarImageView.highlightedImage = [avatarImageDataSource avatarHighlightedImage];
|
UIImage *avatarImage = [avatarImageDataSource avatarImage];
|
||||||
|
if (avatarImage == nil) {
|
||||||
|
cell.avatarImageView.image = [avatarImageDataSource avatarPlaceholderImage];
|
||||||
|
cell.avatarImageView.highlightedImage = nil;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cell.avatarImageView.image = avatarImage;
|
||||||
|
cell.avatarImageView.highlightedImage = [avatarImageDataSource avatarHighlightedImage];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,8 +598,6 @@ 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) {
|
||||||
@ -468,8 +609,8 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
|||||||
|
|
||||||
cell.textView.dataDetectorTypes = UIDataDetectorTypeAll;
|
cell.textView.dataDetectorTypes = UIDataDetectorTypeAll;
|
||||||
|
|
||||||
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
|
|
||||||
cell.layer.shouldRasterize = YES;
|
cell.layer.shouldRasterize = YES;
|
||||||
|
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
|
||||||
|
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
@ -512,8 +653,16 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
|
|||||||
|
|
||||||
- (BOOL)collectionView:(JSQMessagesCollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath
|
- (BOOL)collectionView:(JSQMessagesCollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
// disable menu for media messages
|
// disable menu for media messages, calls, info and error 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;
|
||||||
}
|
}
|
||||||
@ -583,6 +732,8 @@ 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
|
||||||
@ -728,6 +879,10 @@ 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);
|
||||||
@ -735,6 +890,16 @@ 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;
|
||||||
|
|||||||
@ -73,4 +73,7 @@
|
|||||||
*/
|
*/
|
||||||
- (JSQMessagesBubbleImage *)incomingMessagesBubbleImageWithColor:(UIColor *)color;
|
- (JSQMessagesBubbleImage *)incomingMessagesBubbleImageWithColor:(UIColor *)color;
|
||||||
|
|
||||||
|
|
||||||
|
- (JSQMessagesBubbleImage *)outgoingMessageFailedBubbleImageWithColor:(UIColor *)color;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -83,6 +83,11 @@
|
|||||||
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
|
||||||
|
|||||||
@ -27,16 +27,16 @@
|
|||||||
+ (UIButton *)defaultAccessoryButtonItem
|
+ (UIButton *)defaultAccessoryButtonItem
|
||||||
{
|
{
|
||||||
UIImage *accessoryImage = [UIImage jsq_defaultAccessoryImage];
|
UIImage *accessoryImage = [UIImage jsq_defaultAccessoryImage];
|
||||||
UIImage *normalImage = [accessoryImage jsq_imageMaskedWithColor:[UIColor lightGrayColor]];
|
UIImage *normalImage = [accessoryImage jsq_imageMaskedWithColor:[UIColor colorWithRed:0 green:71/255.f blue:1.0f alpha:1.0f]];
|
||||||
UIImage *highlightedImage = [accessoryImage jsq_imageMaskedWithColor:[UIColor darkGrayColor]];
|
UIImage *highlightedImage = [accessoryImage jsq_imageMaskedWithColor:[UIColor darkGrayColor]];
|
||||||
|
|
||||||
UIButton *accessoryButton = [[UIButton alloc] initWithFrame:CGRectZero];
|
UIButton *accessoryButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, accessoryImage.size.width, 32.0f)];
|
||||||
[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,13 +51,25 @@
|
|||||||
[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 boldSystemFontOfSize:17.0f];
|
sendButton.titleLabel.font = [UIFont fontWithName:@"HelveticaNeue-Thin" size: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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -40,8 +40,6 @@
|
|||||||
|
|
||||||
// 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"
|
||||||
|
|||||||
@ -167,6 +167,13 @@ 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.
|
||||||
|
|||||||
@ -33,6 +33,15 @@
|
|||||||
|
|
||||||
#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;
|
||||||
@ -40,7 +49,7 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
|||||||
|
|
||||||
@interface JSQMessagesCollectionViewFlowLayout ()
|
@interface JSQMessagesCollectionViewFlowLayout ()
|
||||||
|
|
||||||
@property (strong, nonatomic) NSMutableDictionary *messageBubbleSizes;
|
@property (strong, nonatomic) NSCache *messageBubbleCache;
|
||||||
|
|
||||||
@property (strong, nonatomic) UIDynamicAnimator *dynamicAnimator;
|
@property (strong, nonatomic) UIDynamicAnimator *dynamicAnimator;
|
||||||
@property (strong, nonatomic) NSMutableSet *visibleIndexPaths;
|
@property (strong, nonatomic) NSMutableSet *visibleIndexPaths;
|
||||||
@ -81,7 +90,9 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
|||||||
|
|
||||||
_bubbleImageAssetWidth = [UIImage jsq_bubbleCompactImage].size.width;
|
_bubbleImageAssetWidth = [UIImage jsq_bubbleCompactImage].size.width;
|
||||||
|
|
||||||
_messageBubbleSizes = [NSMutableDictionary new];
|
_messageBubbleCache = [NSCache new];
|
||||||
|
_messageBubbleCache.name = @"JSQMessagesCollectionViewFlowLayout.messageBubbleCache";
|
||||||
|
_messageBubbleCache.countLimit = 200;
|
||||||
|
|
||||||
_messageBubbleFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
|
_messageBubbleFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
|
||||||
|
|
||||||
@ -89,7 +100,7 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
|||||||
_messageBubbleLeftRightMargin = 240.0f;
|
_messageBubbleLeftRightMargin = 240.0f;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_messageBubbleLeftRightMargin = 40.0f;
|
_messageBubbleLeftRightMargin = 50.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
_messageBubbleTextViewFrameInsets = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 6.0f);
|
_messageBubbleTextViewFrameInsets = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 6.0f);
|
||||||
@ -144,8 +155,8 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
|||||||
|
|
||||||
_messageBubbleFont = nil;
|
_messageBubbleFont = nil;
|
||||||
|
|
||||||
[_messageBubbleSizes removeAllObjects];
|
[_messageBubbleCache removeAllObjects];
|
||||||
_messageBubbleSizes = nil;
|
_messageBubbleCache = nil;
|
||||||
|
|
||||||
[_dynamicAnimator removeAllBehaviors];
|
[_dynamicAnimator removeAllBehaviors];
|
||||||
_dynamicAnimator = nil;
|
_dynamicAnimator = nil;
|
||||||
@ -219,6 +230,11 @@ 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
|
||||||
@ -242,6 +258,11 @@ 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
|
||||||
@ -266,6 +287,10 @@ 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];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,8 +323,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) {
|
||||||
@ -399,7 +424,7 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
|||||||
|
|
||||||
- (void)jsq_resetLayout
|
- (void)jsq_resetLayout
|
||||||
{
|
{
|
||||||
[self.messageBubbleSizes removeAllObjects];
|
[self.messageBubbleCache removeAllObjects];
|
||||||
[self jsq_resetDynamicAnimator];
|
[self jsq_resetDynamicAnimator];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,49 +440,58 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
|
|||||||
|
|
||||||
- (CGSize)messageBubbleSizeForItemAtIndexPath:(NSIndexPath *)indexPath
|
- (CGSize)messageBubbleSizeForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
NSValue *cachedSize = [self.messageBubbleSizes objectForKey:indexPath];
|
id<JSQMessageData> messageItem = [self.collectionView.dataSource collectionView:self.collectionView messageDataForItemAtIndexPath: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 isMediaMessage]) {
|
if (messageItem.messageType != TSCallAdapter && messageItem.messageType != TSErrorMessageAdapter && messageItem.messageType != TSInfoMessageAdapter) {
|
||||||
finalSize = [[messageItem media] mediaViewDisplaySize];
|
if ([messageItem isMediaMessage]) {
|
||||||
}
|
finalSize = [[messageItem media] mediaViewDisplaySize];
|
||||||
else {
|
}
|
||||||
CGSize avatarSize = [self jsq_avatarSizeForIndexPath:indexPath];
|
else {
|
||||||
|
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.messageBubbleSizes setObject:[NSValue valueWithCGSize:finalSize] forKey:indexPath];
|
[self.messageBubbleCache setObject:[NSValue valueWithCGSize:finalSize] forKey:@(messageItem.hash)];
|
||||||
|
|
||||||
return finalSize;
|
return finalSize;
|
||||||
}
|
}
|
||||||
@ -480,11 +514,8 @@ 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;
|
|
||||||
|
|
||||||
CGFloat messageBubblePadding = remainingItemWidthForBubble - messageBubbleSize.width;
|
layoutAttributes.messageBubbleContainerViewWidth = messageBubbleSize.width;
|
||||||
|
|
||||||
layoutAttributes.messageBubbleLeftRightMargin = MAX(messageBubblePadding, 0.0f);
|
|
||||||
|
|
||||||
layoutAttributes.textViewFrameInsets = self.messageBubbleTextViewFrameInsets;
|
layoutAttributes.textViewFrameInsets = self.messageBubbleTextViewFrameInsets;
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,12 @@
|
|||||||
*/
|
*/
|
||||||
@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.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -28,6 +28,7 @@
|
|||||||
if (self) {
|
if (self) {
|
||||||
self.invalidateFlowLayoutDelegateMetrics = NO;
|
self.invalidateFlowLayoutDelegateMetrics = NO;
|
||||||
self.invalidateFlowLayoutAttributes = NO;
|
self.invalidateFlowLayoutAttributes = NO;
|
||||||
|
_emptyCache = NO;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -44,11 +45,8 @@
|
|||||||
|
|
||||||
- (NSString *)description
|
- (NSString *)description
|
||||||
{
|
{
|
||||||
return [NSString stringWithFormat:@"<%@: invalidateFlowLayoutDelegateMetrics=%d, invalidateFlowLayoutAttributes=%d, invalidateDataSourceCounts=%d>",
|
return [NSString stringWithFormat:@"<%@: invalidateFlowLayoutDelegateMetrics=%@, invalidateFlowLayoutAttributes=%@, invalidateDataSourceCounts=%@, emptyCache=%@>",
|
||||||
[self class],
|
[self class], @(self.invalidateFlowLayoutDelegateMetrics), @(self.invalidateFlowLayoutAttributes), @(self.invalidateDataSourceCounts), @(self.emptyCache)];
|
||||||
self.invalidateFlowLayoutDelegateMetrics,
|
|
||||||
self.invalidateFlowLayoutAttributes,
|
|
||||||
self.invalidateDataSourceCounts];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -31,16 +31,12 @@
|
|||||||
@property (strong, nonatomic) UIFont *messageBubbleFont;
|
@property (strong, nonatomic) UIFont *messageBubbleFont;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The horizontal spacing between the message bubble and the edge of the collection
|
* The width of the `messageBubbleContainerView` of a `JSQMessagesCollectionViewCell`.
|
||||||
* view cell in which it is displayed. This value should be greater than or equal to `0.0`.
|
* This value should be greater than `0.0`.
|
||||||
*
|
*
|
||||||
* @discussion For *outgoing* messages, this value specifies the amount of spacing from the left most edge
|
* @see JSQMessagesCollectionViewCell.
|
||||||
* 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 messageBubbleLeftRightMargin;
|
@property (assign, nonatomic) CGFloat messageBubbleContainerViewWidth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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`.
|
||||||
|
|||||||
@ -45,10 +45,10 @@
|
|||||||
_messageBubbleFont = messageBubbleFont;
|
_messageBubbleFont = messageBubbleFont;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMessageBubbleLeftRightMargin:(CGFloat)messageBubbleLeftRightMargin
|
- (void)setMessageBubbleContainerViewWidth:(CGFloat)messageBubbleContainerViewWidth
|
||||||
{
|
{
|
||||||
NSParameterAssert(messageBubbleLeftRightMargin >= 0.0f);
|
NSParameterAssert(messageBubbleContainerViewWidth > 0.0f);
|
||||||
_messageBubbleLeftRightMargin = ceilf(messageBubbleLeftRightMargin);
|
_messageBubbleContainerViewWidth = ceilf(messageBubbleContainerViewWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (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.messageBubbleLeftRightMargin != (int)self.messageBubbleLeftRightMargin
|
|| (int)layoutAttributes.messageBubbleContainerViewWidth != (int)self.messageBubbleContainerViewWidth
|
||||||
|| (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.messageBubbleLeftRightMargin = self.messageBubbleLeftRightMargin;
|
copy.messageBubbleContainerViewWidth = self.messageBubbleContainerViewWidth;
|
||||||
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,6 +156,7 @@
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
70
JSQMessagesViewController/Model/JSQCall.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
171
JSQMessagesViewController/Model/JSQCall.m
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
44
JSQMessagesViewController/Model/JSQDisplayedMessage.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
35
JSQMessagesViewController/Model/JSQDisplayedMessage.m
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
36
JSQMessagesViewController/Model/JSQErrorMessage.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
75
JSQMessagesViewController/Model/JSQErrorMessage.m
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
31
JSQMessagesViewController/Model/JSQInfoMessage.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
54
JSQMessagesViewController/Model/JSQInfoMessage.m
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
//
|
||||||
|
// JSQInfoMessage.m
|
||||||
|
// JSQMessages
|
||||||
|
//
|
||||||
|
// Created by Dylan Bourgeois on 29/11/14.
|
||||||
|
// Copyright (c) 2014 Hexed Bits. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "JSQInfoMessage.h"
|
||||||
|
|
||||||
|
@implementation JSQInfoMessage
|
||||||
|
|
||||||
|
- (instancetype)initWithInfoType:(JSQInfoMessageType)messageType
|
||||||
|
senderId:(NSString *)senderId
|
||||||
|
senderDisplayName:(NSString *)senderDisplayName
|
||||||
|
date:(NSDate *)date
|
||||||
|
{
|
||||||
|
//@discussion: NSParameterAssert() ?
|
||||||
|
|
||||||
|
self = [super initWithSenderId:senderId senderDisplayName:senderDisplayName date:date];
|
||||||
|
|
||||||
|
if (self) {
|
||||||
|
_infoMessageType = messageType;
|
||||||
|
_messageType = TSInfoMessageAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(NSString*)text
|
||||||
|
{
|
||||||
|
switch (self.infoMessageType) {
|
||||||
|
case JSQInfoMessageTypeSessionDidEnd:
|
||||||
|
return [NSString stringWithFormat:@"Session with %@ ended.", self.senderDisplayName];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(NSUInteger)hash
|
||||||
|
{
|
||||||
|
return self.senderId.hash ^ self.date.hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(NSString*)description
|
||||||
|
{
|
||||||
|
return [NSString stringWithFormat:@"<%@: senderId=%@, senderDisplayName=%@, date=%@, type=%ld>",
|
||||||
|
[self class], self.senderId, self.senderDisplayName, self.date, self.infoMessageType];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@ -170,7 +170,7 @@
|
|||||||
|
|
||||||
- (NSUInteger)hash
|
- (NSUInteger)hash
|
||||||
{
|
{
|
||||||
return self.location.hash;
|
return super.hash ^ self.location.hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)description
|
- (NSString *)description
|
||||||
|
|||||||
@ -1,62 +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 "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
|
|
||||||
@ -1,114 +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 "JSQMediaMessage.h"
|
|
||||||
|
|
||||||
@implementation JSQMediaMessage
|
|
||||||
|
|
||||||
#pragma mark - Initialization
|
|
||||||
|
|
||||||
+ (instancetype)messageWithSenderId:(NSString *)senderId
|
|
||||||
displayName:(NSString *)displayName
|
|
||||||
media:(id<JSQMessageMediaData>)media
|
|
||||||
{
|
|
||||||
return [[JSQMediaMessage alloc] initWithSenderId:senderId
|
|
||||||
senderDisplayName:displayName
|
|
||||||
date:[NSDate date]
|
|
||||||
media:media];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithSenderId:(NSString *)senderId
|
|
||||||
senderDisplayName:(NSString *)senderDisplayName
|
|
||||||
date:(NSDate *)date
|
|
||||||
media:(id<JSQMessageMediaData>)media
|
|
||||||
{
|
|
||||||
NSParameterAssert(media != nil);
|
|
||||||
|
|
||||||
self = [super initWithSenderId:senderId senderDisplayName:senderDisplayName date:date isMedia:YES];
|
|
||||||
if (self) {
|
|
||||||
_media = media;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)init
|
|
||||||
{
|
|
||||||
NSAssert(NO, @"%s is not a valid initializer for %@. Use %@ instead.",
|
|
||||||
__PRETTY_FUNCTION__, [self class], NSStringFromSelector(@selector(initWithSenderId:senderDisplayName:date:media:)));
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)dealloc
|
|
||||||
{
|
|
||||||
_media = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - NSObject
|
|
||||||
|
|
||||||
- (BOOL)isEqual:(id)object
|
|
||||||
{
|
|
||||||
if (![super isEqual:object]) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSQMediaMessage *mediaMessage = (JSQMediaMessage *)object;
|
|
||||||
|
|
||||||
return [self.media isEqual:mediaMessage.media];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)description
|
|
||||||
{
|
|
||||||
return [NSString stringWithFormat:@"<%@: senderId=%@, senderDisplayName=%@, date=%@, isMediaMessage=%@, media=%@>",
|
|
||||||
[self class], self.senderId, self.senderDisplayName, self.date, @(self.isMediaMessage), self.media];
|
|
||||||
}
|
|
||||||
- (id)debugQuickLookObject
|
|
||||||
{
|
|
||||||
return [self.media mediaView] ?: [self.media mediaPlaceholderView];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - NSCoding
|
|
||||||
|
|
||||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
|
||||||
{
|
|
||||||
self = [super initWithCoder:aDecoder];
|
|
||||||
if (self) {
|
|
||||||
_media = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(media))];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
|
||||||
{
|
|
||||||
[super encodeWithCoder:aCoder];
|
|
||||||
|
|
||||||
if ([self.media conformsToProtocol:@protocol(NSCoding)]) {
|
|
||||||
[aCoder encodeObject:self.media forKey:NSStringFromSelector(@selector(media))];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - NSCopying
|
|
||||||
|
|
||||||
- (instancetype)copyWithZone:(NSZone *)zone
|
|
||||||
{
|
|
||||||
return [[[self class] allocWithZone:zone] initWithSenderId:self.senderId
|
|
||||||
senderDisplayName:self.senderDisplayName
|
|
||||||
date:self.date
|
|
||||||
media:self.media];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -20,14 +20,21 @@
|
|||||||
|
|
||||||
#import "JSQMessageData.h"
|
#import "JSQMessageData.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum : NSUInteger {
|
||||||
|
kMessageNone,
|
||||||
|
kMessageSent,
|
||||||
|
kMessageRead,
|
||||||
|
kMessageReceived,
|
||||||
|
kMesageFailed
|
||||||
|
} MessageStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The `JSQMessage` class is an abstract base class for message model objects that represents a single user message.
|
* The `JSQMessage` class is a concrete class for message model objects that represents a single user message.
|
||||||
* It contains the senderId, senderDisplayName, and the date that the message was sent.
|
* The message can be a text message or media message, depending on how it is initialized.
|
||||||
*
|
* It implements the `JSQMessageData` protocol and it contains the senderId, senderDisplayName,
|
||||||
* @warning This class is intended to be subclassed. You should not use it directly.
|
* and the date that the message was sent. If initialized as a media message it also contains a media attachment,
|
||||||
*
|
* otherwise it contains the message text.
|
||||||
* @see JSQTextMessage.
|
|
||||||
* @see JSQMediaMessage.
|
|
||||||
*/
|
*/
|
||||||
@interface JSQMessage : NSObject <JSQMessageData, NSCoding, NSCopying>
|
@interface JSQMessage : NSObject <JSQMessageData, NSCoding, NSCopying>
|
||||||
|
|
||||||
@ -48,25 +55,94 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a boolean value specifying whether or not the message contains media.
|
* Returns a boolean value specifying whether or not the message contains media.
|
||||||
* The default value is `NO`, meaning that is message contains text, not media.
|
* If `NO`, the message contains text. If `YES`, the message contains media.
|
||||||
|
* The value of this property depends on how the object was initialized.
|
||||||
*/
|
*/
|
||||||
@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, senderDisplayName, and date.
|
* Initializes and returns a message object having the given senderId, displayName, text,
|
||||||
|
* and current system date.
|
||||||
|
*
|
||||||
|
* @param senderId The unique identifier for the user who sent the message. This value must not be `nil`.
|
||||||
|
* @param displayName The display name for the user who sent the message. This value must not be `nil`.
|
||||||
|
* @param text The body text of the message. This value must not be `nil`.
|
||||||
|
*
|
||||||
|
* @discussion Initializing a `JSQMessage` with this method will set `isMediaMessage` to `NO`.
|
||||||
|
*
|
||||||
|
* @return An initialized `JSQMessage` object if successful, `nil` otherwise.
|
||||||
|
*/
|
||||||
|
+ (instancetype)messageWithSenderId:(NSString *)senderId
|
||||||
|
displayName:(NSString *)displayName
|
||||||
|
text:(NSString *)text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes and returns a message object having the given senderId, senderDisplayName, date, and text.
|
||||||
*
|
*
|
||||||
* @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 isMedia A boolean value specifying whether or not the message contains media.
|
* @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.
|
* @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
|
||||||
isMedia:(BOOL)isMedia;
|
text:(NSString *)text;
|
||||||
|
/**
|
||||||
|
* Initializes and returns a message object having the given senderId, displayName, media,
|
||||||
|
* and current system date.
|
||||||
|
*
|
||||||
|
* @param senderId The unique identifier for the user who sent the message. This value must not be `nil`.
|
||||||
|
* @param displayName The display name for the user who sent the message. This value must not be `nil`.
|
||||||
|
* @param media The media data for the message. This value must not be `nil`.
|
||||||
|
*
|
||||||
|
* @discussion Initializing a `JSQMessage` with this method will set `isMediaMessage` to `YES`.
|
||||||
|
*
|
||||||
|
* @return An initialized `JSQMessage` object if successful, `nil` otherwise.
|
||||||
|
*/
|
||||||
|
+ (instancetype)messageWithSenderId:(NSString *)senderId
|
||||||
|
displayName:(NSString *)displayName
|
||||||
|
media:(id<JSQMessageMediaData>)media;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes and returns a message object having the given senderId, displayName, date, and media.
|
||||||
|
*
|
||||||
|
* @param senderId The unique identifier for the user who sent the message. This value must not be `nil`.
|
||||||
|
* @param senderDisplayName The display name for the user who sent the message. This value must not be `nil`.
|
||||||
|
* @param date The date that the message was sent. This value must not be `nil`.
|
||||||
|
* @param media The media data for the message. This value must not be `nil`.
|
||||||
|
*
|
||||||
|
* @discussion Initializing a `JSQMessage` with this method will set `isMediaMessage` to `YES`.
|
||||||
|
*
|
||||||
|
* @return An initialized `JSQMessage` object if successful, `nil` otherwise.
|
||||||
|
*/
|
||||||
|
- (instancetype)initWithSenderId:(NSString *)senderId
|
||||||
|
senderDisplayName:(NSString *)senderDisplayName
|
||||||
|
date:(NSDate *)date
|
||||||
|
media:(id<JSQMessageMediaData>)media;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -18,10 +18,70 @@
|
|||||||
|
|
||||||
#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
|
||||||
@ -37,14 +97,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 %@. Use %@ instead.",
|
NSAssert(NO, @"%s is not a valid initializer for %@.", __PRETTY_FUNCTION__, [self class]);
|
||||||
__PRETTY_FUNCTION__, [self class], NSStringFromSelector(@selector(initWithSenderId:senderDisplayName:date:isMedia:)));
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +113,9 @@
|
|||||||
_senderId = nil;
|
_senderId = nil;
|
||||||
_senderDisplayName = nil;
|
_senderDisplayName = nil;
|
||||||
_date = nil;
|
_date = nil;
|
||||||
|
_status = kMessageNone;
|
||||||
|
_text = nil;
|
||||||
|
_media = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - NSObject
|
#pragma mark - NSObject
|
||||||
@ -69,21 +132,34 @@
|
|||||||
|
|
||||||
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)
|
||||||
&& self.isMediaMessage == aMessage.isMediaMessage;
|
&& hasEqualContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSUInteger)hash
|
- (NSUInteger)hash
|
||||||
{
|
{
|
||||||
return self.senderId.hash ^ self.date.hash;
|
NSUInteger contentHash = self.isMediaMessage ? self.media.hash : self.text.hash;
|
||||||
|
|
||||||
|
return self.senderId.hash ^ self.date.hash ^ contentHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)description
|
- (NSString *)description
|
||||||
{
|
{
|
||||||
return [NSString stringWithFormat:@"<%@: senderId=%@, senderDisplayName=%@, date=%@, isMediaMessage=%@>",
|
return [NSString stringWithFormat:@"<%@: senderId=%@, senderDisplayName=%@, date=%@, isMediaMessage=%@, text=%@, media=%@>",
|
||||||
[self class], self.senderId, self.senderDisplayName, self.date, @(self.isMediaMessage)];
|
[self class], self.senderId, self.senderDisplayName, self.date, @(self.isMediaMessage), self.text, self.media];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)debugQuickLookObject
|
||||||
|
{
|
||||||
|
return [self.media mediaView] ?: [self.media mediaPlaceholderView];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - NSCoding
|
#pragma mark - NSCoding
|
||||||
@ -96,6 +172,8 @@
|
|||||||
_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;
|
||||||
}
|
}
|
||||||
@ -106,16 +184,28 @@
|
|||||||
[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
|
||||||
isMedia:self.isMediaMessage];
|
text:self.text];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -20,6 +20,16 @@
|
|||||||
|
|
||||||
#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.
|
||||||
@ -61,19 +71,12 @@
|
|||||||
*/
|
*/
|
||||||
- (NSDate *)date;
|
- (NSDate *)date;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is used to determine if the message data item contains text or media.
|
* @return An integer that can be used as a table address in a hash table structure.
|
||||||
* 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;
|
- (NSUInteger)hash;
|
||||||
|
|
||||||
@optional
|
@optional
|
||||||
|
|
||||||
@ -91,4 +94,38 @@
|
|||||||
*/
|
*/
|
||||||
- (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
|
||||||
|
|||||||
@ -70,4 +70,9 @@
|
|||||||
*/
|
*/
|
||||||
- (UIView *)mediaPlaceholderView;
|
- (UIView *)mediaPlaceholderView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return An integer that can be used as a table address in a hash table structure.
|
||||||
|
*/
|
||||||
|
- (NSUInteger)hash;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -49,6 +49,7 @@
|
|||||||
_cachedImageView = nil;
|
_cachedImageView = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - Setters
|
#pragma mark - Setters
|
||||||
|
|
||||||
- (void)setImage:(UIImage *)image
|
- (void)setImage:(UIImage *)image
|
||||||
@ -86,20 +87,9 @@
|
|||||||
|
|
||||||
#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 self.image.hash;
|
return super.hash ^ self.image.hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)description
|
- (NSString *)description
|
||||||
|
|||||||
@ -1,62 +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 "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
|
|
||||||
@ -1,107 +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 "JSQTextMessage.h"
|
|
||||||
|
|
||||||
@implementation JSQTextMessage
|
|
||||||
|
|
||||||
#pragma mark - Initialization
|
|
||||||
|
|
||||||
+ (instancetype)messageWithSenderId:(NSString *)senderId
|
|
||||||
displayName:(NSString *)displayName
|
|
||||||
text:(NSString *)text
|
|
||||||
{
|
|
||||||
return [[JSQTextMessage alloc] initWithSenderId:senderId
|
|
||||||
senderDisplayName:displayName
|
|
||||||
date:[NSDate date]
|
|
||||||
text:text];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithSenderId:(NSString *)senderId
|
|
||||||
senderDisplayName:(NSString *)senderDisplayName
|
|
||||||
date:(NSDate *)date
|
|
||||||
text:(NSString *)text
|
|
||||||
{
|
|
||||||
NSParameterAssert(text != nil);
|
|
||||||
|
|
||||||
self = [super initWithSenderId:senderId senderDisplayName:senderDisplayName date:date isMedia:NO];
|
|
||||||
if (self) {
|
|
||||||
_text = [text copy];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)init
|
|
||||||
{
|
|
||||||
NSAssert(NO, @"%s is not a valid initializer for %@. Use %@ instead.",
|
|
||||||
__PRETTY_FUNCTION__, [self class], NSStringFromSelector(@selector(initWithSenderId:senderDisplayName:date:text:)));
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)dealloc
|
|
||||||
{
|
|
||||||
_text = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - NSObject
|
|
||||||
|
|
||||||
- (BOOL)isEqual:(id)object
|
|
||||||
{
|
|
||||||
if (![super isEqual:object]) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSQTextMessage *textMessage = (JSQTextMessage *)object;
|
|
||||||
|
|
||||||
return [self.text isEqualToString:textMessage.text];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)description
|
|
||||||
{
|
|
||||||
return [NSString stringWithFormat:@"<%@: senderId=%@, senderDisplayName=%@, date=%@, isMediaMessage=%@, text=%@>",
|
|
||||||
[self class], self.senderId, self.senderDisplayName, self.date, @(self.isMediaMessage), self.text];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - NSCoding
|
|
||||||
|
|
||||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
|
||||||
{
|
|
||||||
self = [super initWithCoder:aDecoder];
|
|
||||||
if (self) {
|
|
||||||
_text = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(text))];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
|
||||||
{
|
|
||||||
[super encodeWithCoder:aCoder];
|
|
||||||
[aCoder encodeObject:self.text forKey:NSStringFromSelector(@selector(text))];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - NSCopying
|
|
||||||
|
|
||||||
- (instancetype)copyWithZone:(NSZone *)zone
|
|
||||||
{
|
|
||||||
return [[[self class] allocWithZone:zone] initWithSenderId:self.senderId
|
|
||||||
senderDisplayName:self.senderDisplayName
|
|
||||||
date:self.date
|
|
||||||
text:self.text];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -112,7 +112,7 @@
|
|||||||
|
|
||||||
- (NSUInteger)hash
|
- (NSUInteger)hash
|
||||||
{
|
{
|
||||||
return self.fileURL.hash;
|
return super.hash ^ self.fileURL.hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)description
|
- (NSString *)description
|
||||||
|
|||||||
30
JSQMessagesViewController/Views/JSQCallCollectionViewCell.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
95
JSQMessagesViewController/Views/JSQCallCollectionViewCell.m
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
<?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>
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
@ -0,0 +1,125 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
<?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>
|
||||||
27
JSQMessagesViewController/Views/JSQMessagesCellTextView.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
77
JSQMessagesViewController/Views/JSQMessagesCellTextView.m
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
//
|
||||||
|
// Created by Jesse Squires
|
||||||
|
// http://www.jessesquires.com
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Documentation
|
||||||
|
// http://cocoadocs.org/docsets/JSQMessagesViewController
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// GitHub
|
||||||
|
// https://github.com/jessesquires/JSQMessagesViewController
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// License
|
||||||
|
// Copyright (c) 2014 Jesse Squires
|
||||||
|
// Released under an MIT license: http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "JSQMessagesCellTextView.h"
|
||||||
|
|
||||||
|
@implementation JSQMessagesCellTextView
|
||||||
|
|
||||||
|
- (void)awakeFromNib
|
||||||
|
{
|
||||||
|
[super awakeFromNib];
|
||||||
|
|
||||||
|
self.textColor = [UIColor whiteColor];
|
||||||
|
self.editable = NO;
|
||||||
|
self.selectable = YES;
|
||||||
|
self.userInteractionEnabled = YES;
|
||||||
|
self.dataDetectorTypes = UIDataDetectorTypeNone;
|
||||||
|
self.showsHorizontalScrollIndicator = NO;
|
||||||
|
self.showsVerticalScrollIndicator = NO;
|
||||||
|
self.scrollEnabled = NO;
|
||||||
|
self.backgroundColor = [UIColor clearColor];
|
||||||
|
self.contentInset = UIEdgeInsetsZero;
|
||||||
|
self.scrollIndicatorInsets = UIEdgeInsetsZero;
|
||||||
|
self.contentOffset = CGPointZero;
|
||||||
|
self.textContainerInset = UIEdgeInsetsZero;
|
||||||
|
self.textContainer.lineFragmentPadding = 0;
|
||||||
|
self.linkTextAttributes = @{ NSForegroundColorAttributeName : [UIColor whiteColor],
|
||||||
|
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setSelectedRange:(NSRange)selectedRange
|
||||||
|
{
|
||||||
|
// prevent selecting text
|
||||||
|
[super setSelectedRange:NSMakeRange(NSNotFound, 0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
|
||||||
|
{
|
||||||
|
// ignore double-tap to prevent copy/define/etc. menu from showing
|
||||||
|
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
|
||||||
|
UITapGestureRecognizer *tap = (UITapGestureRecognizer *)gestureRecognizer;
|
||||||
|
if (tap.numberOfTapsRequired == 2) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
|
||||||
|
{
|
||||||
|
// ignore double-tap to prevent copy/define/etc. menu from showing
|
||||||
|
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
|
||||||
|
UITapGestureRecognizer *tap = (UITapGestureRecognizer *)gestureRecognizer;
|
||||||
|
if (tap.numberOfTapsRequired == 2) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@ -22,6 +22,8 @@
|
|||||||
#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;
|
||||||
@ -31,7 +33,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>
|
@interface JSQMessagesCollectionView : UICollectionView <JSQMessagesCollectionViewCellDelegate, JSQDisplayedCollectionViewCellDelegate>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The object that provides the data for the collection view.
|
* The object that provides the data for the collection view.
|
||||||
|
|||||||
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#import "UIColor+JSQMessages.h"
|
#import "UIColor+JSQMessages.h"
|
||||||
|
|
||||||
|
#import "JSQCallCollectionViewCell.h"
|
||||||
|
|
||||||
@interface JSQMessagesCollectionView () <JSQMessagesLoadEarlierHeaderViewDelegate>
|
@interface JSQMessagesCollectionView () <JSQMessagesLoadEarlierHeaderViewDelegate>
|
||||||
|
|
||||||
@ -67,6 +68,12 @@
|
|||||||
[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];
|
||||||
@ -133,21 +140,47 @@
|
|||||||
|
|
||||||
- (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:[self indexPathForCell:cell]];
|
atIndexPath:indexPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)messagesCollectionViewCellDidTapMessageBubble:(JSQMessagesCollectionViewCell *)cell
|
- (void)messagesCollectionViewCellDidTapMessageBubble:(JSQMessagesCollectionViewCell *)cell
|
||||||
{
|
{
|
||||||
[self.delegate collectionView:self didTapMessageBubbleAtIndexPath:[self indexPathForCell:cell]];
|
NSIndexPath *indexPath = [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:[self indexPathForCell:cell]
|
didTapCellAtIndexPath:indexPath
|
||||||
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
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
#import "JSQMessagesLabel.h"
|
#import "JSQMessagesLabel.h"
|
||||||
|
#import "JSQMessagesCellTextView.h"
|
||||||
|
|
||||||
@class JSQMessagesCollectionViewCell;
|
@class JSQMessagesCollectionViewCell;
|
||||||
|
|
||||||
@ -102,7 +103,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) UITextView *textView;
|
@property (weak, nonatomic, readonly) JSQMessagesCellTextView *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.
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#import "UIView+JSQMessages.h"
|
#import "UIView+JSQMessages.h"
|
||||||
#import "UIDevice+JSQMessages.h"
|
#import "UIDevice+JSQMessages.h"
|
||||||
|
#import "UIColor+JSQMessages.h"
|
||||||
|
|
||||||
|
|
||||||
@interface JSQMessagesCollectionViewCell ()
|
@interface JSQMessagesCollectionViewCell ()
|
||||||
@ -34,11 +35,13 @@
|
|||||||
|
|
||||||
@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 UITextView *textView;
|
@property (weak, nonatomic) IBOutlet JSQMessagesCellTextView *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;
|
||||||
@ -51,8 +54,6 @@
|
|||||||
@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;
|
||||||
@ -93,11 +94,8 @@
|
|||||||
[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;
|
||||||
@ -114,23 +112,6 @@
|
|||||||
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;
|
||||||
@ -159,7 +140,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;
|
||||||
@ -187,9 +168,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.textViewFrameInsets = customAttributes.textViewFrameInsets;
|
self.textViewFrameInsets = customAttributes.textViewFrameInsets;
|
||||||
|
|
||||||
[self jsq_updateConstraint:self.messageBubbleLeftRightMarginConstraint
|
[self jsq_updateConstraint:self.messageBubbleContainerWidthConstraint
|
||||||
withConstant:customAttributes.messageBubbleLeftRightMargin];
|
withConstant:customAttributes.messageBubbleContainerViewWidth];
|
||||||
|
|
||||||
[self jsq_updateConstraint:self.cellTopLabelHeightConstraint
|
[self jsq_updateConstraint:self.cellTopLabelHeightConstraint
|
||||||
withConstant:customAttributes.cellTopLabelHeight];
|
withConstant:customAttributes.cellTopLabelHeight];
|
||||||
@ -279,7 +260,7 @@
|
|||||||
if ([_mediaView isEqual:mediaView]) {
|
if ([_mediaView isEqual:mediaView]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self.messageBubbleImageView removeFromSuperview];
|
[self.messageBubbleImageView removeFromSuperview];
|
||||||
[self.textView removeFromSuperview];
|
[self.textView removeFromSuperview];
|
||||||
|
|
||||||
@ -293,11 +274,13 @@
|
|||||||
// 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
|
||||||
for (NSUInteger i = 0; i < self.messageBubbleContainerView.subviews.count; i++) {
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
if (self.messageBubbleContainerView.subviews[i] != _mediaView) {
|
for (NSUInteger i = 0; i < self.messageBubbleContainerView.subviews.count; i++) {
|
||||||
[self.messageBubbleContainerView.subviews[i] removeFromSuperview];
|
if (self.messageBubbleContainerView.subviews[i] != _mediaView) {
|
||||||
|
[self.messageBubbleContainerView.subviews[i] removeFromSuperview];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Getters
|
#pragma mark - Getters
|
||||||
|
|||||||
12
JSQMessagesViewController/Views/JSQMessagesCollectionViewCellIncoming.xib
Normal file → Executable 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="6245" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6250" systemVersion="14A389" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment defaultVersion="1792" identifier="iOS"/>
|
<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 +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">
|
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KYU-B8-cUW" customClass="JSQMessagesCellTextView">
|
||||||
<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,6 +56,7 @@
|
|||||||
<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>
|
||||||
@ -102,7 +103,6 @@
|
|||||||
<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"/>
|
||||||
|
|||||||
13
JSQMessagesViewController/Views/JSQMessagesCollectionViewCellOutgoing.xib
Normal file → Executable file
@ -1,7 +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="6245" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6250" systemVersion="14C68k" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
|
<deployment identifier="iOS"/>
|
||||||
|
<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"/>
|
||||||
@ -39,7 +40,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">
|
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vLY-aM-0Dr" customClass="JSQMessagesCellTextView">
|
||||||
<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"/>
|
||||||
@ -55,6 +56,7 @@
|
|||||||
<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>
|
||||||
@ -102,7 +104,6 @@
|
|||||||
<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"/>
|
||||||
@ -116,8 +117,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"/>
|
||||||
@ -126,7 +127,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="283" y="294"/>
|
<point key="canvasLocation" x="371" y="145"/>
|
||||||
</collectionViewCell>
|
</collectionViewCell>
|
||||||
</objects>
|
</objects>
|
||||||
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
||||||
|
|||||||
@ -48,20 +48,22 @@
|
|||||||
CGFloat cornerRadius = 6.0f;
|
CGFloat cornerRadius = 6.0f;
|
||||||
|
|
||||||
self.backgroundColor = [UIColor whiteColor];
|
self.backgroundColor = [UIColor whiteColor];
|
||||||
self.layer.borderWidth = 0.5f;
|
//Signal: Comment out elements of Composer view
|
||||||
self.layer.borderColor = [UIColor lightGrayColor].CGColor;
|
// self.layer.borderWidth = 0.5f;
|
||||||
self.layer.cornerRadius = cornerRadius;
|
// self.layer.borderColor = [UIColor lightGrayColor].CGColor;
|
||||||
|
// 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(2.0f, 0.0f, 2.0f, 0.0f);
|
self.contentInset = UIEdgeInsetsMake(1.0f, 0.0f, 1.0f, 0.0f);
|
||||||
|
|
||||||
self.scrollEnabled = YES;
|
self.scrollEnabled = YES;
|
||||||
self.scrollsToTop = NO;
|
self.scrollsToTop = NO;
|
||||||
self.userInteractionEnabled = YES;
|
self.userInteractionEnabled = YES;
|
||||||
|
|
||||||
self.font = [UIFont systemFontOfSize:16.0f];
|
self.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:16.0f];
|
||||||
|
// self.font = [UIFont systemFontOfSize:16.0f];
|
||||||
self.textColor = [UIColor blackColor];
|
self.textColor = [UIColor blackColor];
|
||||||
self.textAlignment = NSTextAlignmentNatural;
|
self.textAlignment = NSTextAlignmentNatural;
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,6 +55,10 @@
|
|||||||
|
|
||||||
- (void)setTextInsets:(UIEdgeInsets)textInsets
|
- (void)setTextInsets:(UIEdgeInsets)textInsets
|
||||||
{
|
{
|
||||||
|
if (UIEdgeInsetsEqualToEdgeInsets(_textInsets, textInsets)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_textInsets = textInsets;
|
_textInsets = textInsets;
|
||||||
[self setNeedsDisplay];
|
[self setNeedsDisplay];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,33 +42,61 @@ 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 of this button is ignored. When you set this property, the button
|
* @discussion The frame height of this button is ignored. When you set this property, the button
|
||||||
* is fitted within a pre-defined default content view, whose height is determined by the
|
* is fitted within a pre-defined default content view, the leftBarButtonContainerView,
|
||||||
* height of the toolbar. You may specify a new width using `leftBarButtonItemWidth`.
|
* whose height is determined by the height of the toolbar. However, the width of this button
|
||||||
|
* will be preserved. You may specify a new width using `leftBarButtonItemWidth`.
|
||||||
|
* If the frame of this button is equal to `CGRectZero` when set, then a default frame size will be used.
|
||||||
* 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 of this button is ignored. When you set this property, the button
|
* @discussion The frame height of this button is ignored. When you set this property, the button
|
||||||
* is fitted within a pre-defined default content view, whose height is determined by the
|
* is fitted within a pre-defined default content view, the rightBarButtonContainerView,
|
||||||
* height of the toolbar. You may specify a new width using `rightBarButtonItemWidth`.
|
* whose height is determined by the height of the toolbar. However, the width of this button
|
||||||
|
* will be preserved. You may specify a new width using `rightBarButtonItemWidth`.
|
||||||
|
* If the frame of this button is equal to `CGRectZero` when set, then a default frame size will be used.
|
||||||
* 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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
#import "UIView+JSQMessages.h"
|
#import "UIView+JSQMessages.h"
|
||||||
|
|
||||||
const CGFloat kJSQMessagesToolbarContentViewHorizontalSpacingDefault = 4.0f;
|
const CGFloat kJSQMessagesToolbarContentViewHorizontalSpacingDefault = 8.0f;
|
||||||
|
|
||||||
|
|
||||||
@interface JSQMessagesToolbarContentView ()
|
@interface JSQMessagesToolbarContentView ()
|
||||||
@ -113,10 +113,6 @@ const CGFloat kJSQMessagesToolbarContentViewHorizontalSpacingDefault = 4.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];
|
||||||
}
|
}
|
||||||
@ -152,10 +148,6 @@ const CGFloat kJSQMessagesToolbarContentViewHorizontalSpacingDefault = 4.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];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +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="6245" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6250" systemVersion="14A389" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
|
<deployment identifier="iOS"/>
|
||||||
|
<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"/>
|
||||||
@ -11,7 +12,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="4" y="6" width="34" height="32"/>
|
<rect key="frame" x="8" 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"/>
|
||||||
@ -19,7 +20,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="266" y="6" width="50" height="32"/>
|
<rect key="frame" x="262" 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"/>
|
||||||
@ -27,7 +28,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="42" y="7" width="220" height="30"/>
|
<rect key="frame" x="50" y="7" width="204" 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"/>
|
||||||
@ -35,14 +36,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="4" id="7Ld-5r-Hp3"/>
|
<constraint firstItem="Myo-1S-Vg1" firstAttribute="leading" secondItem="dm4-NT-mvr" secondAttribute="trailing" constant="8" 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="4" id="LAU-fo-GJJ"/>
|
<constraint firstItem="LEq-G7-jGt" firstAttribute="leading" secondItem="1" secondAttribute="leading" constant="8" id="LAU-fo-GJJ"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="Myo-1S-Vg1" secondAttribute="trailing" constant="4" id="ds6-61-GNv"/>
|
<constraint firstAttribute="trailing" secondItem="Myo-1S-Vg1" secondAttribute="trailing" constant="8" 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="4" id="owo-gB-gyR"/>
|
<constraint firstItem="dm4-NT-mvr" firstAttribute="leading" secondItem="LEq-G7-jGt" secondAttribute="trailing" constant="8" id="owo-gB-gyR"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<nil key="simulatedStatusBarMetrics"/>
|
<nil key="simulatedStatusBarMetrics"/>
|
||||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||||
@ -55,7 +56,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="174" y="567"/>
|
<point key="canvasLocation" x="268" y="548"/>
|
||||||
</view>
|
</view>
|
||||||
</objects>
|
</objects>
|
||||||
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
||||||
|
|||||||
@ -10,4 +10,4 @@ SPEC CHECKSUMS:
|
|||||||
JSQSystemSoundPlayer: c98443b1cbb3b45db09d0d3d6c2355cf78294981
|
JSQSystemSoundPlayer: c98443b1cbb3b45db09d0d3d6c2355cf78294981
|
||||||
OCMock: f6cb8c162ab9d5620dddf411282c7b2c0ee78854
|
OCMock: f6cb8c162ab9d5620dddf411282c7b2c0ee78854
|
||||||
|
|
||||||
COCOAPODS: 0.34.4
|
COCOAPODS: 0.35.0
|
||||||
|
|||||||
152
README.md
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
[](http://travis-ci.org/jessesquires/JSQMessagesViewController) [][docsLink] [][mitLink]
|
[](http://travis-ci.org/jessesquires/JSQMessagesViewController) [][docsLink] [][mitLink]
|
||||||
|
|
||||||
### Update: 6.0-beta6 is out! See [#476](https://github.com/jessesquires/JSQMessagesViewController/issues/476) for details.
|
![Screenshot0][img0] ![Screenshot1][img1]
|
||||||
|
|
||||||
![Messages Screenshot 1][img1] ![Messages Screenshot 2][img2]
|
![Screenshot2][img2] ![Screenshot3][img3]
|
||||||
|
|
||||||
> 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/07/14/apple-ios-7-adoption-90-percent/). But, there's a branch for that!*
|
*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!*
|
||||||
````
|
````
|
||||||
git checkout iOS6_support_stable
|
git checkout iOS6_support_stable
|
||||||
````
|
````
|
||||||
@ -31,11 +31,21 @@ git checkout iOS6_support_stable
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
````
|
````ruby
|
||||||
pod 'JSQMessagesViewController'
|
# For latest release in cocoapods
|
||||||
|
pod 'JSQMessagesViewController'
|
||||||
|
|
||||||
|
# Feeling adventurous? Get the latest on develop
|
||||||
|
pod 'JSQMessagesViewController', :git => 'https://github.com/jessesquires/JSQMessagesViewController.git', :branch => 'develop'
|
||||||
|
|
||||||
|
# For version 5.3.2
|
||||||
|
pod 'JSQMessagesViewController', :git => 'https://github.com/jessesquires/JSQMessagesViewController', :branch => 'version_5.3.2_patch'
|
||||||
|
|
||||||
|
# For iOS 6 support
|
||||||
|
pod 'JSMessagesViewController', :git => 'https://github.com/jessesquires/JSQMessagesViewController.git', :branch => 'iOS6_support_stable'
|
||||||
````
|
````
|
||||||
|
|
||||||
Otherwise, drag the `JSQMessagesViewController/` folder to your project. Install [`JSQSystemSoundPlayer`][playerLink] and add the `QuartzCore.framework`.
|
Otherwise, drag the `JSQMessagesViewController/` folder to your project and install [`JSQSystemSoundPlayer`][playerLink].
|
||||||
|
|
||||||
>**NOTE:**
|
>**NOTE:**
|
||||||
>
|
>
|
||||||
@ -43,35 +53,115 @@ Otherwise, drag the `JSQMessagesViewController/` folder to your project. Install
|
|||||||
>
|
>
|
||||||
>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
|
||||||
````
|
````
|
||||||
|
|
||||||
* **Demo project**
|
>Read the [blog post](http://www.jessesquires.com/introducing-jsqmessagesvc-6-0/) about the 6.0 release!
|
||||||
* 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.
|
||||||
|
|
||||||
* **Model**
|
* **Message Model**
|
||||||
* Your model objects should conform to the `JSQMessageData` protocol.
|
* Your message 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:
|
* However, you may use the provided classes: `JSQPhotoMediaItem`, `JSQLocationMediaItem`, `JSQVideoMediaItem`.
|
||||||
* Model: `JSQTextMessage` and `JSQMediaMessage`
|
* Creating your own custom media items is easy! Simply follow the pattern used by the built-in media types.
|
||||||
* Media attachments: `JSQPhotoMediaItem`, `JSQLocationMediaItem`, `JSQVideoMediaItem`
|
* Also see `JSQMessagesMediaViewBubbleImageMasker` for masking your custom media views as message bubbles.
|
||||||
|
|
||||||
|
* **Avatar Model**
|
||||||
|
* Your avatar model objects should conform to the `JSQMessageAvatarImageDataSource` protocol.
|
||||||
|
* However, you may use the provided `JSQMessagesAvatarImage` class.
|
||||||
|
* Also see `JSQMessagesAvatarImageFactory` for easily generating custom avatars.
|
||||||
|
|
||||||
|
* **Message Bubble Model**
|
||||||
|
* Your message bubble model objects should conform to the `JSQMessageBubbleImageDataSource` protocol.
|
||||||
|
* However, you may use the provided `JSQMessagesBubbleImage` class.
|
||||||
|
* Also see `JSQMessagesBubbleImageFactory` and `UIImage+JSQMessages.h` for easily generating custom bubbles.
|
||||||
|
|
||||||
* **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. This should help you configure your view however you like.
|
* The demo project is well-commented. Please use this as a guide.
|
||||||
|
|
||||||
|
## Quick Tips
|
||||||
|
|
||||||
|
*Springy bubbles?*
|
||||||
|
````objective-c
|
||||||
|
- (void)viewDidAppear:(BOOL)animated
|
||||||
|
{
|
||||||
|
[super viewDidAppear:animated];
|
||||||
|
self.collectionView.collectionViewLayout.springinessEnabled = YES;
|
||||||
|
}
|
||||||
|
````
|
||||||
|
|
||||||
|
*Remove avatars?*
|
||||||
|
````objective-c
|
||||||
|
- (void)viewDidLoad
|
||||||
|
{
|
||||||
|
[super viewDidLoad];
|
||||||
|
self.collectionView.collectionViewLayout.incomingAvatarViewSize = CGSizeZero;
|
||||||
|
self.collectionView.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<JSQMessageAvatarImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView avatarImageDataForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||||
|
{
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
````
|
||||||
|
|
||||||
|
*Customize your cells?*
|
||||||
|
````objective-c
|
||||||
|
- (UICollectionViewCell *)collectionView:(JSQMessagesCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||||
|
{
|
||||||
|
JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
|
||||||
|
|
||||||
|
// Customize the shit out of this cell
|
||||||
|
// See the docs for JSQMessagesCollectionViewCell
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
````
|
||||||
|
|
||||||
|
*Customize your toolbar buttons?*
|
||||||
|
````objective-c
|
||||||
|
- (void)viewDidLoad
|
||||||
|
{
|
||||||
|
[super viewDidLoad];
|
||||||
|
|
||||||
|
// This button will call the `didPressAccessoryButton:` selector on your JSQMessagesViewController subclass
|
||||||
|
self.inputToolbar.contentView.leftBarButtonItem = /* custom button or nil to remove */
|
||||||
|
|
||||||
|
// This button will call the `didPressSendButton:` selector on your JSQMessagesViewController subclass
|
||||||
|
self.inputToolbar.contentView.rightBarButtonItem = /* custom button or nil to remove */
|
||||||
|
|
||||||
|
// Swap buttons, move send button to the LEFT side and the attachment button to the RIGHT
|
||||||
|
// For RTL language support
|
||||||
|
self.inputToolbar.contentView.leftBarButtonItem = [JSQMessagesToolbarButtonFactory defaultSendButtonItem];
|
||||||
|
self.inputToolbar.contentView.rightBarButtonItem = [JSQMessagesToolbarButtonFactory defaultAccessoryButtonItem];
|
||||||
|
|
||||||
|
// The library will call the correct selector for each button, based on this value
|
||||||
|
self.inputToolbar.sendButtonOnRight = NO;
|
||||||
|
}
|
||||||
|
````
|
||||||
|
|
||||||
|
## Questions & Help
|
||||||
|
|
||||||
|
There's [a label](https://github.com/jessesquires/JSQMessagesViewController/labels/questions%20&%20help) for that. Before asking a question, see if it has [already been answered](https://github.com/jessesquires/JSQMessagesViewController/issues?q=label%3A%22questions+%26+help%22+is%3Aclosed).
|
||||||
|
|
||||||
|
## Migrating from v5.x to v6.x
|
||||||
|
|
||||||
|
If you are upgrading from v5.x to v6.x, see the [6.0 release notes](https://github.com/jessesquires/JSQMessagesViewController/releases/tag/6.0.0) for details about API changes.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
@ -83,15 +173,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></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> :coffee:</h4>
|
||||||
<h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$10&body=Thanks for developing JSQMessagesViewController!">Send $10</a> <em>This library is great. Lunch is on me!</em></h4>
|
<h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$10&body=Thanks for developing JSQMessagesViewController!">Send $10</a> <em>This library is great. Lunch is on me!</em> :ramen:</h4>
|
||||||
<h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$25&body=Thanks for developing JSQMessagesViewController!">Send $25</a> <em>This totally saved me time. Go get a nice dinner!</em></h4>
|
<h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$25&body=Thanks for developing JSQMessagesViewController!">Send $25</a> <em>This totally saved me time. Go get a nice dinner!</em> :fork_and_knife:</h4>
|
||||||
<h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$50&body=Thanks for developing JSQMessagesViewController!">Send $50</a> <em>I love this library. I want new features!</em></h4>
|
<h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$50&body=Thanks for developing JSQMessagesViewController!">Send $50</a> <em>I love this library. I want new features!</em> :clap:</h4>
|
||||||
<h4><a href="mailto:jesse.squires.developer@gmail.com?cc=cash@square.com&subject=$100&body=Thanks for developing JSQMessagesViewController!">Send $100</a> <em>I really want to support this project!</em></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>
|
||||||
>*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
|
||||||
@ -134,6 +224,8 @@ 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
|
||||||
@ -148,5 +240,7 @@ 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
|
||||||
|
|
||||||
[img1]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot0.png
|
[img0]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot0.png
|
||||||
[img2]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot1.png
|
[img1]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot1.png
|
||||||
|
[img2]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot2.png
|
||||||
|
[img3]:https://raw.githubusercontent.com/jessesquires/JSQMessagesViewController/develop/Screenshots/screenshot3.png
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 47 KiB |
BIN
Screenshots/screenshot2.png
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
Screenshots/screenshot3.png
Normal file
|
After Width: | Height: | Size: 27 KiB |