Merge pull request #1255 from WhisperSystems/update-jsqmvc

Unfork/Update JSQMessagesViewController
pull/1/head
Michael Kirk 9 years ago committed by GitHub
commit cca4bc451c

@ -1,14 +1,10 @@
---
BasedOnStyle: Chromium
AlignTrailingComments: true
AlignConsecutiveAssignments: true
AllowShortIfStatementsOnASingleLine: false
BreakBeforeBraces: Attach
BasedOnStyle: WebKit
AllowShortFunctionsOnASingleLine: false
BinPackArguments: false
BinPackParameters: false
ColumnLimit: 120
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: false
IndentCaseLabels: true
MaxEmptyLinesToKeep: 2
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true

@ -9,7 +9,7 @@ target 'Signal' do
pod 'FFCircularProgressView', '~> 0.5'
pod 'SCWaveformView', '~> 1.0'
pod 'DJWActionSheet'
pod 'JSQMessagesViewController', :git => 'https://github.com/WhisperSystems/JSQMessagesViewController', :branch => 'JSignalQ'
pod 'JSQMessagesViewController'
target 'SignalTests' do
inherit! :search_paths
end

@ -30,7 +30,7 @@ PODS:
- DJWActionSheet (1.0.4)
- FFCircularProgressView (0.5)
- HKDFKit (0.0.3)
- JSQMessagesViewController (7.1.0):
- JSQMessagesViewController (7.3.3):
- JSQSystemSoundPlayer (~> 2.0.1)
- JSQSystemSoundPlayer (2.0.1)
- libPhoneNumber-iOS (0.8.14)
@ -115,7 +115,7 @@ PODS:
DEPENDENCIES:
- DJWActionSheet
- FFCircularProgressView (~> 0.5)
- JSQMessagesViewController (from `https://github.com/WhisperSystems/JSQMessagesViewController`, branch `JSignalQ`)
- JSQMessagesViewController
- OpenSSL (~> 1.0.208)
- PastelogKit (~> 1.3)
- SCWaveformView (~> 1.0)
@ -123,18 +123,12 @@ DEPENDENCIES:
- SocketRocket (from `https://github.com/facebook/SocketRocket.git`)
EXTERNAL SOURCES:
JSQMessagesViewController:
:branch: JSignalQ
:git: https://github.com/WhisperSystems/JSQMessagesViewController
SignalServiceKit:
:git: https://github.com/WhisperSystems/SignalServiceKit.git
SocketRocket:
:git: https://github.com/facebook/SocketRocket.git
CHECKOUT OPTIONS:
JSQMessagesViewController:
:commit: 225b1baa11125ea84d4b960d700834b5b0a40ee1
:git: https://github.com/WhisperSystems/JSQMessagesViewController
SignalServiceKit:
:commit: f537b6f19265b0f0845f15b3155cdac4f1913dc6
:git: https://github.com/WhisperSystems/SignalServiceKit.git
@ -150,7 +144,7 @@ SPEC CHECKSUMS:
DJWActionSheet: 2fe54b1298a7f0fe44462233752c76a530e0cd80
FFCircularProgressView: 683a4ab1e1bd613246a3dffa61503ffdebcde8d8
HKDFKit: c058305d6f64b84f28c50bd7aa89574625bcb62a
JSQMessagesViewController: ca11f86fa68ca70835f05e169df9244147c1dc40
JSQMessagesViewController: 0ee3f80237268192a3e8337fd0d787f1a1bf5a7a
JSQSystemSoundPlayer: c5850e77a4363ffd374cd851154b9af93264ed8d
libPhoneNumber-iOS: fb165271ebe7fb32e55da97b83219382f2f9d409
Mantle: bc40bb061d8c2c6fb48d5083e04d928c3b7f73d9
@ -167,6 +161,6 @@ SPEC CHECKSUMS:
UnionFind: c33be5adb12983981d6e827ea94fc7f9e370f52d
YapDatabase: 713d4018cfacbd6e77dd430710ca84730e450980
PODFILE CHECKSUM: 860bce87f11d7ce3a8a80c10f8d35ef83699531e
PODFILE CHECKSUM: 060ff4edf8b7a110984cb2c1ffef3f6e19a6b8b6
COCOAPODS: 1.0.1

@ -9,9 +9,24 @@
/* Begin PBXBuildFile section */
0DD55B166906AF3368995978 /* libPods-Signal.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 80CD5E19DD23200E7926EEA7 /* libPods-Signal.a */; };
30209C98DABCE82064B4EAF5 /* libPods-SignalTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A33D3C7EB4B17BDBD47F0FCC /* libPods-SignalTests.a */; };
453D28B31D32B87100D523F0 /* OWSErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 453D28B01D32B87100D523F0 /* OWSErrorMessage.m */; };
453D28B41D32B87100D523F0 /* OWSInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 453D28B21D32B87100D523F0 /* OWSInfoMessage.m */; };
453D28B71D32BA5F00D523F0 /* OWSDisplayedMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 453D28B61D32BA5F00D523F0 /* OWSDisplayedMessage.m */; };
453D28BA1D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = 453D28B91D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m */; };
453D28BB1D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = 453D28B91D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m */; };
45843D1F1D2236B30013E85A /* OWSContactsSearcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */; };
45843D201D2236B30013E85A /* OWSContactsSearcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */; };
45843D221D223BA10013E85A /* OWSContactsSearcherTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D211D223BA10013E85A /* OWSContactsSearcherTest.m */; };
45C681B71D305A580050903A /* OWSCall.m in Sources */ = {isa = PBXBuildFile; fileRef = 45C681B61D305A580050903A /* OWSCall.m */; };
45C681B81D305A580050903A /* OWSCall.m in Sources */ = {isa = PBXBuildFile; fileRef = 45C681B61D305A580050903A /* OWSCall.m */; };
45C681BC1D305C080050903A /* OWSCallCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 45C681BA1D305C080050903A /* OWSCallCollectionViewCell.m */; };
45C681BD1D305C080050903A /* OWSCallCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 45C681BA1D305C080050903A /* OWSCallCollectionViewCell.m */; };
45C681C41D305C9E0050903A /* OWSCallCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 45C681C01D305C9E0050903A /* OWSCallCollectionViewCell.xib */; };
45C681C51D305C9E0050903A /* OWSCallCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 45C681C01D305C9E0050903A /* OWSCallCollectionViewCell.xib */; };
45C681C61D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 45C681C21D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.m */; };
45C681C71D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 45C681C21D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.m */; };
45C681C81D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 45C681C31D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.xib */; };
45C681C91D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 45C681C31D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.xib */; };
45CB2FA81CB7146C00E1B343 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */; };
4CE0E3771B954546007210CF /* TSAnimatedAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE0E3761B954546007210CF /* TSAnimatedAdapter.m */; };
701231B518ECAA4500D456C4 /* EvpMessageDigest.m in Sources */ = {isa = PBXBuildFile; fileRef = 701231B418ECAA4500D456C4 /* EvpMessageDigest.m */; };
@ -131,7 +146,6 @@
A5509ECD1A69B1D600ABA4BC /* CountryCodeTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A5509ECC1A69B1D600ABA4BC /* CountryCodeTableViewCell.m */; };
A56977911A351BC400173BF2 /* ScanIdentityBarcodeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A569778E1A351BC400173BF2 /* ScanIdentityBarcodeViewController.m */; };
A56977921A351BC400173BF2 /* PresentIdentityQRCodeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A569778F1A351BC400173BF2 /* PresentIdentityQRCodeViewController.m */; };
A5988A811A8A70D0002AD6BE /* UIButton+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = A5988A801A8A70D0002AD6BE /* UIButton+OWS.m */; };
A5D0699B1A50E9CB004CB540 /* ShowGroupMembersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A5D069991A50E9CB004CB540 /* ShowGroupMembersViewController.m */; };
A5E9D4BB1A65FAD800E4481C /* TSVideoAttachmentAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = A5E9D4B91A65FAD800E4481C /* TSVideoAttachmentAdapter.m */; };
AD41D7B51A6F6F0600241130 /* play_button.png in Resources */ = {isa = PBXBuildFile; fileRef = AD41D7B31A6F6F0600241130 /* play_button.png */; };
@ -327,7 +341,6 @@
B660F7701C29988E00687D6E /* FLAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = B68EF9B71C0B1EBD009C3DCD /* FLAnimatedImage.m */; };
B660F7711C29988E00687D6E /* FLAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = B68EF9B91C0B1EBD009C3DCD /* FLAnimatedImageView.m */; };
B660F7721C29988E00687D6E /* AppStoreRating.m in Sources */ = {isa = PBXBuildFile; fileRef = B6DA6B061B8A2F9A00CA6F98 /* AppStoreRating.m */; };
B660F7731C29988E00687D6E /* UIButton+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = A5988A801A8A70D0002AD6BE /* UIButton+OWS.m */; };
B660F7741C29988E00687D6E /* DJWActionSheet+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = A547DD721A70A87800103EC7 /* DJWActionSheet+OWS.m */; };
B660F7751C29988E00687D6E /* UIColor+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = FCFA64B31A24F3880007FB87 /* UIColor+OWS.m */; };
B660F7761C29988E00687D6E /* UIFont+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = FCFA64B61A24F6730007FB87 /* UIFont+OWS.m */; };
@ -491,10 +504,26 @@
/* Begin PBXFileReference section */
453CC0361D08E1A60040EBA3 /* sn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sn; path = translations/sn.lproj/Localizable.strings; sourceTree = "<group>"; };
453D28AF1D32B87100D523F0 /* OWSErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSErrorMessage.h; sourceTree = "<group>"; };
453D28B01D32B87100D523F0 /* OWSErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSErrorMessage.m; sourceTree = "<group>"; };
453D28B11D32B87100D523F0 /* OWSInfoMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSInfoMessage.h; sourceTree = "<group>"; };
453D28B21D32B87100D523F0 /* OWSInfoMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSInfoMessage.m; sourceTree = "<group>"; };
453D28B51D32BA5F00D523F0 /* OWSDisplayedMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDisplayedMessage.h; sourceTree = "<group>"; };
453D28B61D32BA5F00D523F0 /* OWSDisplayedMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisplayedMessage.m; sourceTree = "<group>"; };
453D28B81D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessagesBubblesSizeCalculator.h; sourceTree = "<group>"; };
453D28B91D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessagesBubblesSizeCalculator.m; sourceTree = "<group>"; };
454B35071D08EED80026D658 /* mk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = mk; path = translations/mk.lproj/Localizable.strings; sourceTree = "<group>"; };
45843D1D1D2236B30013E85A /* OWSContactsSearcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactsSearcher.h; sourceTree = "<group>"; };
45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsSearcher.m; sourceTree = "<group>"; };
45843D211D223BA10013E85A /* OWSContactsSearcherTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsSearcherTest.m; sourceTree = "<group>"; };
45C681B51D305A580050903A /* OWSCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSCall.h; sourceTree = "<group>"; };
45C681B61D305A580050903A /* OWSCall.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSCall.m; sourceTree = "<group>"; };
45C681B91D305C080050903A /* OWSCallCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSCallCollectionViewCell.h; sourceTree = "<group>"; };
45C681BA1D305C080050903A /* OWSCallCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSCallCollectionViewCell.m; sourceTree = "<group>"; };
45C681C01D305C9E0050903A /* OWSCallCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OWSCallCollectionViewCell.xib; sourceTree = "<group>"; };
45C681C11D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDisplayedMessageCollectionViewCell.h; sourceTree = "<group>"; };
45C681C21D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisplayedMessageCollectionViewCell.m; sourceTree = "<group>"; };
45C681C31D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OWSDisplayedMessageCollectionViewCell.xib; sourceTree = "<group>"; };
45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = "Launch Screen.storyboard"; path = "Signal/src/util/Launch Screen.storyboard"; sourceTree = SOURCE_ROOT; };
45E282DE1D08E67800ADD4C8 /* gl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = gl; path = translations/gl.lproj/Localizable.strings; sourceTree = "<group>"; };
45E282DF1D08E6CC00ADD4C8 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = translations/id.lproj/Localizable.strings; sourceTree = "<group>"; };
@ -723,8 +752,6 @@
A569778E1A351BC400173BF2 /* ScanIdentityBarcodeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ScanIdentityBarcodeViewController.m; sourceTree = "<group>"; };
A569778F1A351BC400173BF2 /* PresentIdentityQRCodeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PresentIdentityQRCodeViewController.m; sourceTree = "<group>"; };
A56977901A351BC400173BF2 /* PresentIdentityQRCodeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PresentIdentityQRCodeViewController.h; sourceTree = "<group>"; };
A5988A7F1A8A70D0002AD6BE /* UIButton+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIButton+OWS.h"; path = "util/UIButton+OWS.h"; sourceTree = "<group>"; };
A5988A801A8A70D0002AD6BE /* UIButton+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIButton+OWS.m"; path = "util/UIButton+OWS.m"; sourceTree = "<group>"; };
A5D069991A50E9CB004CB540 /* ShowGroupMembersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ShowGroupMembersViewController.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
A5D0699A1A50E9CB004CB540 /* ShowGroupMembersViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShowGroupMembersViewController.h; sourceTree = "<group>"; };
A5E9D4B91A65FAD800E4481C /* TSVideoAttachmentAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSVideoAttachmentAdapter.m; sourceTree = "<group>"; };
@ -1094,6 +1121,16 @@
isa = PBXGroup;
children = (
B62D53F41A23CC8B009AAF82 /* TSMessageAdapters */,
453D28B51D32BA5F00D523F0 /* OWSDisplayedMessage.h */,
453D28B61D32BA5F00D523F0 /* OWSDisplayedMessage.m */,
453D28AF1D32B87100D523F0 /* OWSErrorMessage.h */,
453D28B01D32B87100D523F0 /* OWSErrorMessage.m */,
453D28B11D32B87100D523F0 /* OWSInfoMessage.h */,
453D28B21D32B87100D523F0 /* OWSInfoMessage.m */,
45C681B51D305A580050903A /* OWSCall.h */,
45C681B61D305A580050903A /* OWSCall.m */,
453D28B81D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.h */,
453D28B91D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m */,
);
path = Models;
sourceTree = "<group>";
@ -1638,6 +1675,12 @@
76EB052B18170B33006006FC /* Views */ = {
isa = PBXGroup;
children = (
45C681C11D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.h */,
45C681C21D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.m */,
45C681C31D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.xib */,
45C681B91D305C080050903A /* OWSCallCollectionViewCell.h */,
45C681BA1D305C080050903A /* OWSCallCollectionViewCell.m */,
45C681C01D305C9E0050903A /* OWSCallCollectionViewCell.xib */,
A5509ECB1A69B1D600ABA4BC /* CountryCodeTableViewCell.h */,
A5509ECC1A69B1D600ABA4BC /* CountryCodeTableViewCell.m */,
FCAC963D19FEF99A0046DFC5 /* InboxTableViewCell.h */,
@ -2199,8 +2242,6 @@
FCFA64B11A24F29E0007FB87 /* UI Categories */ = {
isa = PBXGroup;
children = (
A5988A7F1A8A70D0002AD6BE /* UIButton+OWS.h */,
A5988A801A8A70D0002AD6BE /* UIButton+OWS.m */,
A547DD731A70A87800103EC7 /* DJWActionSheet+OWS.h */,
A547DD721A70A87800103EC7 /* DJWActionSheet+OWS.m */,
FCFA64B21A24F3880007FB87 /* UIColor+OWS.h */,
@ -2399,6 +2440,7 @@
A5509ECA1A69AB8B00ABA4BC /* Storyboard.storyboard in Resources */,
A507A3B11A6C60E300BEED0D /* InboxTableViewCell.xib in Resources */,
AD83FF421A73426500B5C81A /* audio_play_button.png in Resources */,
45C681C41D305C9E0050903A /* OWSCallCollectionViewCell.xib in Resources */,
B633C5C41A1D190B0059AC12 /* mute_on@2x.png in Resources */,
B633C5CE1A1D190B0059AC12 /* quit@2x.png in Resources */,
AD83FF441A73426500B5C81A /* audio_pause_button.png in Resources */,
@ -2407,6 +2449,7 @@
B633C59D1A1D190B0059AC12 /* endcall@2x.png in Resources */,
FC5CDF391A3393DD00B47253 /* error_white@2x.png in Resources */,
B633C5D21A1D190B0059AC12 /* savephoto@2x.png in Resources */,
45C681C81D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.xib in Resources */,
B10C9B611A7049EC00ECA2BF /* play_icon.png in Resources */,
AD83FF401A73426500B5C81A /* audio_pause_button_blue@2x.png in Resources */,
B66DBF4A19D5BBC8006EA940 /* Images.xcassets in Resources */,
@ -2443,6 +2486,8 @@
files = (
B660F6D41C29868000687D6E /* whisperFake.cer in Resources */,
76EB060118170B33006006FC /* InitiateSignal.proto in Resources */,
45C681C91D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.xib in Resources */,
45C681C51D305C9E0050903A /* OWSCallCollectionViewCell.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -2578,7 +2623,6 @@
B6B9ECFC198B31BA00C620D3 /* PushManager.m in Sources */,
76EB05D618170B33006006FC /* ZrtpResponder.m in Sources */,
B62D53F71A23CCAD009AAF82 /* TSMessageAdapter.m in Sources */,
A5988A811A8A70D0002AD6BE /* UIButton+OWS.m in Sources */,
FCD274EB1A5AFDDB00202277 /* AboutTableViewController.m in Sources */,
E197B61618BBEC1A00F073E5 /* StretchFactorController.m in Sources */,
FCFD257F1A154B2C00F4C644 /* RegistrationViewController.m in Sources */,
@ -2601,6 +2645,7 @@
76EB05A618170B33006006FC /* RtpPacket.m in Sources */,
76EB064218170B33006006FC /* StringUtil.m in Sources */,
A547DD741A70A87800103EC7 /* DJWActionSheet+OWS.m in Sources */,
45C681B71D305A580050903A /* OWSCall.m in Sources */,
76EB062618170B33006006FC /* Queue.m in Sources */,
D221A09A169C9E5E00537ABF /* main.m in Sources */,
45843D1F1D2236B30013E85A /* OWSContactsSearcher.m in Sources */,
@ -2611,15 +2656,18 @@
76EB05FE18170B33006006FC /* InitiateSignal.pb.m in Sources */,
76EB05CA18170B33006006FC /* RecipientUnavailable.m in Sources */,
E197B61418BBEC1A00F073E5 /* DropoutTracker.m in Sources */,
453D28B41D32B87100D523F0 /* OWSInfoMessage.m in Sources */,
FCAC963C19FEF9280046DFC5 /* SignalsViewController.m in Sources */,
76EB05DA18170B33006006FC /* LowLatencyConnector.m in Sources */,
76EB05EE18170B33006006FC /* CallTermination.m in Sources */,
B66B9F7D1AEAF40500E2E609 /* NotificationSettingsOptionsViewController.m in Sources */,
453D28B31D32B87100D523F0 /* OWSErrorMessage.m in Sources */,
E1CD329618BCFF9900B1A496 /* SoundInstance.m in Sources */,
76EB05B418170B33006006FC /* HashChain.m in Sources */,
76EB05E418170B33006006FC /* UdpSocket.m in Sources */,
76EB058218170B33006006FC /* Environment.m in Sources */,
76EB064418170B33006006FC /* ThreadManager.m in Sources */,
45C681C61D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.m in Sources */,
E197B61E18BBEC6D00F073E5 /* AudioRouter.m in Sources */,
E197B60D18BBEC1A00F073E5 /* AudioSocket.m in Sources */,
A5D0699B1A50E9CB004CB540 /* ShowGroupMembersViewController.m in Sources */,
@ -2632,6 +2680,7 @@
B63761ED19E1FBE8005735D1 /* HttpRequestOrResponse.m in Sources */,
76EB05A018170B33006006FC /* IpAddress.m in Sources */,
FCAC965119FF0A6E0046DFC5 /* MessagesViewController.m in Sources */,
453D28BA1D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m in Sources */,
B68EF9BB1C0B1EBD009C3DCD /* FLAnimatedImageView.m in Sources */,
A5E9D4BB1A65FAD800E4481C /* TSVideoAttachmentAdapter.m in Sources */,
E197B61118BBEC1A00F073E5 /* AudioProcessor.m in Sources */,
@ -2670,6 +2719,7 @@
E16E5BF018AAC40200B7C403 /* EvpKeyAgreement.m in Sources */,
FCFD25821A154B3800F4C644 /* CodeVerificationViewController.m in Sources */,
B65EDA1219E1BE6400AAA7CB /* RPAPICall.m in Sources */,
453D28B71D32BA5F00D523F0 /* OWSDisplayedMessage.m in Sources */,
76EB05DC18170B33006006FC /* StreamPair.m in Sources */,
76EB064618170B33006006FC /* TimeUtil.m in Sources */,
70BAFD5D190584BE00FA5E0B /* NotificationTracker.m in Sources */,
@ -2707,6 +2757,7 @@
B63761E319E1F487005735D1 /* AFHTTPSessionManager+SignalMethods.m in Sources */,
76EB05CC18170B33006006FC /* ShortAuthenticationStringGenerator.m in Sources */,
E16E5BEF18AAC40200B7C403 /* EC25KeyAgreementProtocol.m in Sources */,
45C681BC1D305C080050903A /* OWSCallCollectionViewCell.m in Sources */,
76EB064018170B33006006FC /* AnonymousTerminator.m in Sources */,
76EB058818170B33006006FC /* PropertyListPreferences.m in Sources */,
76EB05B218170B33006006FC /* DH3KKeyAgreementProtocol.m in Sources */,
@ -2785,6 +2836,7 @@
B660F7341C29988E00687D6E /* RtpSocket.m in Sources */,
B660F7351C29988E00687D6E /* SequenceCounter.m in Sources */,
B660F7361C29988E00687D6E /* SrtpSocket.m in Sources */,
45C681C71D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.m in Sources */,
B660F7371C29988E00687D6E /* SrtpStream.m in Sources */,
B660F7381C29988E00687D6E /* DH3KKeyAgreementParticipant.m in Sources */,
B660F7391C29988E00687D6E /* DH3KKeyAgreementProtocol.m in Sources */,
@ -2805,6 +2857,7 @@
B660F7481C29988E00687D6E /* RecipientUnavailable.m in Sources */,
45843D201D2236B30013E85A /* OWSContactsSearcher.m in Sources */,
B660F7491C29988E00687D6E /* ShortAuthenticationStringGenerator.m in Sources */,
45C681BD1D305C080050903A /* OWSCallCollectionViewCell.m in Sources */,
B660F74A1C29988E00687D6E /* ZrtpHandshakeResult.m in Sources */,
B660F74B1C29988E00687D6E /* ZrtpHandshakeSocket.m in Sources */,
B660F74C1C29988E00687D6E /* ZrtpInitiator.m in Sources */,
@ -2815,6 +2868,7 @@
B660F7511C29988E00687D6E /* StreamPair.m in Sources */,
B660F7521C29988E00687D6E /* Certificate.m in Sources */,
B660F7531C29988E00687D6E /* NetworkStream.m in Sources */,
453D28BB1D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m in Sources */,
B660F7541C29988E00687D6E /* SecureEndPoint.m in Sources */,
B660F7551C29988E00687D6E /* UdpSocket.m in Sources */,
45843D221D223BA10013E85A /* OWSContactsSearcherTest.m in Sources */,
@ -2835,6 +2889,7 @@
B660F7641C29988E00687D6E /* InitiateSignal.pb.m in Sources */,
B660F7651C29988E00687D6E /* InitiatorSessionDescriptor.m in Sources */,
B660F7661C29988E00687D6E /* ResponderSessionDescriptor.m in Sources */,
45C681B81D305A580050903A /* OWSCall.m in Sources */,
B660F7671C29988E00687D6E /* SignalUtil.m in Sources */,
B660F7681C29988E00687D6E /* CategorizingLogger.m in Sources */,
B660F7691C29988E00687D6E /* DecayingSampleEstimator.m in Sources */,
@ -2847,7 +2902,6 @@
B660F7701C29988E00687D6E /* FLAnimatedImage.m in Sources */,
B660F7711C29988E00687D6E /* FLAnimatedImageView.m in Sources */,
B660F7721C29988E00687D6E /* AppStoreRating.m in Sources */,
B660F7731C29988E00687D6E /* UIButton+OWS.m in Sources */,
B660F7741C29988E00687D6E /* DJWActionSheet+OWS.m in Sources */,
B660F7751C29988E00687D6E /* UIColor+OWS.m in Sources */,
B660F7761C29988E00687D6E /* UIFont+OWS.m in Sources */,

@ -0,0 +1,60 @@
// Created by Dylan Bourgeois on 20/11/14.
// Portions Copyright (c) 2016 Open Whisper Systems. All rights reserved.
#import "TSMessageAdapter.h"
#import <Foundation/Foundation.h>
#import <JSQMessagesViewController/JSQMessageData.h>
typedef enum : NSUInteger {
kCallOutgoing = 1,
kCallIncoming = 2,
kCallMissed = 3,
kGroupUpdateJoin = 4,
kGroupUpdateLeft = 5,
kGroupUpdate = 6
} CallStatus;
@interface OWSCall : 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;
/**
* String to be displayed
*/
@property (nonatomic, copy) NSString *detailString;
#pragma mark - Initialization
- (instancetype)initWithCallerId:(NSString *)callerId
callerDisplayName:(NSString *)callerDisplayName
date:(NSDate *)date
status:(CallStatus)status
displayString:(NSString *)detailString NS_DESIGNATED_INITIALIZER;
- (NSString *)dateText;
@end

@ -0,0 +1,144 @@
// Created by Dylan Bourgeois on 20/11/14.
// Portions Copyright (c) 2016 Open Whisper Systems. All rights reserved.
#import "OWSCall.h"
#import <JSQMessagesViewController/JSQMessagesTimestampFormatter.h>
#import <JSQMessagesViewController/UIImage+JSQMessages.h>
@implementation OWSCall
#pragma mark - Initialzation
- (id)init
{
NSAssert(NO,
@"%s is not a valid initializer for %@. Use %@ instead",
__PRETTY_FUNCTION__,
[self class],
NSStringFromSelector(@selector(initWithCallerId:callerDisplayName:date:status:displayString:)));
return [self initWithCallerId:nil callerDisplayName:nil date:nil status:0 displayString:nil];
}
- (instancetype)initWithCallerId:(NSString *)senderId
callerDisplayName:(NSString *)senderDisplayName
date:(NSDate *)date
status:(CallStatus)status
displayString:(NSString *)detailString
{
NSParameterAssert(senderId != nil);
NSParameterAssert(senderDisplayName != nil);
self = [super init];
if (!self) {
return self;
}
_senderId = [senderId copy];
_senderDisplayName = [senderDisplayName copy];
_date = [date copy];
_status = status;
_messageType = TSCallAdapter;
// TODO interpret detailString from status. make sure it works for calls and
// our re-use of calls as group update display
_detailString = [detailString stringByAppendingFormat:@" "];
return self;
}
- (NSString *)dateText
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.timeStyle = NSDateFormatterShortStyle;
dateFormatter.dateStyle = NSDateFormatterMediumStyle;
dateFormatter.doesRelativeDateFormatting = YES;
return [dateFormatter stringFromDate:_date];
}
#pragma mark - NSObject
- (BOOL)isEqual:(id)object
{
if (self == object) {
return YES;
}
if (![object isKindOfClass:[self class]]) {
return NO;
}
OWSCall *aCall = (OWSCall *)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 - JSQMessageData
- (BOOL)isMediaMessage
{
return NO;
}
#pragma mark - NSCoding
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
NSString *senderId = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(senderId))];
NSString *senderDisplayName = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(senderDisplayName))];
NSDate *date = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(date))];
CallStatus status = (CallStatus)[aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(status))];
NSString *displayString = @""; // FIXME what should this be?
return [self initWithCallerId:senderId
callerDisplayName:senderDisplayName
date:date
status:status
displayString:displayString];
}
- (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
displayString:self.detailString];
}
- (NSUInteger)messageHash
{
return self.hash;
}
- (NSString *)text
{
return _detailString;
}
@end

@ -0,0 +1,38 @@
// Created by Dylan Bourgeois on 29/11/14.
// Copyright (c) 2014 Hexed Bits. All rights reserved.
// Portions Copyright (c) 2016 Open Whisper Systems. All rights reserved.
#import "JSQMessageData.h"
#import <Foundation/Foundation.h>
/* OWSDisplayedMessage message is the parent class for displaying information to the user
* from within the conversation view. Do not use directly :
*
* @see OWSInfoMessage
* @see OWSErrorMessage
*
*/
@interface OWSDisplayedMessage : 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

@ -0,0 +1,45 @@
// Created by Dylan Bourgeois on 29/11/14.
// Copyright (c) 2014 Hexed Bits. All rights reserved.
// Portions Copyright (c) 2016 Open Whisper Systems. All rights reserved.
#import "OWSDisplayedMessage.h"
@implementation OWSDisplayedMessage
- (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) {
return self;
}
_senderId = [senderId copy];
_senderDisplayName = [senderDisplayName copy];
_date = [date copy];
return self;
}
- (NSUInteger)messageHash
{
return self.date.hash ^ self.senderId.hash;
}
- (BOOL)isMediaMessage
{
return NO;
}
@end

@ -0,0 +1,32 @@
// Created by Dylan Bourgeois on 29/11/14.
// Copyright (c) 2014 Hexed Bits. All rights reserved.
// Portions Copyright (c) 2016 Open Whisper Systems. All rights reserved.
#import "OWSDisplayedMessage.h"
#import "TSMessageAdapter.h"
typedef NS_ENUM(NSInteger, OWSErrorMessageType) {
OWSErrorMessageNoSession,
OWSErrorMessageWrongTrustedIdentityKey,
OWSErrorMessageInvalidKeyException,
OWSErrorMessageMissingKeyId,
OWSErrorMessageInvalidMessage,
OWSErrorMessageDuplicateMessage,
OWSErrorMessageInvalidVersion
};
@interface OWSErrorMessage : OWSDisplayedMessage
@property (nonatomic) OWSErrorMessageType errorMessageType;
@property (nonatomic) TSMessageAdapterType messageType;
#pragma mark - Initialization
- (instancetype)initWithErrorType:(OWSErrorMessageType)messageType
senderId:(NSString *)senderId
senderDisplayName:(NSString *)senderDisplayName
date:(NSDate *)date;
- (NSString *)text;
@end

@ -0,0 +1,75 @@
// Created by Dylan Bourgeois on 29/11/14.
// Copyright (c) 2014 Hexed Bits. All rights reserved.
#import "OWSErrorMessage.h"
@implementation OWSErrorMessage
- (instancetype)initWithErrorType:(OWSErrorMessageType)messageType
senderId:(NSString *)senderId
senderDisplayName:(NSString *)senderDisplayName
date:(NSDate *)date
{
self = [super initWithSenderId:senderId senderDisplayName:senderDisplayName date:date];
if (!self) {
return self;
}
_errorMessageType = messageType;
_messageType = TSErrorMessageAdapter;
return self;
}
- (NSString *)text
{
switch (self.errorMessageType) {
case OWSErrorMessageNoSession:
return [NSString stringWithFormat:@"No session error"];
break;
case OWSErrorMessageWrongTrustedIdentityKey:
return [NSString stringWithFormat:@"Error : Wrong trusted identity key for %@.", self.senderDisplayName];
break;
case OWSErrorMessageInvalidKeyException:
return [NSString stringWithFormat:@"Error : Invalid key exception for %@.", self.senderDisplayName];
break;
case OWSErrorMessageMissingKeyId:
return [NSString stringWithFormat:@"Error: Missing key identifier for %@", self.senderDisplayName];
break;
case OWSErrorMessageInvalidMessage:
return [NSString stringWithFormat:@"Error: Invalid message"];
break;
case OWSErrorMessageDuplicateMessage:
return [NSString stringWithFormat:@"Error: Duplicate message"];
break;
case OWSErrorMessageInvalidVersion:
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

@ -0,0 +1,26 @@
// Created by Dylan Bourgeois on 29/11/14.
// Copyright (c) 2014 Hexed Bits. All rights reserved.
// Portions Copyright (c) 2016 Open Whisper Systems. All rights reserved.
#import "OWSDisplayedMessage.h"
#import "TSMessageAdapter.h"
typedef NS_ENUM(NSInteger, OWSInfoMessageType) {
OWSInfoMessageTypeSessionDidEnd,
};
@interface OWSInfoMessage : OWSDisplayedMessage
@property (nonatomic) OWSInfoMessageType infoMessageType;
@property (nonatomic) TSMessageAdapterType messageType;
#pragma mark - Initialization
- (instancetype)initWithInfoType:(OWSInfoMessageType)messageType
senderId:(NSString *)senderId
senderDisplayName:(NSString *)senderDisplayName
date:(NSDate *)date;
- (NSString *)text;
@end

@ -0,0 +1,55 @@
// Created by Dylan Bourgeois on 29/11/14.
// Copyright (c) 2014 Hexed Bits. All rights reserved.
// Portions Copyright (c) 2016 Open Whisper Systems. All rights reserved.
#import "OWSInfoMessage.h"
@implementation OWSInfoMessage
- (instancetype)initWithInfoType:(OWSInfoMessageType)messageType
senderId:(NSString *)senderId
senderDisplayName:(NSString *)senderDisplayName
date:(NSDate *)date
{
//@discussion: NSParameterAssert() ?
self = [super initWithSenderId:senderId senderDisplayName:senderDisplayName date:date];
if (!self) {
return self;
}
_infoMessageType = messageType;
_messageType = TSInfoMessageAdapter;
return self;
}
- (NSString *)text
{
switch (self.infoMessageType) {
case OWSInfoMessageTypeSessionDidEnd:
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

@ -0,0 +1,7 @@
// Copyright (c) 2016 Open Whisper Systems. All rights reserved.
#import <JSQMessagesViewController/JSQMessagesBubblesSizeCalculator.h>
@interface OWSMessagesBubblesSizeCalculator : JSQMessagesBubblesSizeCalculator
@end

@ -0,0 +1,36 @@
// Copyright (c) 2016 Open Whisper Systems. All rights reserved.
#import "OWSMessagesBubblesSizeCalculator.h"
#import "OWSDisplayedMessageCollectionViewCell.h"
#import "TSMessageAdapter.h"
@implementation OWSMessagesBubblesSizeCalculator
/**
* Computes and returns the size of the `messageBubbleImageView` property
* of a `JSQMessagesCollectionViewCell` for the specified messageData at indexPath.
*
* @param messageData A message data object.
* @param indexPath The index path at which messageData is located.
* @param layout The layout object asking for this information.
*
* @return A sizes that specifies the required dimensions to display the entire message contents.
* Note, this is *not* the entire cell, but only its message bubble.
*/
- (CGSize)messageBubbleSizeForMessageData:(id<JSQMessageData>)messageData
atIndexPath:(NSIndexPath *)indexPath
withLayout:(JSQMessagesCollectionViewFlowLayout *)layout
{
CGSize superSize = [super messageBubbleSizeForMessageData:messageData atIndexPath:indexPath withLayout:layout];
TSMessageAdapter *message = (TSMessageAdapter *)messageData;
if (message.messageType == TSInfoMessageAdapter || message.messageType == TSErrorMessageAdapter) {
// Prevent cropping message text by accounting for message container/icon
superSize.height = OWSDisplayedMessageCellHeight;
}
return superSize;
}
@end

@ -7,10 +7,9 @@
//
#import "TSAnimatedAdapter.h"
#import "FLAnimatedImage.h"
#import "JSQMessagesMediaViewBubbleImageMasker.h"
#import "UIDevice+TSHardwareVersion.h"
#import <JSQMessagesViewController/JSQMessagesMediaViewBubbleImageMasker.h>
@interface TSAnimatedAdapter ()

@ -8,13 +8,22 @@
#import <Foundation/Foundation.h>
#import <JSQMessagesViewController/JSQMessageData.h>
#import "TSInteraction.h"
#import "TSMessageAdapter.h"
#import "TSThread.h"
#define ME_MESSAGE_IDENTIFIER @"Me";
typedef NS_ENUM(NSInteger, TSMessageAdapterType) {
TSIncomingMessageAdapter,
TSOutgoingMessageAdapter,
TSCallAdapter,
TSInfoMessageAdapter,
TSErrorMessageAdapter,
TSMediaAttachmentAdapter,
TSGenericTextMessageAdapter, // Used when message direction is unknown (outgoing or incoming)
};
@interface TSMessageAdapter : NSObject <JSQMessageData>
+ (id<JSQMessageData>)messageViewDataWithInteraction:(TSInteraction *)interaction inThread:(TSThread *)thread;

@ -6,9 +6,9 @@
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import "JSQCall.h"
#import "TSAttachmentPointer.h"
#import "TSCall.h"
#import "OWSCall.h"
#import "TSContentAdapters.h"
#import "TSErrorMessage.h"
#import "TSIncomingMessage.h"
@ -58,6 +58,7 @@
+ (id<JSQMessageData>)messageViewDataWithInteraction:(TSInteraction *)interaction inThread:(TSThread *)thread {
TSMessageAdapter *adapter = [[TSMessageAdapter alloc] init];
adapter.messageDate = interaction.date;
// TODO casting a string to an integer? At least need a comment here explaining why we are doing this.
adapter.identifier = (NSUInteger)interaction.uniqueId;
if ([thread isKindOfClass:[TSContactThread class]]) {
@ -136,8 +137,7 @@
} else if ([interaction isKindOfClass:[TSCall class]]) {
adapter.messageBody = @"Placeholder for TSCalls";
adapter.messageType = TSCallAdapter;
JSQCall *call = [self jsqCallForTSCall:(TSCall *)interaction thread:(TSContactThread *)thread];
call.useThumbnail = NO; // disables use of iconography to represent group update actions
OWSCall *call = [self owsCallForTSCall:(TSCall *)interaction thread:(TSContactThread *)thread];
return call;
} else if ([interaction isKindOfClass:[TSInfoMessage class]]) {
TSInfoMessage *infoMessage = (TSInfoMessage *)interaction;
@ -154,12 +154,11 @@
} else if (adapter.infoMessageType == TSInfoMessageTypeGroupUpdate) {
status = kGroupUpdate;
}
JSQCall *call = [[JSQCall alloc] initWithCallerId:@""
OWSCall *call = [[OWSCall alloc] initWithCallerId:@""
callerDisplayName:adapter.messageBody
date:nil
status:status
displayString:@""];
call.useThumbnail = NO; // disables use of iconography to represent group update actions
return call;
}
} else {
@ -176,7 +175,7 @@
return adapter;
}
+ (JSQCall *)jsqCallForTSCall:(TSCall *)call thread:(TSContactThread *)thread {
+ (OWSCall *)owsCallForTSCall:(TSCall *)call thread:(TSContactThread *)thread {
CallStatus status = 0;
NSString *name = thread.name;
NSString *detailString = @"";
@ -210,12 +209,12 @@
break;
}
JSQCall *jsqCall = [[JSQCall alloc] initWithCallerId:thread.contactIdentifier
OWSCall *owsCall = [[OWSCall alloc] initWithCallerId:thread.contactIdentifier
callerDisplayName:thread.name
date:call.date
status:status
displayString:detailString];
return jsqCall;
return owsCall;
}
- (NSString *)senderId {
@ -230,7 +229,7 @@
if (self.thread) {
return _thread.name;
}
return self.senderDisplayName;
return _senderDisplayName;
}
- (NSDate *)date {
@ -249,8 +248,13 @@
return self.messageBody;
}
- (NSUInteger)messageHash {
return self.identifier;
- (NSUInteger)messageHash
{
if (self.isMediaMessage) {
return [self.mediaItem mediaHash];
} else {
return self.identifier;
}
}
- (NSInteger)messageState {

@ -1,10 +1,5 @@
//
// TSAttachementAdapter.h
// Signal
//
// Created by Frederic Jacobs on 17/12/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <JSQMessagesViewController/JSQPhotoMediaItem.h>

@ -1,15 +1,9 @@
//
// TSAttachementAdapter.m
// Signal
//
// Created by Frederic Jacobs on 17/12/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import "TSPhotoAdapter.h"
#import "JSQMessagesMediaViewBubbleImageMasker.h"
#import "UIDevice+TSHardwareVersion.h"
#import <JSQMessagesViewController/JSQMessagesMediaViewBubbleImageMasker.h>
@interface TSPhotoAdapter ()

@ -1,10 +1,5 @@
//
// TSAttachementAdapter.h
// Signal
//
// Created by Frederic Jacobs on 17/12/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <JSQMessagesViewController/JSQVideoMediaItem.h>

@ -1,19 +1,13 @@
//
// TSAttachementAdapter.m
// Signal
//
// Created by Frederic Jacobs on 17/12/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import "TSMessagesManager.h"
#import "TSVideoAttachmentAdapter.h"
#import "FFCircularProgressView.h"
#import "JSQMessagesMediaViewBubbleImageMasker.h"
#import "MIMETypeUtil.h"
#import "SCWaveformView.h"
#import "TSMessagesManager.h"
#import "TSStorageManager+keyingMaterial.h"
#import <FFCircularProgressView.h>
#import <JSQMessagesViewController/JSQMessagesMediaViewBubbleImageMasker.h>
#import <SCWaveformView.h>
#define AUDIO_BAR_HEIGHT 36
@interface TSVideoAttachmentAdapter ()

@ -11,21 +11,15 @@
@interface UIColor (OWS)
+ (UIColor *)ows_materialBlueColor;
+ (UIColor *)ows_fadedBlueColor;
+ (UIColor *)ows_darkBackgroundColor;
+ (UIColor *)ows_darkGrayColor;
+ (UIColor *)ows_yellowColor;
+ (UIColor *)ows_greenColor;
+ (UIColor *)ows_redColor;
+ (UIColor *)ows_blackColor;
+ (UIColor *)ows_errorMessageBorderColor;
+ (UIColor *)ows_infoMessageBorderColor;
+ (UIColor *)backgroundColorForContact:(NSString *)contactIdentifier;
@end

@ -1,61 +1,74 @@
//
// UIColor+UIColor_OWS.m
// Signal
//
// Created by Dylan Bourgeois on 25/11/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import "Cryptography.h"
#import "UIColor+OWS.h"
@implementation UIColor (OWS)
+ (UIColor *)ows_materialBlueColor {
+ (UIColor *)ows_materialBlueColor
{
// blue: #2090EA
return [UIColor colorWithRed:32.f / 255.f green:144.f / 255.f blue:234.f / 255.f alpha:1.f];
}
+ (UIColor *)ows_blackColor {
+ (UIColor *)ows_blackColor
{
// black: #080A00
return [UIColor colorWithRed:8.f / 255.f green:10.f / 255.f blue:0. / 255.f alpha:1.f];
}
+ (UIColor *)ows_darkGrayColor {
+ (UIColor *)ows_darkGrayColor
{
return [UIColor colorWithRed:81.f / 255.f green:81.f / 255.f blue:81.f / 255.f alpha:1.f];
}
+ (UIColor *)ows_darkBackgroundColor {
+ (UIColor *)ows_darkBackgroundColor
{
return [UIColor colorWithRed:35.f / 255.f green:31.f / 255.f blue:32.f / 255.f alpha:1.f];
}
+ (UIColor *)ows_fadedBlueColor {
+ (UIColor *)ows_fadedBlueColor
{
// blue: #B6DEF4
return [UIColor colorWithRed:182.f / 255.f green:222.f / 255.f blue:244.f / 255.f alpha:1.f];
}
+ (UIColor *)ows_yellowColor {
+ (UIColor *)ows_yellowColor
{
// gold: #FFBB5C
return [UIColor colorWithRed:245.f / 255.f green:186.f / 255.f blue:98.f / 255.f alpha:1.f];
}
+ (UIColor *)ows_greenColor {
+ (UIColor *)ows_greenColor
{
// green: #BF4240
return [UIColor colorWithRed:66.f / 255.f green:191.f / 255.f blue:64.f / 255.f alpha:1.f];
}
+ (UIColor *)ows_redColor {
+ (UIColor *)ows_redColor
{
// red: #FF3867
return [UIColor colorWithRed:255. / 255.f green:56.f / 255.f blue:103.f / 255.f alpha:1.f];
}
+ (UIColor *)ows_lightBackgroundColor {
+ (UIColor *)ows_errorMessageBorderColor
{
return [UIColor colorWithRed:195.f / 255.f green:0 blue:22.f / 255.f alpha:1.0f];
}
+ (UIColor *)ows_infoMessageBorderColor
{
return [UIColor colorWithRed:239.f / 255.f green:189.f / 255.f blue:88.f / 255.f alpha:1.0f];
}
+ (UIColor *)ows_lightBackgroundColor
{
return [UIColor colorWithRed:242.f / 255.f green:242.f / 255.f blue:242.f / 255.f alpha:1.f];
}
+ (UIColor *)backgroundColorForContact:(NSString *)contactIdentifier {
+ (UIColor *)backgroundColorForContact:(NSString *)contactIdentifier
{
NSArray *colors = @[
[UIColor colorWithRed:204.f / 255.f green:148.f / 255.f blue:102.f / 255.f alpha:1.f],
[UIColor colorWithRed:187.f / 255.f green:104.f / 255.f blue:62.f / 255.f alpha:1.f],
@ -88,5 +101,4 @@
return [colors objectAtIndex:(choose % [colors count])];
}
@end

@ -1,15 +0,0 @@
//
// UIButton+OWS.h
// Signal
//
// Created by Christine Corbett Moran on 2/10/15.
// Copyright (c) 2013 Open Whisper Systems. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIButton (OWS)
+ (UIButton *)ows_blueButtonWithTitle:(NSString *)title;
@end

@ -1,37 +0,0 @@
//
// UIButton+OWS.m
// Signal
//
// Created by Christine Corbett Moran on 2/10/15.
// Copyright (c) 2013 Open Whisper Systems. All rights reserved.
//
#import "UIButton+OWS.h"
#import "UIColor+OWS.h"
#import "UIFont+OWS.h"
@implementation UIButton (OWS)
+ (UIButton *)ows_blueButtonWithTitle:(NSString *)title {
NSDictionary *buttonTextAttributes = @{
NSFontAttributeName : [UIFont ows_regularFontWithSize:15.0f],
NSForegroundColorAttributeName : [UIColor ows_materialBlueColor]
};
UIButton *button = [[UIButton alloc] init];
NSMutableAttributedString *attributedTitle = [[NSMutableAttributedString alloc] initWithString:title];
[attributedTitle setAttributes:buttonTextAttributes range:NSMakeRange(0, [attributedTitle length])];
[button setAttributedTitle:attributedTitle forState:UIControlStateNormal];
NSDictionary *disabledAttributes = @{
NSFontAttributeName : [UIFont ows_regularFontWithSize:15.0f],
NSForegroundColorAttributeName : [UIColor ows_darkGrayColor]
};
NSMutableAttributedString *attributedTitleDisabled = [[NSMutableAttributedString alloc] initWithString:title];
[attributedTitleDisabled setAttributes:disabledAttributes range:NSMakeRange(0, [attributedTitle length])];
[button setAttributedTitle:attributedTitleDisabled forState:UIControlStateDisabled];
[button.titleLabel setTextAlignment:NSTextAlignmentCenter];
return button;
}
@end

@ -1,10 +1,5 @@
//
// TableViewCell.h
// Signal
//
// Created by Dylan Bourgeois on 27/10/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "TSThread.h"

@ -1,19 +1,14 @@
//
// TableViewCell.m
// Signal
//
// Created by Dylan Bourgeois on 27/10/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import <JSQMessagesViewController/JSQMessagesAvatarImageFactory.h>
#import <JSQMessagesViewController/UIImage+JSQMessages.h>
#import "Environment.h"
#import "InboxTableViewCell.h"
#import "JSQMessagesAvatarImageFactory.h"
#import "PreferencesUtil.h"
#import "TSContactThread.h"
#import "TSGroupThread.h"
#import "TSMessagesManager.h"
#import "UIImage+JSQMessages.h"
#import "Util.h"
#define ARCHIVE_IMAGE_VIEW_WIDTH 22.0f

@ -7,14 +7,11 @@
//
#import <UIKit/UIKit.h>
#import <JSQMessagesViewController/JSQMessagesComposerTextView.h>
#import <JSQMessagesViewController/JSQMessagesInputToolbar.h>
#import <JSQMessagesViewController/JSQMessagesToolbarContentView.h>
#import <JSQMessagesViewController/JSQMessagesKeyboardController.h>
#import "Contact.h"
#import "JSQMessagesComposerTextView.h"
#import "JSQMessagesInputToolbar.h"
#import "JSQMessagesToolbarContentView.h"
#import "JSQMessagesKeyboardController.h"
#import "LocalizableText.h"
@interface MessageComposeTableViewController : UITableViewController

@ -9,8 +9,7 @@
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>
#import "APNavigationController.h"
#import "JSQMessages.h"
#import "JSQMessagesViewController.h"
#import <JSQMessagesViewController/JSQMessagesViewController.h>
#import "TSGroupModel.h"
@class TSThread;

@ -14,12 +14,20 @@
#import <MobileCoreServices/UTCoreTypes.h>
#import <SignalServiceKit/TSAccountManager.h>
#import <YapDatabase/YapDatabaseView.h>
#import <JSQMessagesViewController/JSQMessagesBubbleImage.h>
#import <JSQMessagesViewController/JSQMessagesBubbleImageFactory.h>
#import <JSQMessagesViewController/JSQMessagesTimestampFormatter.h>
#import <JSQMessagesViewController/UIColor+JSQMessages.h>
#import <JSQMessagesViewController/JSQMessagesCollectionViewFlowLayoutInvalidationContext.h>
#import <JSQMessagesViewController/JSQSystemSoundPlayer+JSQMessages.h>
#import <JSQSystemSoundPlayer.h>
#import "OWSContactsManager.h"
#import "DJWActionSheet+OWS.h"
#import "Environment.h"
#import "FingerprintViewController.h"
#import "FullImageViewController.h"
#import "JSQCallCollectionViewCell.h"
#import "OWSCallCollectionViewCell.h"
#import "OWSDisplayedMessageCollectionViewCell.h"
#import "MessagesViewController.h"
#import "NSDate+millisecondTimeStamp.h"
#import "NewGroupViewController.h"
@ -30,12 +38,17 @@
#import "TSAttachmentPointer.h"
#import "TSContentAdapters.h"
#import "TSDatabaseView.h"
#import "OWSMessagesBubblesSizeCalculator.h"
#import "OWSInfoMessage.h"
#import "TSInfoMessage.h"
#import "OWSErrorMessage.h"
#import "TSErrorMessage.h"
#import "OWSCall.h"
#import "TSCall.h"
#import "TSIncomingMessage.h"
#import "TSInvalidIdentityKeyErrorMessage.h"
#import "TSMessagesManager+attachments.h"
#import "TSMessagesManager+sendMessages.h"
#import "UIButton+OWS.h"
#import "UIFont+OWS.h"
#import "UIUtil.h"
@ -79,7 +92,6 @@ typedef enum : NSUInteger {
@property (nonatomic, strong) TSVideoAttachmentAdapter *currentMediaAdapter;
@property (nonatomic, retain) NSTimer *readTimer;
@property (nonatomic, retain) UIButton *messageButton;
@property (nonatomic, retain) UIButton *attachButton;
@property (nonatomic, retain) NSIndexPath *lastDeliveredMessageIndexPath;
@ -102,7 +114,8 @@ typedef enum : NSUInteger {
@implementation MessagesViewController
- (void)dealloc {
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@ -152,8 +165,15 @@ typedef enum : NSUInteger {
}
}
- (void)viewDidLoad {
- (void)viewDidLoad
{
[super viewDidLoad];
// JSQMVC width is 375px at this point (as specified by the xib), but this causes
// our initial bubble calculations to be off since they happen before the containing
// view is layed out. https://github.com/jessesquires/JSQMessagesViewController/issues/1257
// Resetting here makes sure we've got a good initial width.
[self resetFrame];
[self.navigationController.navigationBar setTranslucent:NO];
self.messageAdapterCache = [[NSCache alloc] init];
@ -165,10 +185,6 @@ typedef enum : NSUInteger {
[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleContactPhone)];
_toggleContactPhoneDisplay.numberOfTapsRequired = 1;
_messageButton = [UIButton ows_blueButtonWithTitle:NSLocalizedString(@"SEND_BUTTON_TITLE", @"")];
_messageButton.enabled = NO;
_messageButton.titleLabel.adjustsFontSizeToFitWidth = YES;
_attachButton = [[UIButton alloc] init];
[_attachButton setFrame:CGRectMake(0,
0,
@ -182,16 +198,26 @@ typedef enum : NSUInteger {
[self initializeTextView];
[JSQMessagesCollectionViewCell registerMenuAction:@selector(delete:)];
self.collectionView.collectionViewLayout.bubbleSizeCalculator = [[OWSMessagesBubblesSizeCalculator alloc] init];
[self initializeCollectionViewLayout];
[self registerCustomMessageNibs];
self.senderId = ME_MESSAGE_IDENTIFIER;
self.senderDisplayName = ME_MESSAGE_IDENTIFIER;
}
- (void)registerCustomMessageNibs
{
[self.collectionView registerNib:[OWSCallCollectionViewCell nib]
forCellWithReuseIdentifier:[OWSCallCollectionViewCell cellReuseIdentifier]];
[self.collectionView registerNib:[OWSDisplayedMessageCollectionViewCell nib]
forCellWithReuseIdentifier:[OWSDisplayedMessageCollectionViewCell cellReuseIdentifier]];
}
- (void)toggleObservers:(BOOL)shouldObserve {
- (void)toggleObservers:(BOOL)shouldObserve
{
if (shouldObserve) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModified:)
@ -220,9 +246,15 @@ typedef enum : NSUInteger {
- (void)initializeTextView {
[self.inputToolbar.contentView.textView setFont:[UIFont ows_dynamicTypeBodyFont]];
self.inputToolbar.contentView.leftBarButtonItem = _attachButton;
self.inputToolbar.contentView.rightBarButtonItem = _messageButton;
self.inputToolbar.contentView.textView.layer.cornerRadius = 4.f;
self.inputToolbar.contentView.leftBarButtonItem = self.attachButton;
UILabel *sendLabel = self.inputToolbar.contentView.rightBarButtonItem.titleLabel;
// override superclass translations since we support more translations than upstream.
sendLabel.text = NSLocalizedString(@"SEND_BUTTON_TITLE", nil);
sendLabel.font = [UIFont ows_regularFontWithSize:17.0f];
sendLabel.textColor = [UIColor ows_materialBlueColor];
sendLabel.textAlignment = NSTextAlignmentCenter;
}
- (void)viewWillAppear:(BOOL)animated {
@ -497,15 +529,13 @@ typedef enum : NSUInteger {
}
}
- (void)initializeBubbles {
- (void)initializeBubbles
{
JSQMessagesBubbleImageFactory *bubbleFactory = [[JSQMessagesBubbleImageFactory alloc] init];
self.incomingBubbleImageData = [bubbleFactory incomingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleLightGrayColor]];
self.outgoingBubbleImageData = [bubbleFactory outgoingMessagesBubbleImageWithColor:[UIColor ows_materialBlueColor]];
self.incomingBubbleImageData =
[bubbleFactory incomingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleLightGrayColor]];
self.currentlyOutgoingBubbleImageData =
[bubbleFactory outgoingMessageFailedBubbleImageWithColor:[UIColor ows_fadedBlueColor]];
self.outgoingMessageFailedImageData = [bubbleFactory outgoingMessageFailedBubbleImageWithColor:[UIColor grayColor]];
self.currentlyOutgoingBubbleImageData = [bubbleFactory outgoingMessagesBubbleImageWithColor:[UIColor ows_fadedBlueColor]];
self.outgoingMessageFailedImageData = [bubbleFactory outgoingMessagesBubbleImageWithColor:[UIColor grayColor]];
}
- (void)initializeCollectionViewLayout {
@ -651,13 +681,6 @@ typedef enum : NSUInteger {
return !(isGroupConversation || [((TSContactThread *)self.thread).contactIdentifier isEqualToString:[TSAccountManager localNumber]]);
}
- (void)textViewDidChange:(UITextView *)textView {
if ([textView.text length] > 0) {
self.inputToolbar.contentView.rightBarButtonItem.enabled = YES;
} else {
self.inputToolbar.contentView.rightBarButtonItem.enabled = NO;
}
}
#pragma mark - JSQMessagesViewController method overrides
- (void)didPressSendButton:(UIButton *)button
@ -681,16 +704,19 @@ typedef enum : NSUInteger {
#pragma mark - JSQMessages CollectionView DataSource
- (id<JSQMessageData>)collectionView:(JSQMessagesCollectionView *)collectionView
messageDataForItemAtIndexPath:(NSIndexPath *)indexPath {
messageDataForItemAtIndexPath:(NSIndexPath *)indexPath
{
return [self messageAtIndexPath:indexPath];
}
- (id<JSQMessageBubbleImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView
messageBubbleImageDataForItemAtIndexPath:(NSIndexPath *)indexPath {
id<JSQMessageData> message = [self messageAtIndexPath:indexPath];
messageBubbleImageDataForItemAtIndexPath:(NSIndexPath *)indexPath
{
TSInteraction *message = [self interactionAtIndexPath:indexPath];
if ([message.senderId isEqualToString:self.senderId]) {
switch (message.messageState) {
if ([message isKindOfClass:[TSOutgoingMessage class]]) {
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)message;
switch (outgoingMessage.messageState) {
case TSOutgoingMessageStateUnsent:
return self.outgoingMessageFailedImageData;
case TSOutgoingMessageStateAttemptingOut:
@ -711,31 +737,46 @@ typedef enum : NSUInteger {
#pragma mark - UICollectionView DataSource
- (UICollectionViewCell *)collectionView:(JSQMessagesCollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
TSMessageAdapter *msg = [self messageAtIndexPath:indexPath];
switch (msg.messageType) {
case TSIncomingMessageAdapter:
return [self loadIncomingMessageCellForMessage:msg atIndexPath:indexPath];
case TSOutgoingMessageAdapter:
return [self loadOutgoingCellForMessage:msg atIndexPath:indexPath];
case TSCallAdapter:
return [self loadCallCellForCall:msg atIndexPath:indexPath];
case TSInfoMessageAdapter:
return [self loadInfoMessageCellForMessage:msg atIndexPath:indexPath];
case TSErrorMessageAdapter:
return [self loadErrorMessageCellForMessage:msg atIndexPath:indexPath];
default:
DDLogError(@"Something went wrong");
return nil;
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
TSMessageAdapter *message = [self messageAtIndexPath:indexPath];
NSParameterAssert(message != nil);
JSQMessagesCollectionViewCell *cell;
switch (message.messageType) {
case TSCallAdapter: {
OWSCall *call = (OWSCall *)message;
cell = [self loadCallCellForCall:call atIndexPath:indexPath];
} break;
case TSInfoMessageAdapter: {
OWSInfoMessage *infoMessage = (OWSInfoMessage *)message;
cell = [self loadInfoMessageCellForMessage:infoMessage atIndexPath:indexPath];
} break;
case TSErrorMessageAdapter: {
OWSErrorMessage *errorMessage = (OWSErrorMessage *)message;
cell = [self loadErrorMessageCellForMessage:errorMessage atIndexPath:indexPath];
} break;
case TSIncomingMessageAdapter: {
cell = [self loadIncomingMessageCellForMessage:message atIndexPath:indexPath];
} break;
case TSOutgoingMessageAdapter: {
cell = [self loadOutgoingCellForMessage:message atIndexPath:indexPath];
} break;
default: {
DDLogWarn(@"using default cell constructor for message: %@", message);
cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
} break;
}
cell.delegate = collectionView;
return cell;
}
#pragma mark - Loading message cells
- (JSQMessagesCollectionViewCell *)loadIncomingMessageCellForMessage:(id<JSQMessageData>)message
atIndexPath:(NSIndexPath *)indexPath {
atIndexPath:(NSIndexPath *)indexPath
{
JSQMessagesCollectionViewCell *cell =
(JSQMessagesCollectionViewCell *)[super collectionView:self.collectionView cellForItemAtIndexPath:indexPath];
if (!message.isMediaMessage) {
@ -750,7 +791,8 @@ typedef enum : NSUInteger {
}
- (JSQMessagesCollectionViewCell *)loadOutgoingCellForMessage:(id<JSQMessageData>)message
atIndexPath:(NSIndexPath *)indexPath {
atIndexPath:(NSIndexPath *)indexPath
{
JSQMessagesCollectionViewCell *cell =
(JSQMessagesCollectionViewCell *)[super collectionView:self.collectionView cellForItemAtIndexPath:indexPath];
if (!message.isMediaMessage) {
@ -764,26 +806,61 @@ typedef enum : NSUInteger {
return cell;
}
- (JSQCallCollectionViewCell *)loadCallCellForCall:(id<JSQMessageData>)call atIndexPath:(NSIndexPath *)indexPath {
JSQCallCollectionViewCell *cell =
(JSQCallCollectionViewCell *)[super collectionView:self.collectionView cellForItemAtIndexPath:indexPath];
return cell;
- (OWSCallCollectionViewCell *)loadCallCellForCall:(OWSCall *)call atIndexPath:(NSIndexPath *)indexPath
{
OWSCallCollectionViewCell *callCell = [self.collectionView dequeueReusableCellWithReuseIdentifier:[OWSCallCollectionViewCell cellReuseIdentifier]
forIndexPath:indexPath];
NSString *text = call.date != nil ? [call text] : call.senderDisplayName;
NSString *allText = call.date != nil ? [text stringByAppendingString:[call dateText]] : text;
UIFont *boldFont = [UIFont fontWithName:@"HelveticaNeue-Medium" size:12.0f];
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:allText
attributes:@{ NSFontAttributeName: boldFont }];
if([call date]!=nil) {
// Not a group meta message
UIFont *regularFont = [UIFont fontWithName:@"HelveticaNeue-Light" size:12.0f];
const NSRange range = NSMakeRange([text length], [[call dateText] length]);
[attributedText setAttributes:@{ NSFontAttributeName: regularFont }
range:range];
}
callCell.cellLabel.attributedText = attributedText;
callCell.cellLabel.numberOfLines = 0; // uses as many lines as it needs
callCell.cellLabel.textColor = [UIColor ows_materialBlueColor];
callCell.layer.shouldRasterize = YES;
callCell.layer.rasterizationScale = [UIScreen mainScreen].scale;
return callCell;
}
- (JSQDisplayedMessageCollectionViewCell *)loadInfoMessageCellForMessage:(id<JSQMessageData>)message
atIndexPath:(NSIndexPath *)indexPath {
JSQDisplayedMessageCollectionViewCell *cell =
(JSQDisplayedMessageCollectionViewCell *)[super collectionView:self.collectionView
cellForItemAtIndexPath:indexPath];
return cell;
- (OWSDisplayedMessageCollectionViewCell *)loadInfoMessageCellForMessage:(OWSInfoMessage *)infoMessage
atIndexPath:(NSIndexPath *)indexPath
{
OWSDisplayedMessageCollectionViewCell *infoCell = [self.collectionView dequeueReusableCellWithReuseIdentifier:[OWSDisplayedMessageCollectionViewCell cellReuseIdentifier]
forIndexPath:indexPath];
infoCell.cellLabel.text = [infoMessage text];
infoCell.cellLabel.textColor = [UIColor darkGrayColor];
infoCell.textContainer.layer.borderColor = infoCell.textContainer.layer.borderColor = [[UIColor ows_infoMessageBorderColor] CGColor];
infoCell.headerImageView.image = [UIImage imageNamed:@"warning_white"];
infoCell.layer.shouldRasterize = YES;
infoCell.layer.rasterizationScale = [UIScreen mainScreen].scale;
return infoCell;
}
- (JSQDisplayedMessageCollectionViewCell *)loadErrorMessageCellForMessage:(id<JSQMessageData>)message
atIndexPath:(NSIndexPath *)indexPath {
JSQDisplayedMessageCollectionViewCell *cell =
(JSQDisplayedMessageCollectionViewCell *)[super collectionView:self.collectionView
cellForItemAtIndexPath:indexPath];
return cell;
- (OWSDisplayedMessageCollectionViewCell *)loadErrorMessageCellForMessage:(OWSErrorMessage *)errorMessage
atIndexPath:(NSIndexPath *)indexPath
{
OWSDisplayedMessageCollectionViewCell *errorCell = [self.collectionView dequeueReusableCellWithReuseIdentifier:[OWSDisplayedMessageCollectionViewCell cellReuseIdentifier]
forIndexPath:indexPath];
errorCell.cellLabel.text = [errorMessage text];
errorCell.cellLabel.textColor = [UIColor darkGrayColor];
errorCell.textContainer.layer.borderColor = [[UIColor ows_errorMessageBorderColor] CGColor];
errorCell.headerImageView.image = [UIImage imageNamed:@"error_white"];
errorCell.layer.shouldRasterize = YES;
errorCell.layer.rasterizationScale = [UIScreen mainScreen].scale;
return errorCell;
}
#pragma mark - Adjusting cell label heights
@ -831,9 +908,11 @@ typedef enum : NSUInteger {
TSMessageAdapter *currentMessage = [self messageAtIndexPath:indexPath];
// If message failed, say that message should be tapped to retry;
if (currentMessage.messageType == TSOutgoingMessageAdapter &&
currentMessage.messageState == TSOutgoingMessageStateUnsent) {
return YES;
if (currentMessage.messageType == TSOutgoingMessageAdapter) {
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)currentMessage;
if(outgoingMessage.messageState == TSOutgoingMessageStateUnsent) {
return YES;
}
}
if ([self.thread isKindOfClass:[TSGroupThread class]]) {
@ -867,8 +946,15 @@ typedef enum : NSUInteger {
return nextMessage;
}
- (BOOL)isMessageOutgoingAndDelivered:(TSMessageAdapter *)message {
return message.messageType == TSOutgoingMessageAdapter && message.messageState == TSOutgoingMessageStateDelivered;
- (BOOL)isMessageOutgoingAndDelivered:(TSMessageAdapter *)message
{
if (message.messageType == TSOutgoingMessageAdapter) {
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)message;
if(outgoingMessage.messageState == TSOutgoingMessageStateDelivered) {
return YES;
}
}
return NO;
}
@ -879,11 +965,14 @@ typedef enum : NSUInteger {
textAttachment.bounds = CGRectMake(0, 0, 11.0f, 10.0f);
if ([self shouldShowMessageStatusAtIndexPath:indexPath]) {
if (msg.messageType == TSOutgoingMessageAdapter && msg.messageState == TSOutgoingMessageStateUnsent) {
NSMutableAttributedString *attrStr =
if (msg.messageType == TSOutgoingMessageAdapter) {
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)msg;
if(outgoingMessage.messageState == TSOutgoingMessageStateUnsent) {
NSMutableAttributedString *attrStr =
[[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"FAILED_SENDING_TEXT", nil)];
[attrStr appendAttributedString:[NSAttributedString attributedStringWithAttachment:textAttachment]];
return attrStr;
[attrStr appendAttributedString:[NSAttributedString attributedStringWithAttachment:textAttachment]];
return attrStr;
}
}
if ([self.thread isKindOfClass:[TSGroupThread class]]) {
@ -922,17 +1011,27 @@ typedef enum : NSUInteger {
#pragma mark - Actions
- (void)collectionView:(JSQMessagesCollectionView *)collectionView didTapCellAtIndexPath:(NSIndexPath *)indexPath touchLocation:(CGPoint)touchLocation
{
// Pass info/error message tapping to bubble tapping handler
[self collectionView:collectionView didTapMessageBubbleAtIndexPath:indexPath];
}
- (void)collectionView:(JSQMessagesCollectionView *)collectionView
didTapMessageBubbleAtIndexPath:(NSIndexPath *)indexPath {
didTapMessageBubbleAtIndexPath:(NSIndexPath *)indexPath
{
TSMessageAdapter *messageItem =
[collectionView.dataSource collectionView:collectionView messageDataForItemAtIndexPath:indexPath];
TSInteraction *interaction = [self interactionAtIndexPath:indexPath];
switch (messageItem.messageType) {
case TSOutgoingMessageAdapter:
if (messageItem.messageState == TSOutgoingMessageStateUnsent) {
case TSOutgoingMessageAdapter: {
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)messageItem;
if (outgoingMessage.messageState == TSOutgoingMessageStateUnsent) {
[self handleUnsentMessageTap:(TSOutgoingMessage *)interaction];
}
}
// No `break` as we want to fall through to capture tapping on media items
case TSIncomingMessageAdapter: {
BOOL isMediaMessage = [messageItem isMediaMessage];
@ -1111,11 +1210,13 @@ typedef enum : NSUInteger {
case TSCallAdapter:
break;
default:
DDLogDebug(@"Unhandled bubble touch for interaction: %@.", interaction);
break;
}
}
- (void)handleWarningTap:(TSInteraction *)interaction {
- (void)handleWarningTap:(TSInteraction *)interaction
{
if ([interaction isKindOfClass:[TSIncomingMessage class]]) {
TSIncomingMessage *message = (TSIncomingMessage *)interaction;
@ -1129,6 +1230,8 @@ typedef enum : NSUInteger {
if ([attachment isKindOfClass:[TSAttachmentPointer class]]) {
TSAttachmentPointer *pointer = (TSAttachmentPointer *)attachment;
// FIXME possible for pointer to get stuck in isDownloading state if app is closed while downloading.
// see: https://github.com/WhisperSystems/Signal-iOS/issues/1254
if (!pointer.isDownloading) {
[[TSMessagesManager sharedManager] retrieveAttachment:pointer messageId:message.uniqueId];
}
@ -2000,5 +2103,4 @@ typedef enum : NSUInteger {
return @[];
}
@end

@ -0,0 +1,18 @@
// Created by Dylan Bourgeois on 20/11/14.
// Portions Copyright (c) 2014 Open Whisper Systems. All rights reserved.
#import <UIKit/UIKit.h>
#import <JSQMessagesViewController/JSQMessagesCollectionViewCell.h>
@interface OWSCallCollectionViewCell : JSQMessagesCollectionViewCell
@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

@ -0,0 +1,53 @@
// Created by Dylan Bourgeois on 20/11/14.
// Portions Copyright (c) 2014 Open Whisper Systems. All rights reserved.
#import "OWSCallCollectionViewCell.h"
#import <JSQMessagesViewController/UIView+JSQMessages.h>
@interface OWSCallCollectionViewCell ()
@property (weak, nonatomic) IBOutlet JSQMessagesLabel *cellLabel;
@property (weak, nonatomic) IBOutlet UIImageView *outgoingCallImageView;
@property (weak, nonatomic) IBOutlet UIImageView *incomingCallImageView;
@end
@implementation OWSCallCollectionViewCell
#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.cellLabel.textAlignment = NSTextAlignmentCenter;
self.cellLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:14.0f];
self.cellLabel.textColor = [UIColor lightGrayColor];
}
#pragma mark - Collection view cell
- (void)prepareForReuse
{
[super prepareForReuse];
self.cellLabel.text = nil;
}
@end

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</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="OWSCallCollectionViewCell">
<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" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<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="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,16 @@
// Created by Dylan Bourgeois on 29/11/14.
// Copyright (c) 2014 Hexed Bits. All rights reserved.
// Portions Copyright (c) 2016 Open Whisper Systems. All rights reserved.
#import <JSQMessagesViewController/JSQMessagesCollectionViewCell.h>
#import <UIKit/UIKit.h>
static const CGFloat OWSDisplayedMessageCellHeight = 70.0f;
@interface OWSDisplayedMessageCollectionViewCell : JSQMessagesCollectionViewCell
@property (weak, nonatomic, readonly) JSQMessagesLabel *cellLabel;
@property (weak, nonatomic, readonly) UIImageView *headerImageView;
@property (strong, nonatomic, readonly) UIView *textContainer;
@end

@ -0,0 +1,58 @@
// Created by Dylan Bourgeois on 29/11/14.
// Copyright (c) 2014 Hexed Bits. All rights reserved.
// Portions Copyright (c) 2016 Open Whisper Systems. All rights reserved.
#import "OWSDisplayedMessageCollectionViewCell.h"
#import <JSQMessagesViewController/UIView+JSQMessages.h>
@interface OWSDisplayedMessageCollectionViewCell ()
@property (weak, nonatomic) IBOutlet JSQMessagesLabel *cellLabel;
@property (weak, nonatomic) IBOutlet UIImageView *headerImageView;
@property (strong, nonatomic) IBOutlet UIView *textContainer;
@end
@implementation OWSDisplayedMessageCollectionViewCell
#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.textContainer.layer.borderColor = [[UIColor lightGrayColor] CGColor];
self.textContainer.layer.borderWidth = 0.75f;
self.textContainer.layer.cornerRadius = 5.0f;
self.cellLabel.textAlignment = NSTextAlignmentCenter;
self.cellLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:14.0f];
self.cellLabel.textColor = [UIColor lightGrayColor];
}
#pragma mark - Collection view cell
- (void)prepareForReuse
{
[super prepareForReuse];
self.cellLabel.text = nil;
}
@end

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
<capability name="Alignment constraints with different attributes" minToolsVersion="5.1"/>
</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="OWSDisplayedMessageCollectionViewCell">
<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>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qCf-bs-dBd" userLabel="textContainer">
<rect key="frame" x="0.0" y="22" width="320" height="48"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Info Message" textAlignment="center" lineBreakMode="wordWrap" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="OVa-Xw-5vl" customClass="JSQMessagesLabel">
<rect key="frame" x="8" y="12" width="304" height="28"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="14" id="fed-2c-dqd"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="OVa-Xw-5vl" firstAttribute="leading" secondItem="qCf-bs-dBd" secondAttribute="leading" constant="8" id="2IE-8k-czI"/>
<constraint firstAttribute="bottom" secondItem="OVa-Xw-5vl" secondAttribute="bottom" constant="8" id="MtI-jW-t1x"/>
<constraint firstAttribute="trailing" secondItem="OVa-Xw-5vl" secondAttribute="trailing" constant="8" id="Y8z-8G-PLt"/>
<constraint firstItem="OVa-Xw-5vl" firstAttribute="top" secondItem="qCf-bs-dBd" secondAttribute="top" constant="12" id="v5B-tB-pOB"/>
</constraints>
</view>
<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="0.0" 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="ePO-Cy-jUE" firstAttribute="top" secondItem="eMU-z2-CzM" secondAttribute="top" id="D28-BQ-Qam"/>
<constraint firstAttribute="trailing" secondItem="qCf-bs-dBd" secondAttribute="trailing" id="F3T-1l-nCg"/>
<constraint firstItem="qCf-bs-dBd" firstAttribute="leading" secondItem="eMU-z2-CzM" secondAttribute="leading" id="OzF-VM-85V"/>
<constraint firstAttribute="bottom" secondItem="qCf-bs-dBd" secondAttribute="bottom" id="PNq-zm-usq"/>
<constraint firstItem="qCf-bs-dBd" firstAttribute="top" secondItem="ePO-Cy-jUE" secondAttribute="centerY" constant="4" id="UzU-DS-8WZ"/>
<constraint firstItem="ePO-Cy-jUE" firstAttribute="centerX" secondItem="eMU-z2-CzM" secondAttribute="centerX" id="qtQ-mS-o6z"/>
</constraints>
<size key="customSize" width="320" height="55"/>
<connections>
<outlet property="cellLabel" destination="OVa-Xw-5vl" id="7PC-oj-dQZ"/>
<outlet property="headerImageView" destination="ePO-Cy-jUE" id="4uq-2C-V7U"/>
<outlet property="textContainer" destination="qCf-bs-dBd" id="fL7-LO-El1"/>
</connections>
<point key="canvasLocation" x="219" y="433"/>
</collectionViewCell>
</objects>
<resources>
<image name="warning_white.png" width="100" height="100"/>
</resources>
</document>
Loading…
Cancel
Save