Compare commits

...

54 Commits

Author SHA1 Message Date
Christine Corbett
26fb5cbcf4 groups and calls have optional avatar; consumer must specify that it should be used and provide images in project of naming convention. otherwise no image will be used 2015-01-27 22:53:25 -10:00
Christine Corbett
c8262eee36 calls and group update messages now blue styled in correct font 2015-01-25 19:10:42 -10:00
Joyce Yan
184f53b07b Design tweaks based on @abolishme's work. 2015-01-24 08:31:23 -10:00
dtsbourg
ed9858bd6d revert b73b5d 2014-12-29 23:48:01 +01:00
dtsbourg
9dffc05aa7 Merge branch 'FredericJacobs-JSignalQ' into JSignalQ 2014-12-29 22:07:24 +01:00
Frederic Jacobs
cb5c4facbc Removing unused properties + bug fix call label 2014-12-29 21:56:58 +01:00
dtsbourg
84d1b659f3 Typo fix 2014-12-29 21:21:19 +01:00
dtsbourg
b73b5d9983 Performance enhancement for collection view reloading 2014-12-29 19:25:29 +01:00
dtsbourg
6a30411791 Merge remote-tracking branch 'jsq/master' into JSignalQ-6.1.1 2014-12-23 18:04:39 +01:00
dtsbourg
8703ce020c JSQDisplayedMessage: implement tap delegate 2014-12-10 21:45:29 +01:00
dtsbourg
fcbbfdc43f Fix crash on long tap on error and info messages 2014-12-09 22:37:56 +01:00
dtsbourg
bc976a04d9 Cells: change isKindOfClass to messageType check 2014-12-07 14:42:27 +01:00
dtsbourg
43f6e75bbf Set adapter type as property 2014-12-06 18:23:03 +01:00
dtsbourg
59ea2b6920 Revert to TSMessageAdapterType for naming to avoid conflicts 2014-12-06 16:57:31 +01:00
dtsbourg
dee758a3ff TSMessageType added to JSQMessageData 2014-12-06 16:52:16 +01:00
dtsbourg
82482a1fc5 Remove call button on toolbar 2014-12-04 16:11:34 +01:00
dtsbourg
7c2cec63f9 Remove unnecessary res 2014-11-30 19:55:56 +01:00
dtsbourg
91fbb4dce7 JSQDisplayedMessage: Update UI 2014-11-30 19:55:27 +01:00
dtsbourg
0d8fabe142 Calls: Update UI 2014-11-30 16:51:24 +01:00
dtsbourg
4049f54789 JSQDisplayedMessage: Link to UI 2014-11-29 15:30:53 +01:00
dtsbourg
54ae40b07a JSQDisplayedMessageCollectionViewCell: Base class 2014-11-29 15:06:43 +01:00
dtsbourg
bcf0ac6e1f JSQErrorMessage: Model 2014-11-29 14:48:59 +01:00
dtsbourg
e70cec697f JSQDisplayedMessage: Model + JSQInfoMessage: Model 2014-11-29 14:39:59 +01:00
dtsbourg
b22b7a4caf JSQMessagesBubbleImageFactory: Add a failed message bubble 2014-11-27 12:43:24 +01:00
dtsbourg
b8b3fb9122 JSQMessageData: add message status field 2014-11-27 12:29:49 +01:00
dtsbourg
5fc12f5cba Merge branch 'master' of https://github.com/jessesquires/JSQMessagesViewController into JSignalQ 2014-11-26 18:04:32 +01:00
dtsbourg
4cad607ae2 none 2014-11-26 18:01:19 +01:00
dtsbourg
597670e446 JSQCallCollectionViewCell: UI 2014-11-21 23:01:16 +01:00
dtsbourg
881ddddeb4 Demo: make JSQM6.0 work with JSQCall 2014-11-21 22:14:53 +01:00
dtsbourg
32395453ff Finish merging 2014-11-21 13:43:21 +01:00
dtsbourg
5c6dce5a04 Fix merge from master conflicts 2014-11-21 13:37:28 +01:00
dtsbourg
3d248e4af0 JSQCall : layout 2014-11-21 12:02:20 +01:00
dtsbourg
6bbef1949b JSQCall model 2014-11-20 14:57:18 +01:00
dtsbourg
1031a89858 JSQMessage: Add failed state 2014-11-20 10:10:55 +01:00
dtsbourg
21d877492e InputToolbar: blue BarButtonItems 2014-11-19 13:05:35 +01:00
dtsbourg
5670accd2c General: Font update 2014-11-18 18:05:24 +01:00
dtsbourg
d138d4f3a3 InputToolbar: Fine tune enabling on rightBarButtonItem 2014-11-17 20:41:08 +01:00
dtsbourg
cddbbf2c75 InputToolbar: Bar button item always responds to tap events 2014-11-17 20:27:57 +01:00
dtsbourg
104ba0e023 MessageStatus: add kMessageNone status 2014-11-17 20:22:59 +01:00
dtsbourg
a27fa1091e Test: Custom UIButton in factory 2014-11-17 20:17:08 +01:00
dtsbourg
7446b63cbb remove * 2014-11-12 22:31:22 +01:00
dtsbourg
73482f6ace ≈Merge branch 'issue_492_scrollviewperformance' into JSignalQ 2014-11-12 22:26:40 +01:00
dtsbourg
2dad6e3036 add message status 2014-11-12 22:22:59 +01:00
dtsbourg
99971a8d38 Merge branch 'JSignalQ' of https://github.com/dtsbourg/JSQMessagesViewController into JSignalQ 2014-10-28 23:39:44 +01:00
dtsbourg
da7203dee2 [UIColor whiteColor] 2014-10-28 23:37:11 +01:00
dtsbourg
88e16ac830 white bg ? 2014-10-28 23:37:11 +01:00
dtsbourg
41dddfea3a cell xib white bg 2014-10-28 23:37:11 +01:00
dtsbourg
ebea4ef0b8 Restore white bg 2014-10-28 23:37:11 +01:00
dtsbourg
f115194efa Signal 2014-10-28 23:37:11 +01:00
dtsbourg
06e7c2bec9 [UIColor whiteColor] 2014-10-28 22:51:14 +01:00
dtsbourg
6dded2cce9 white bg ? 2014-10-28 22:28:47 +01:00
dtsbourg
f03bac13a0 cell xib white bg 2014-10-28 22:23:39 +01:00
dtsbourg
33b81ca6b0 Restore white bg 2014-10-28 22:19:28 +01:00
dtsbourg
752edc4f0f Signal 2014-10-28 21:49:55 +01:00
45 changed files with 1435 additions and 98 deletions

View File

@ -58,9 +58,7 @@
88A25FCA19D8E01A00924534 /* JSQMessagesCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8B19D8E01A00924534 /* JSQMessagesCollectionView.m */; };
88A25FCB19D8E01A00924534 /* JSQMessagesCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8D19D8E01A00924534 /* JSQMessagesCollectionViewCell.m */; };
88A25FCC19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F8F19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.m */; };
88A25FCD19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.xib in Resources */ = {isa = PBXBuildFile; fileRef = 88A25F9019D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.xib */; };
88A25FCE19D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F9219D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.m */; };
88A25FCF19D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.xib in Resources */ = {isa = PBXBuildFile; fileRef = 88A25F9319D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.xib */; };
88A25FD019D8E01A00924534 /* JSQMessagesComposerTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F9519D8E01A00924534 /* JSQMessagesComposerTextView.m */; };
88A25FD119D8E01A00924534 /* JSQMessagesInputToolbar.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F9719D8E01A00924534 /* JSQMessagesInputToolbar.m */; };
88A25FD219D8E01A00924534 /* JSQMessagesLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 88A25F9919D8E01A00924534 /* JSQMessagesLabel.m */; };
@ -105,6 +103,23 @@
88C4583019F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C4582F19F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.m */; };
88E4D7131A0DBD6B000CC061 /* JSQMessages.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8841B88719F4988800EA16B6 /* JSQMessages.strings */; };
94A4FA20C2FBD0D62614D5A8 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 97E6750B77E8A7042BA0754B /* libPods.a */; };
FC15B7A91A1E880900F59801 /* JSQCallCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = FC15B7A81A1E880900F59801 /* JSQCallCollectionViewCell.xib */; };
FC15B7B01A1F6AC800F59801 /* JSQMessagesCollectionViewCellIncoming.xib in Resources */ = {isa = PBXBuildFile; fileRef = FC15B7AE1A1F6AC800F59801 /* JSQMessagesCollectionViewCellIncoming.xib */; };
FC15B7B11A1F6AC800F59801 /* JSQMessagesCollectionViewCellOutgoing.xib in Resources */ = {isa = PBXBuildFile; fileRef = FC15B7AF1A1F6AC800F59801 /* JSQMessagesCollectionViewCellOutgoing.xib */; };
FC4FA03A1A1E1BD100DA100A /* JSQCall.m in Sources */ = {isa = PBXBuildFile; fileRef = FC4FA0391A1E1BD100DA100A /* JSQCall.m */; };
FC4FA03D1A1E81AF00DA100A /* JSQCallCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FC4FA03C1A1E81AF00DA100A /* JSQCallCollectionViewCell.m */; };
FCA52AEF1A2B6ECE00CCADFA /* call_missed@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FCA52AEE1A2B6ECE00CCADFA /* call_missed@2x.png */; };
FCA52AF51A2B6FAE00CCADFA /* call_canceled@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FCA52AF11A2B6FAE00CCADFA /* call_canceled@2x.png */; };
FCA52AF61A2B6FAE00CCADFA /* call_failed@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FCA52AF21A2B6FAE00CCADFA /* call_failed@2x.png */; };
FCA52AF71A2B6FAE00CCADFA /* call_incoming@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FCA52AF31A2B6FAE00CCADFA /* call_incoming@2x.png */; };
FCA52AF81A2B6FAE00CCADFA /* call_outgoing@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FCA52AF41A2B6FAE00CCADFA /* call_outgoing@2x.png */; };
FCA52B021A2B9F0E00CCADFA /* warning_white@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FCA52B001A2B9F0E00CCADFA /* warning_white@2x.png */; };
FCA52B031A2B9F0E00CCADFA /* error_white@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FCA52B011A2B9F0E00CCADFA /* error_white@2x.png */; };
FCFA5E131A29FC1000C8E32E /* JSQDisplayedMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = FCFA5E121A29FC1000C8E32E /* JSQDisplayedMessage.m */; };
FCFA5E161A29FE3B00C8E32E /* JSQInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = FCFA5E151A29FE3B00C8E32E /* JSQInfoMessage.m */; };
FCFA5E191A2A044500C8E32E /* JSQErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = FCFA5E181A2A044500C8E32E /* JSQErrorMessage.m */; };
FCFA5E1D1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FCFA5E1B1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.m */; };
FCFA5E1E1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = FCFA5E1C1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.xib */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -219,10 +234,8 @@
88A25F8D19D8E01A00924534 /* JSQMessagesCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesCollectionViewCell.m; sourceTree = "<group>"; };
88A25F8E19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesCollectionViewCellIncoming.h; sourceTree = "<group>"; };
88A25F8F19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesCollectionViewCellIncoming.m; sourceTree = "<group>"; };
88A25F9019D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JSQMessagesCollectionViewCellIncoming.xib; sourceTree = "<group>"; };
88A25F9119D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesCollectionViewCellOutgoing.h; sourceTree = "<group>"; };
88A25F9219D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesCollectionViewCellOutgoing.m; sourceTree = "<group>"; };
88A25F9319D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JSQMessagesCollectionViewCellOutgoing.xib; sourceTree = "<group>"; };
88A25F9419D8E01A00924534 /* JSQMessagesComposerTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesComposerTextView.h; sourceTree = "<group>"; };
88A25F9519D8E01A00924534 /* JSQMessagesComposerTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesComposerTextView.m; sourceTree = "<group>"; };
88A25F9619D8E01A00924534 /* JSQMessagesInputToolbar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesInputToolbar.h; sourceTree = "<group>"; };
@ -277,7 +290,30 @@
88C4582E19F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQMessagesMediaViewBubbleImageMasker.h; sourceTree = "<group>"; };
88C4582F19F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQMessagesMediaViewBubbleImageMasker.m; sourceTree = "<group>"; };
97E6750B77E8A7042BA0754B /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
FC15B7A81A1E880900F59801 /* JSQCallCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JSQCallCollectionViewCell.xib; sourceTree = "<group>"; };
FC15B7AE1A1F6AC800F59801 /* JSQMessagesCollectionViewCellIncoming.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JSQMessagesCollectionViewCellIncoming.xib; sourceTree = "<group>"; };
FC15B7AF1A1F6AC800F59801 /* JSQMessagesCollectionViewCellOutgoing.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JSQMessagesCollectionViewCellOutgoing.xib; sourceTree = "<group>"; };
FC4FA0381A1E1BD100DA100A /* JSQCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQCall.h; sourceTree = "<group>"; };
FC4FA0391A1E1BD100DA100A /* JSQCall.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQCall.m; sourceTree = "<group>"; };
FC4FA03B1A1E81AF00DA100A /* JSQCallCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQCallCollectionViewCell.h; sourceTree = "<group>"; };
FC4FA03C1A1E81AF00DA100A /* JSQCallCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQCallCollectionViewCell.m; sourceTree = "<group>"; };
FC5C727E4CCDA2B95A7BA30C /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
FCA52AEE1A2B6ECE00CCADFA /* call_missed@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "call_missed@2x.png"; path = "../../JSQMessagesDemo/call_missed@2x.png"; sourceTree = "<group>"; };
FCA52AF11A2B6FAE00CCADFA /* call_canceled@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "call_canceled@2x.png"; sourceTree = "<group>"; };
FCA52AF21A2B6FAE00CCADFA /* call_failed@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "call_failed@2x.png"; sourceTree = "<group>"; };
FCA52AF31A2B6FAE00CCADFA /* call_incoming@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "call_incoming@2x.png"; sourceTree = "<group>"; };
FCA52AF41A2B6FAE00CCADFA /* call_outgoing@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "call_outgoing@2x.png"; sourceTree = "<group>"; };
FCA52B001A2B9F0E00CCADFA /* warning_white@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "warning_white@2x.png"; sourceTree = "<group>"; };
FCA52B011A2B9F0E00CCADFA /* error_white@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "error_white@2x.png"; sourceTree = "<group>"; };
FCFA5E111A29FC1000C8E32E /* JSQDisplayedMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQDisplayedMessage.h; sourceTree = "<group>"; };
FCFA5E121A29FC1000C8E32E /* JSQDisplayedMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQDisplayedMessage.m; sourceTree = "<group>"; };
FCFA5E141A29FE3B00C8E32E /* JSQInfoMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQInfoMessage.h; sourceTree = "<group>"; };
FCFA5E151A29FE3B00C8E32E /* JSQInfoMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQInfoMessage.m; sourceTree = "<group>"; };
FCFA5E171A2A044500C8E32E /* JSQErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQErrorMessage.h; sourceTree = "<group>"; };
FCFA5E181A2A044500C8E32E /* JSQErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQErrorMessage.m; sourceTree = "<group>"; };
FCFA5E1A1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSQDisplayedMessageCollectionViewCell.h; sourceTree = "<group>"; };
FCFA5E1B1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSQDisplayedMessageCollectionViewCell.m; sourceTree = "<group>"; };
FCFA5E1C1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JSQDisplayedMessageCollectionViewCell.xib; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -339,6 +375,7 @@
88445B3A19E0C0B10014F889 /* XCTest.framework */,
);
name = Frameworks;
path = ../..;
sourceTree = "<group>";
};
8841B88219F4983C00EA16B6 /* Strings */ = {
@ -354,7 +391,6 @@
children = (
886C33FE19F45E30006B4997 /* JSQMessagesViewController.podspec */,
88A25F3E19D8E01A00924534 /* JSQMessagesViewController */,
636A8663AEEE5C37B65C515D /* Frameworks */,
88A25F2B19D8DF2500924534 /* JSQMessagesDemo */,
88A25F1E19D8DEC500924534 /* JSQMessagesTests */,
2BBEF3CD91C31A49E5FF9E3C /* Pods */,
@ -434,6 +470,8 @@
88A25F3F19D8E01A00924534 /* Assets */ = {
isa = PBXGroup;
children = (
FCA52AFB1A2B9BAD00CCADFA /* InfoError */,
FCA52AF01A2B6F8A00CCADFA /* Calls */,
8841B88219F4983C00EA16B6 /* Strings */,
8861666C19F492B70025B958 /* JSQMessagesAssets.bundle */,
);
@ -524,6 +562,14 @@
88A25F8619D8E01A00924534 /* JSQPhotoMediaItem.m */,
886C33FB19F4371E006B4997 /* JSQVideoMediaItem.h */,
886C33FC19F4371E006B4997 /* JSQVideoMediaItem.m */,
FC4FA0381A1E1BD100DA100A /* JSQCall.h */,
FC4FA0391A1E1BD100DA100A /* JSQCall.m */,
FCFA5E111A29FC1000C8E32E /* JSQDisplayedMessage.h */,
FCFA5E121A29FC1000C8E32E /* JSQDisplayedMessage.m */,
FCFA5E141A29FE3B00C8E32E /* JSQInfoMessage.h */,
FCFA5E151A29FE3B00C8E32E /* JSQInfoMessage.m */,
FCFA5E171A2A044500C8E32E /* JSQErrorMessage.h */,
FCFA5E181A2A044500C8E32E /* JSQErrorMessage.m */,
);
path = Model;
sourceTree = "<group>";
@ -531,6 +577,7 @@
88A25F8919D8E01A00924534 /* Views */ = {
isa = PBXGroup;
children = (
636A8663AEEE5C37B65C515D /* Frameworks */,
883C11761A09FB100092A16D /* JSQMessagesCellTextView.h */,
883C11771A09FB100092A16D /* JSQMessagesCellTextView.m */,
88A25F8A19D8E01A00924534 /* JSQMessagesCollectionView.h */,
@ -539,10 +586,10 @@
88A25F8D19D8E01A00924534 /* JSQMessagesCollectionViewCell.m */,
88A25F8E19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.h */,
88A25F8F19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.m */,
88A25F9019D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.xib */,
FC15B7AE1A1F6AC800F59801 /* JSQMessagesCollectionViewCellIncoming.xib */,
88A25F9119D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.h */,
88A25F9219D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.m */,
88A25F9319D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.xib */,
FC15B7AF1A1F6AC800F59801 /* JSQMessagesCollectionViewCellOutgoing.xib */,
88A25F9419D8E01A00924534 /* JSQMessagesComposerTextView.h */,
88A25F9519D8E01A00924534 /* JSQMessagesComposerTextView.m */,
88A25F9619D8E01A00924534 /* JSQMessagesInputToolbar.h */,
@ -560,6 +607,12 @@
88A25FA019D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.h */,
88A25FA119D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.m */,
88A25FA219D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.xib */,
FC4FA03B1A1E81AF00DA100A /* JSQCallCollectionViewCell.h */,
FC4FA03C1A1E81AF00DA100A /* JSQCallCollectionViewCell.m */,
FC15B7A81A1E880900F59801 /* JSQCallCollectionViewCell.xib */,
FCFA5E1A1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.h */,
FCFA5E1B1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.m */,
FCFA5E1C1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.xib */,
);
path = Views;
sourceTree = "<group>";
@ -634,6 +687,27 @@
path = ViewTests;
sourceTree = "<group>";
};
FCA52AF01A2B6F8A00CCADFA /* Calls */ = {
isa = PBXGroup;
children = (
FCA52AF11A2B6FAE00CCADFA /* call_canceled@2x.png */,
FCA52AF21A2B6FAE00CCADFA /* call_failed@2x.png */,
FCA52AF31A2B6FAE00CCADFA /* call_incoming@2x.png */,
FCA52AF41A2B6FAE00CCADFA /* call_outgoing@2x.png */,
FCA52AEE1A2B6ECE00CCADFA /* call_missed@2x.png */,
);
name = Calls;
sourceTree = "<group>";
};
FCA52AFB1A2B9BAD00CCADFA /* InfoError */ = {
isa = PBXGroup;
children = (
FCA52B001A2B9F0E00CCADFA /* warning_white@2x.png */,
FCA52B011A2B9F0E00CCADFA /* error_white@2x.png */,
);
name = InfoError;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -734,14 +808,23 @@
88E4D7131A0DBD6B000CC061 /* JSQMessages.strings in Resources */,
886C33FF19F45E30006B4997 /* JSQMessagesViewController.podspec in Resources */,
8861666D19F492B70025B958 /* JSQMessagesAssets.bundle in Resources */,
88A25FCF19D8E01A00924534 /* JSQMessagesCollectionViewCellOutgoing.xib in Resources */,
88A25FCD19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.xib in Resources */,
FC15B7B11A1F6AC800F59801 /* JSQMessagesCollectionViewCellOutgoing.xib in Resources */,
88A25FD619D8E01A00924534 /* JSQMessagesToolbarContentView.xib in Resources */,
FCA52AF71A2B6FAE00CCADFA /* call_incoming@2x.png in Resources */,
88A25F3A19D8DF2500924534 /* Images.xcassets in Resources */,
88A25FBC19D8E01A00924534 /* JSQMessagesViewController.xib in Resources */,
FCA52AF81A2B6FAE00CCADFA /* call_outgoing@2x.png in Resources */,
FCA52B021A2B9F0E00CCADFA /* warning_white@2x.png in Resources */,
FCA52AF51A2B6FAE00CCADFA /* call_canceled@2x.png in Resources */,
FCA52B031A2B9F0E00CCADFA /* error_white@2x.png in Resources */,
FCA52AEF1A2B6ECE00CCADFA /* call_missed@2x.png in Resources */,
88A25FD819D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.xib in Resources */,
FCFA5E1E1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.xib in Resources */,
88A25F3919D8DF2500924534 /* Main.storyboard in Resources */,
FC15B7B01A1F6AC800F59801 /* JSQMessagesCollectionViewCellIncoming.xib in Resources */,
88A25FD419D8E01A00924534 /* JSQMessagesLoadEarlierHeaderView.xib in Resources */,
FC15B7A91A1E880900F59801 /* JSQCallCollectionViewCell.xib in Resources */,
FCA52AF61A2B6FAE00CCADFA /* call_failed@2x.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -831,6 +914,7 @@
8885734D19DE55D000E89D20 /* NSUserDefaults+DemoSettings.m in Sources */,
883C11781A09FB100092A16D /* JSQMessagesCellTextView.m in Sources */,
88A25FB919D8E01A00924534 /* UIView+JSQMessages.m in Sources */,
FCFA5E131A29FC1000C8E32E /* JSQDisplayedMessage.m in Sources */,
88A25FCA19D8E01A00924534 /* JSQMessagesCollectionView.m in Sources */,
88A25FD219D8E01A00924534 /* JSQMessagesLabel.m in Sources */,
88445B4019E1B4470014F889 /* JSQLocationMediaItem.m in Sources */,
@ -838,19 +922,23 @@
88A25FD519D8E01A00924534 /* JSQMessagesToolbarContentView.m in Sources */,
88A25FC119D8E01A00924534 /* JSQMessagesCollectionViewFlowLayout.m in Sources */,
8885734A19DE540400E89D20 /* DemoSettingsViewController.m in Sources */,
FC4FA03A1A1E1BD100DA100A /* JSQCall.m in Sources */,
88A25FC719D8E01A00924534 /* JSQMessagesBubbleImage.m in Sources */,
88A25FC519D8E01A00924534 /* JSQMessage.m in Sources */,
88A25FD719D8E01A00924534 /* JSQMessagesTypingIndicatorFooterView.m in Sources */,
88A25FD319D8E01A00924534 /* JSQMessagesLoadEarlierHeaderView.m in Sources */,
FC4FA03D1A1E81AF00DA100A /* JSQCallCollectionViewCell.m in Sources */,
88A25FC819D8E01A00924534 /* JSQPhotoMediaItem.m in Sources */,
88C4583019F5F7A0008FD427 /* JSQMessagesMediaViewBubbleImageMasker.m in Sources */,
88A25FB819D8E01A00924534 /* UIImage+JSQMessages.m in Sources */,
88A25FBF19D8E01A00924534 /* JSQMessagesTimestampFormatter.m in Sources */,
88A25FE019D8E0C400924534 /* DemoModelData.m in Sources */,
FCFA5E1D1A2A08E500C8E32E /* JSQDisplayedMessageCollectionViewCell.m in Sources */,
88A25F3C19D8DF2500924534 /* main.m in Sources */,
88A25F3719D8DF2500924534 /* AppDelegate.m in Sources */,
886FFD2E19E9A65D00EB8485 /* UIDevice+JSQMessages.m in Sources */,
88A25FB619D8E01A00924534 /* NSString+JSQMessages.m in Sources */,
FCFA5E191A2A044500C8E32E /* JSQErrorMessage.m in Sources */,
88A901B619F618B100F99777 /* JSQMediaItem.m in Sources */,
88A25FCC19D8E01A00924534 /* JSQMessagesCollectionViewCellIncoming.m in Sources */,
88A25FBE19D8E01A00924534 /* JSQMessagesBubbleImageFactory.m in Sources */,
@ -858,6 +946,7 @@
88A25FB719D8E01A00924534 /* UIColor+JSQMessages.m in Sources */,
886C33FD19F4371E006B4997 /* JSQVideoMediaItem.m in Sources */,
88A25FBA19D8E01A00924534 /* JSQMessagesKeyboardController.m in Sources */,
FCFA5E161A29FE3B00C8E32E /* JSQInfoMessage.m in Sources */,
88A25FC019D8E01A00924534 /* JSQMessagesToolbarButtonFactory.m in Sources */,
88A25FC219D8E01A00924534 /* JSQMessagesCollectionViewFlowLayoutInvalidationContext.m in Sources */,
88A25FE119D8E0C400924534 /* TableViewController.m in Sources */,

View File

@ -18,6 +18,12 @@
#import "DemoMessagesViewController.h"
#import "JSQCallCollectionViewCell.h"
#import "JSQCall.h"
#import "JSQDisplayedMessageCollectionViewCell.h"
#import "JSQErrorMessage.h"
#import "JSQInfoMessage.h"
@implementation DemoMessagesViewController
@ -158,7 +164,7 @@
id<JSQMessageMediaData> newMediaData = nil;
id newMediaAttachmentCopy = nil;
if (copyMessage.isMediaMessage) {
if ([copyMessage isKindOfClass:[JSQMessage class]]) {
/**
* Last message was a media message
*/
@ -396,6 +402,8 @@
*/
JSQMessage *message = [self.demoData.messages objectAtIndex:indexPath.item];
if (![message isKindOfClass:[JSQCall class]] || ![message isKindOfClass:[JSQErrorMessage class]] || ![message isKindOfClass:[JSQInfoMessage class]]) return nil;
if ([message.senderId isEqualToString:self.senderId]) {
if (![NSUserDefaults outgoingAvatarSetting]) {
return nil;
@ -406,8 +414,7 @@
return nil;
}
}
return [self.demoData.avatars objectForKey:message.senderId];
}
@ -468,38 +475,34 @@
/**
* Override point for customizing cells
*/
JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
/**
* Configure almost *anything* on the cell
*
* Text colors, label text, label colors, etc.
*
*
* DO NOT set `cell.textView.font` !
* Instead, you need to set `self.collectionView.collectionViewLayout.messageBubbleFont` to the font you want in `viewDidLoad`
*
*
* DO NOT manipulate cell layout information!
* Instead, override the properties you want on `self.collectionView.collectionViewLayout` from `viewDidLoad`
*/
JSQMessage *msg = [self.demoData.messages objectAtIndex:indexPath.item];
if (!msg.isMediaMessage) {
if ([msg.senderId isEqualToString:self.senderId]) {
cell.textView.textColor = [UIColor blackColor];
}
else {
cell.textView.textColor = [UIColor whiteColor];
if ([msg isKindOfClass:[JSQMessage class]])
{
JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
if (!msg.isMediaMessage) {
if ([msg.senderId isEqualToString:self.senderId]) {
cell.textView.textColor = [UIColor blackColor];
}
else {
cell.textView.textColor = [UIColor whiteColor];
}
cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor,
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };
}
cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor,
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };
return cell;
} else if ([msg isKindOfClass:[JSQCall class]]) {
JSQCallCollectionViewCell *cell = (JSQCallCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
return cell;
} else {
JSQDisplayedMessageCollectionViewCell * cell = (JSQDisplayedMessageCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
return cell;
}
return cell;
}
@ -521,9 +524,9 @@
*
* Show a timestamp for every 3rd message
*/
if (indexPath.item % 3 == 0) {
return kJSQMessagesCollectionViewCellLabelHeightDefault;
}
// if (indexPath.item % 3 == 0) {
// return kJSQMessagesCollectionViewCellLabelHeightDefault;
// }
return 0.0f;
}

View File

@ -20,6 +20,9 @@
#import "NSUserDefaults+DemoSettings.h"
#import "JSQCall.h"
#import "JSQInfoMessage.h"
#import "JSQErrorMessage.h"
/**
* This is for demo/testing purposes only.
@ -99,11 +102,18 @@
* You should have a mutable array or orderedSet, or something.
*/
self.messages = [[NSMutableArray alloc] initWithObjects:
[[JSQCall alloc] initWithCallerId:kJSQDemoAvatarIdWoz
callerDisplayName:kJSQDemoAvatarDisplayNameWoz
date:[NSDate date]
status:kCallOutgoing],
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
senderDisplayName:kJSQDemoAvatarDisplayNameSquires
date:[NSDate distantPast]
text:@"Welcome to JSQMessages: A messaging UI framework for iOS."],
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
senderDisplayName:kJSQDemoAvatarDisplayNameSquires
date:[NSDate distantPast]
text:@"Welcome to JSQMessages: A messaging UI framework for iOS."],
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdWoz
senderDisplayName:kJSQDemoAvatarDisplayNameWoz
date:[NSDate distantPast]
@ -125,9 +135,42 @@
text:@"It is unit-tested, free, open-source, and documented."],
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdSquires
senderDisplayName:kJSQDemoAvatarDisplayNameSquires
date:[NSDate date]
text:@"Now with media messages!"],
senderDisplayName:kJSQDemoAvatarDisplayNameSquires
date:[NSDate date]
text:@"Now with media messages!"],
[[JSQCall alloc] initWithCallerId:kJSQDemoAvatarIdWoz
callerDisplayName:kJSQDemoAvatarDisplayNameWoz
date:[NSDate date]
status:kCallIncoming],
[[JSQCall alloc] initWithCallerId:kJSQDemoAvatarIdWoz
callerDisplayName:kJSQDemoAvatarDisplayNameWoz
date:[NSDate date]
status:kCallMissed],
[[JSQInfoMessage alloc] initWithInfoType:JSQInfoMessageTypeSessionDidEnd
senderId:kJSQDemoAvatarIdCook
senderDisplayName:kJSQDemoAvatarDisplayNameCook
date:[NSDate date]],
[[JSQErrorMessage alloc] initWithErrorType:JSQErrorMessageMissingKeyId
senderId:kJSQDemoAvatarIdCook
senderDisplayName:kJSQDemoAvatarDisplayNameCook
date:[NSDate date]],
[[JSQErrorMessage alloc] initWithErrorType:JSQErrorMessageInvalidMessage
senderId:kJSQDemoAvatarIdCook
senderDisplayName:kJSQDemoAvatarDisplayNameCook
date:[NSDate date]],
[[JSQErrorMessage alloc] initWithErrorType:JSQErrorMessageInvalidVersion
senderId:kJSQDemoAvatarIdCook
senderDisplayName:kJSQDemoAvatarDisplayNameCook
date:[NSDate date]],
[[JSQErrorMessage alloc] initWithErrorType:JSQErrorMessageInvalidKeyException
senderId:kJSQDemoAvatarIdCook
senderDisplayName:kJSQDemoAvatarDisplayNameCook
date:[NSDate date]],
[[JSQErrorMessage alloc] initWithErrorType:JSQErrorMessageWrongTrustedIdentityKey
senderId:kJSQDemoAvatarIdCook
senderDisplayName:kJSQDemoAvatarDisplayNameCook
date:[NSDate date]],
nil];
[self addPhotoMediaMessage];

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -42,6 +42,22 @@
*/
+ (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
/**

View File

@ -54,6 +54,23 @@
alpha:1.0f];
}
+ (UIColor *)jsq_messageBubbleLightBlueColor
{
return [UIColor colorWithRed:137/255.f green:214/255.f blue:250/255.f alpha:1];
}
+ (UIColor *)jsq_messageBubbleGrayColor
{
return [UIColor colorWithRed:230/255.f green:230/255.f blue:230/255.f alpha:1];
}
+ (UIColor *)jsq_messageBackgroundGrayColor
{
return [UIColor colorWithRed:242.f/255 green:242.f/255 blue:242.f/255 alpha:1];
}
#pragma mark - Utilities
- (UIColor *)jsq_colorByDarkeningColorWithValue:(CGFloat)value

View File

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

View File

@ -143,6 +143,28 @@
*/
@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.
*

View File

@ -42,11 +42,16 @@
#import "UIColor+JSQMessages.h"
#import "UIDevice+JSQMessages.h"
#import "JSQCall.h"
#import "JSQCallCollectionViewCell.h"
#import "JSQInfoMessage.h"
#import "JSQErrorMessage.h"
#import "JSQDisplayedMessageCollectionViewCell.h"
static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObservingContext;
@interface JSQMessagesViewController () <JSQMessagesInputToolbarDelegate,
JSQMessagesKeyboardControllerDelegate>
@ -119,6 +124,7 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
- (void)jsq_configureMessagesViewController
{
self.view.backgroundColor = [UIColor whiteColor];
;
self.jsq_isObserving = NO;
@ -142,6 +148,10 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
self.incomingCellIdentifier = [JSQMessagesCollectionViewCellIncoming cellReuseIdentifier];
self.incomingMediaCellIdentifier = [JSQMessagesCollectionViewCellIncoming mediaCellReuseIdentifier];
self.callCellIndentifier = [JSQCallCollectionViewCell cellReuseIdentifier];
self.displayedMessageCellIndentifier = [JSQDisplayedMessageCollectionViewCell cellReuseIdentifier];
self.showTypingIndicator = NO;
self.showLoadEarlierMessagesHeader = NO;
@ -340,8 +350,8 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
[self.collectionView.collectionViewLayout invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
[self.collectionView reloadData];
if (self.automaticallyScrollsToMostRecentMessage && ![self jsq_isMenuVisible]) {
if (self.automaticallyScrollsToMostRecentMessage) {
[self scrollToBottomAnimated:animated];
}
}
@ -442,14 +452,102 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
NSParameterAssert(messageSenderId != nil);
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;
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;
}
else {
} else {
cellIdentifier = isOutgoingMessage ? self.outgoingCellIdentifier : self.incomingCellIdentifier;
}
JSQMessagesCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
@ -511,8 +609,8 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
cell.textView.dataDetectorTypes = UIDataDetectorTypeAll;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
return cell;
}
@ -555,8 +653,16 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
- (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];
BOOL isErrorOrInfoMessage = messageItem.messageType == TSInfoMessageAdapter || messageItem.messageType == TSErrorMessageAdapter;
BOOL isCall = messageItem.messageType == TSCallAdapter;
if (isErrorOrInfoMessage || isCall) {
return NO;
}
if ([messageItem isMediaMessage]) {
return NO;
}
@ -626,6 +732,8 @@ static void * kJSQMessagesKeyValueObservingContext = &kJSQMessagesKeyValueObserv
didTapCellAtIndexPath:(NSIndexPath *)indexPath
touchLocation:(CGPoint)touchLocation { }
#pragma mark - Input toolbar delegate
- (void)messagesInputToolbar:(JSQMessagesInputToolbar *)toolbar didPressLeftBarButton:(UIButton *)sender

View File

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

View File

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

View File

@ -27,7 +27,7 @@
+ (UIButton *)defaultAccessoryButtonItem
{
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]];
UIButton *accessoryButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, accessoryImage.size.width, 32.0f)];
@ -36,7 +36,7 @@
accessoryButton.contentMode = UIViewContentModeScaleAspectFit;
accessoryButton.backgroundColor = [UIColor clearColor];
accessoryButton.tintColor = [UIColor lightGrayColor];
//accessoryButton.tintColor = [UIColor lightGrayColor];
return accessoryButton;
}
@ -51,7 +51,7 @@
[sendButton setTitleColor:[[UIColor jsq_messageBubbleBlueColor] jsq_colorByDarkeningColorWithValue:0.1f] forState:UIControlStateHighlighted];
[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.minimumScaleFactor = 0.85f;
sendButton.contentMode = UIViewContentModeCenter;

View File

@ -33,6 +33,15 @@
#import "UIImage+JSQMessages.h"
#import "JSQCall.h"
#import "JSQCallCollectionViewCell.h"
#import "JSQDisplayedMessage.h"
#import "JSQDisplayedMessageCollectionViewCell.h"
#import "JSQErrorMessage.h"
#import "JSQInfoMessage.h"
const CGFloat kJSQMessagesCollectionViewCellLabelHeightDefault = 20.0f;
const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
@ -440,38 +449,46 @@ const CGFloat kJSQMessagesCollectionViewAvatarSizeDefault = 30.0f;
CGSize finalSize = CGSizeZero;
if ([messageItem isMediaMessage]) {
finalSize = [[messageItem media] mediaViewDisplaySize];
}
else {
CGSize avatarSize = [self jsq_avatarSizeForIndexPath:indexPath];
if (messageItem.messageType != TSCallAdapter && messageItem.messageType != TSErrorMessageAdapter && messageItem.messageType != TSInfoMessageAdapter) {
if ([messageItem isMediaMessage]) {
finalSize = [[messageItem media] mediaViewDisplaySize];
}
else {
CGSize avatarSize = [self jsq_avatarSizeForIndexPath:indexPath];
// from the cell xibs, there is a 2 point space between avatar and bubble
CGFloat spacingBetweenAvatarAndBubble = 2.0f;
CGFloat horizontalContainerInsets = self.messageBubbleTextViewTextContainerInsets.left + self.messageBubbleTextViewTextContainerInsets.right;
CGFloat horizontalFrameInsets = self.messageBubbleTextViewFrameInsets.left + self.messageBubbleTextViewFrameInsets.right;
// from the cell xibs, there is a 2 point space between avatar and bubble
CGFloat spacingBetweenAvatarAndBubble = 2.0f;
CGFloat horizontalContainerInsets = self.messageBubbleTextViewTextContainerInsets.left + self.messageBubbleTextViewTextContainerInsets.right;
CGFloat horizontalFrameInsets = self.messageBubbleTextViewFrameInsets.left + self.messageBubbleTextViewFrameInsets.right;
CGFloat horizontalInsetsTotal = horizontalContainerInsets + horizontalFrameInsets + spacingBetweenAvatarAndBubble;
CGFloat maximumTextWidth = self.itemWidth - avatarSize.width - self.messageBubbleLeftRightMargin - horizontalInsetsTotal;
CGFloat horizontalInsetsTotal = horizontalContainerInsets + horizontalFrameInsets + spacingBetweenAvatarAndBubble;
CGFloat maximumTextWidth = self.itemWidth - avatarSize.width - self.messageBubbleLeftRightMargin - horizontalInsetsTotal;
CGRect stringRect = [[messageItem text] boundingRectWithSize:CGSizeMake(maximumTextWidth, CGFLOAT_MAX)
CGRect stringRect = [[messageItem text] boundingRectWithSize:CGSizeMake(maximumTextWidth, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:@{ NSFontAttributeName : self.messageBubbleFont }
context:nil];
CGSize stringSize = CGRectIntegral(stringRect).size;
CGSize stringSize = CGRectIntegral(stringRect).size;
CGFloat verticalContainerInsets = self.messageBubbleTextViewTextContainerInsets.top + self.messageBubbleTextViewTextContainerInsets.bottom;
CGFloat verticalFrameInsets = self.messageBubbleTextViewFrameInsets.top + self.messageBubbleTextViewFrameInsets.bottom;
CGFloat verticalContainerInsets = self.messageBubbleTextViewTextContainerInsets.top + self.messageBubbleTextViewTextContainerInsets.bottom;
CGFloat verticalFrameInsets = self.messageBubbleTextViewFrameInsets.top + self.messageBubbleTextViewFrameInsets.bottom;
// add extra 2 points of space, because `boundingRectWithSize:` is slightly off
// not sure why. magix. (shrug) if you know, submit a PR
CGFloat verticalInsets = verticalContainerInsets + verticalFrameInsets + 2.0f;
CGFloat verticalInsets = verticalContainerInsets + verticalFrameInsets + 2.0f;
// same as above, an extra 2 points of magix
CGFloat finalWidth = MAX(stringSize.width + horizontalInsetsTotal, self.bubbleImageAssetWidth) + 2.0f;
CGFloat finalWidth = MAX(stringSize.width + horizontalInsetsTotal, self.bubbleImageAssetWidth) + 2.0f;
finalSize = CGSizeMake(finalWidth, stringSize.height + verticalInsets);
finalSize = CGSizeMake(finalWidth, stringSize.height + verticalInsets);
}
}
else if (messageItem.messageType == TSCallAdapter)
{
finalSize = CGSizeMake(kCallCellWidth, kCallCellHeight);
} else {
finalSize = CGSizeMake(kDisplayedMessageCellWidth, kDisplayedMessageCellHeight);
}
[self.messageBubbleCache setObject:[NSValue valueWithCGSize:finalSize] forKey:@(messageItem.hash)];

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View File

@ -20,6 +20,15 @@
#import "JSQMessageData.h"
typedef enum : NSUInteger {
kMessageNone,
kMessageSent,
kMessageRead,
kMessageReceived,
kMesageFailed
} MessageStatus;
/**
* The `JSQMessage` class is a concrete class for message model objects that represents a single user message.
* The message can be a text message or media message, depending on how it is initialized.
@ -51,6 +60,8 @@
*/
@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`.
@ -64,6 +75,9 @@
@property (copy, nonatomic, readonly) id<JSQMessageMediaData> media;
@property (nonatomic) TSMessageAdapterType messageType;
#pragma mark - Initialization
/**

View File

@ -19,6 +19,7 @@
#import "JSQMessage.h"
@interface JSQMessage ()
- (instancetype)initWithSenderId:(NSString *)senderId
@ -29,7 +30,6 @@
@end
@implementation JSQMessage
#pragma mark - Initialization
@ -97,6 +97,7 @@
_senderDisplayName = [senderDisplayName copy];
_date = [date copy];
_isMediaMessage = isMedia;
_messageType = TSGenericTextMessageAdapter;
}
return self;
}
@ -112,6 +113,7 @@
_senderId = nil;
_senderDisplayName = nil;
_date = nil;
_status = kMessageNone;
_text = nil;
_media = nil;
}

View File

@ -20,6 +20,16 @@
#import "JSQMessageMediaData.h"
typedef NS_ENUM(NSInteger, TSMessageAdapterType) {
TSIncomingMessageAdapter,
TSOutgoingMessageAdapter,
TSCallAdapter,
TSInfoMessageAdapter,
TSErrorMessageAdapter,
TSMediaAttachmentAdapter,
TSGenericTextMessageAdapter, //Used when message direction is unknown (outgoing or incoming)
};
/**
* The `JSQMessageData` protocol defines the common interface through which
* a `JSQMessagesViewController` and `JSQMessagesCollectionView` interact with message model objects.
@ -61,19 +71,7 @@
*/
- (NSDate *)date;
/**
* 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;
/**
* @return An integer that can be used as a table address in a hash table structure.
@ -96,4 +94,38 @@
*/
- (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

View File

@ -49,6 +49,7 @@
_cachedImageView = nil;
}
#pragma mark - Setters
- (void)setImage:(UIImage *)image

View 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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,6 +27,7 @@
#import "UIColor+JSQMessages.h"
#import "JSQCallCollectionViewCell.h"
@interface JSQMessagesCollectionView () <JSQMessagesLoadEarlierHeaderViewDelegate>
@ -67,6 +68,12 @@
[self registerNib:[JSQMessagesLoadEarlierHeaderView nib]
forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
withReuseIdentifier:[JSQMessagesLoadEarlierHeaderView headerReuseIdentifier]];
[self registerNib:[JSQCallCollectionViewCell nib]
forCellWithReuseIdentifier:[JSQCallCollectionViewCell cellReuseIdentifier]];
[self registerNib:[JSQDisplayedMessageCollectionViewCell nib]
forCellWithReuseIdentifier:[JSQDisplayedMessageCollectionViewCell cellReuseIdentifier]];
_typingIndicatorDisplaysOnLeft = YES;
_typingIndicatorMessageBubbleColor = [UIColor jsq_messageBubbleLightGrayColor];
@ -165,4 +172,15 @@
touchLocation:position];
}
- (void)displayedCollectionViewCellDidTapMessage:(JSQDisplayedMessageCollectionViewCell *)cell
{
NSIndexPath * indexPath = [self indexPathForCell:cell];
if (indexPath == nil) {
return;
}
[self.delegate collectionView:self didTapMessageBubbleAtIndexPath:indexPath];
}
@end

View File

@ -24,6 +24,7 @@
#import "UIView+JSQMessages.h"
#import "UIDevice+JSQMessages.h"
#import "UIColor+JSQMessages.h"
@interface JSQMessagesCollectionViewCell ()
@ -95,7 +96,6 @@
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
self.backgroundColor = [UIColor whiteColor];
self.cellTopLabelHeightConstraint.constant = 0.0f;
self.messageBubbleTopLabelHeightConstraint.constant = 0.0f;
self.cellBottomLabelHeightConstraint.constant = 0.0f;

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6250" systemVersion="14A389" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6250" systemVersion="14C68k" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6244"/>

View File

@ -48,9 +48,10 @@
CGFloat cornerRadius = 6.0f;
self.backgroundColor = [UIColor whiteColor];
self.layer.borderWidth = 0.5f;
self.layer.borderColor = [UIColor lightGrayColor].CGColor;
self.layer.cornerRadius = cornerRadius;
//Signal: Comment out elements of Composer view
// self.layer.borderWidth = 0.5f;
// self.layer.borderColor = [UIColor lightGrayColor].CGColor;
// self.layer.cornerRadius = cornerRadius;
self.scrollIndicatorInsets = UIEdgeInsetsMake(cornerRadius, 0.0f, cornerRadius, 0.0f);
@ -61,7 +62,8 @@
self.scrollsToTop = NO;
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.textAlignment = NSTextAlignmentNatural;

View File

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

View File

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