From 5e1c6c02a0c1549defcaf4fbc1016031733c4012 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 26 Oct 2017 17:16:48 -0400 Subject: [PATCH] Add "failed message send" badges. // FREEBIE --- .../Contents.json | 23 ++++++++ .../message_send_failure@1x.png | Bin 0 -> 1733 bytes .../message_send_failure@2x.png | Bin 0 -> 2428 bytes .../message_send_failure@3x.png | Bin 0 -> 3328 bytes .../ConversationView/Cells/OWSMessageCell.m | 53 +++++++++++++++++- .../ConversationView/ConversationViewLayout.m | 4 +- 6 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 Signal/Images.xcassets/message_send_failure.imageset/Contents.json create mode 100644 Signal/Images.xcassets/message_send_failure.imageset/message_send_failure@1x.png create mode 100644 Signal/Images.xcassets/message_send_failure.imageset/message_send_failure@2x.png create mode 100644 Signal/Images.xcassets/message_send_failure.imageset/message_send_failure@3x.png diff --git a/Signal/Images.xcassets/message_send_failure.imageset/Contents.json b/Signal/Images.xcassets/message_send_failure.imageset/Contents.json new file mode 100644 index 000000000..c1ca74cf9 --- /dev/null +++ b/Signal/Images.xcassets/message_send_failure.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "message_send_failure@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "message_send_failure@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "message_send_failure@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/message_send_failure.imageset/message_send_failure@1x.png b/Signal/Images.xcassets/message_send_failure.imageset/message_send_failure@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..faa7e18f0fc24dc09ecef3349355a6b5b41402ec GIT binary patch literal 1733 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VOS+@4BLl<6e(pbstUx|zfk$L9 z1B0G22s2hJwJ!szQOOL6D2ed(u}aR*)k{ptPfFFR$SnY>W?-jfNYSkzLEl1NlCV?QiN}Sf^&XRs)DJWiJpOy9hZWFf=y9MnpKdC8&o@x zXRDM^Qc_^0uU}qXu2*iXmtT~wZ)j<0sc&GUZ)BtkRH0j3nOBlnp_^B%3^4>|j!SBB za#3bMNoIbY0?6FNr2NtnTO}osMQ{LdXGvxn!lt}psJDO~)CbAv8|oS8W7C#ek%>ba zNCv02lw`QC3QCJ|z`lh!DTofLv}B zlvtVqp?aLEJ)DcB!IKxbi3!Y*k#El$DxXf)roCSOceir^Ix9Bw-tU ztg3B*X~D`jKP5A*(j~DZ)y~Mk(A>(0m3jaw$VpZgX98`jB`}JbrUi=vbFCd0P$#Seu;Y6B;{R3#1}1Y)7sn6_ z!L?J)dxr#y9DjcIdQX)J-@i9O}^=@zx7tumV&a1z4w;q>|qbOn)Q|8r}HO;_hDXl-S#%gole`l z{(`p9<UzA#W8yJ>i$oh76$yt>$_g6`1$u= z!w(O9E*x|8UUtxW`|Z1>R<6IkstIuT%;QVgeZYq~{m`4)i#l|fWX~$t&OW^JMoGlf z)ibuT>F8d{oS@fuJW2b(GV#eKmA*1>b$;zTwNLXwP>4CtO-1u>yJd}TDo=L`w6{#1 zq8Z>UA%9!-@^6XtEUmmJC(18WDP0ij8EBLw$a<4iB=gt*2(N>Ggucw1-g{`*f%Ky{ zzXvXQuKGleO+#m)jhugs){{29+Y{s-zRzBen*CshTj2GXQ~0%}dOcOVv+z>7S<9n+ z+{fNL@>^a!?}pir#l?DtFY{-ff6n6YCpoHu1fbJU&PHy;zar zT)%qJ{W{zaJ5OKa{HSyC@r`zee+~K`QMoP$6w3H-JZ+Z#@znY3)vgV4Jne_))!5k| svfwxuu4M7qI%-elr|-PL_dDQ(8>nLOboFyt=akR{0E7B$WB>pF literal 0 HcmV?d00001 diff --git a/Signal/Images.xcassets/message_send_failure.imageset/message_send_failure@2x.png b/Signal/Images.xcassets/message_send_failure.imageset/message_send_failure@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1e540f14b570f59e90ccd819849bbccbc0294b7d GIT binary patch literal 2428 zcmZ`*3pkr+8xB?792!H5Iz<@PpPW=hM4X}ym9W$yYC0hw4N1PpflRfORh^2qTC_FH zYK(NuU+qduhG~mhf0xd-`q7iNL_>95%U}Bv*5-HVcU@oJ_r0I{exK)lzVH36~LLA6JF_>U1fD&_f5E}*~iV4t^0|*%iF^A0+5XA0CC4&IX6)+l! zP*Q|R?npW%1mOen0faMZ2MU8EX(12@BA*#gppkd2%Au7za=%c>BcRc#si~+`Clts} zKx189UC|gE8i#X)7>!yQx`&RgWMT!}`m1N2$u6QFVDksnY0mv39S`fx%2}wAj($HG?T}M__J|Kt32Lu90 zMsi-2sA6mR^ml1UP8iIpLKR)B2q5X{2)Lbym5CFch+e}{sX!6&;R6gI z$PWcUHc9D%qgW!GP%bM<)%dEEh*q2c(;Lx<5q?LNL{+?mSFO!w{-m!X}(#_Jw==_MZ z+O24ZtcgvHxj_}JNbkyK)2U-z*&SV%q(+Y4K*Y(qyw2q$+KETg9UPWmqH3yRifFk^ zga-F1y!o_!Wo2beI%&LYFg|sn?hjeYOQfK`zu%~mI#u=KXR}%3&pI(KE=EyF#@|MF zx3#sQvOJ2$4q;$zThbpKFYqKCJhC${5>qs2kGD9s>-*9L=ca82HU{n%#Z!6~aDDrr zN4CeupD!7dSHFQ*1l^uxvsiQ1?OlTlvW?jbFXxHbX11-*`tHwlvc^m9aY4|-P)Bph zt4QaNj>S){zviT7*c+x9F4iL8byDq}GmVWWE>81=I$8YJVFsP3X8ShyG-2#NqqRwBZ;IE!I zK8Qa;wb6gwwroXBSLwg&y7)%!-5cm-L$N*J z+|x!1I6DWQU>?NvQcRYPS4)M2gCp@8E_u=`O=aQfsQl{FWhr`^luswViEbsnpROOL#0eI`H9VJIXxdvRpc=AoL{p?Tn3DlK_F`3_Q+*Bkpke@aOE$C=Wn z9{BiQ1H8tytH$e>H&@w7c5chbEGoV9{p}|?71B76aX-zIDj8Id*y`7i(3KVp688K% z)7fZWNm(Y>@)}B@{v3YMj%nIdQ0X8z{vla$7kp%GdgXVh3^KPbEJ`BQ}!0 zd(6Hox7d!1$glZ19@v&uNR zo}HlNF4#ZnX)?Y^E-@_>T+zm18bYOc|D8!b_qfL+HeI^sN#c25pZw0DhX!U-`OjXT zy5$_cgeRy=eVOVV-FG|s>(E9Svli((**YX)b`4NJNgTN}S}z|08GY8@4ynsVsB=q> z^9kW^K53qKkv2?p!&MZ*TaLY{ysq|u^g7krfLM$ef0XOydzFE;r7w_eQ<^vY$LsUU zrn!ZIhCNMZx@*w8LqxeBTM4yXZ_1X-8bY7)z54t|ZRtNivL3azEtuB@0hH=0YhHK5&!@I literal 0 HcmV?d00001 diff --git a/Signal/Images.xcassets/message_send_failure.imageset/message_send_failure@3x.png b/Signal/Images.xcassets/message_send_failure.imageset/message_send_failure@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..1413112271cb83876f42503962b73a17f5704404 GIT binary patch literal 3328 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 IVj?sD2i78S`2YX_ literal 0 HcmV?d00001 diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m index 4901da5ec..bb84be168 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m @@ -73,6 +73,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) BubbleMaskingView *payloadView; @property (nonatomic) UILabel *dateHeaderLabel; @property (nonatomic) UITextView *textView; +@property (nonatomic, nullable) UIImageView *failedSendBadgeView; @property (nonatomic, nullable) UILabel *tapForMoreLabel; @property (nonatomic, nullable) UIImageView *bubbleImageView; @property (nonatomic, nullable) AttachmentUploadView *attachmentUploadView; @@ -85,6 +86,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) UIView *footerView; @property (nonatomic) UILabel *footerLabel; @property (nonatomic, nullable) OWSExpirationTimerView *expirationTimerView; +@property (nonatomic, nullable) NSArray *payloadConstraints; @property (nonatomic, nullable) NSArray *dateHeaderConstraints; @property (nonatomic, nullable) NSArray *contentConstraints; @property (nonatomic, nullable) NSArray *footerConstraints; @@ -108,6 +110,7 @@ NS_ASSUME_NONNULL_BEGIN OWSAssert(!self.textView); self.layoutMargins = UIEdgeInsetsZero; + self.contentView.layoutMargins = UIEdgeInsetsZero; self.payloadView = [BubbleMaskingView new]; self.payloadView.layoutMargins = UIEdgeInsetsZero; @@ -153,7 +156,6 @@ NS_ASSUME_NONNULL_BEGIN self.footerLabel.hidden = YES; [self.payloadView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.dateHeaderLabel]; - [self.payloadView autoPinWidthToSuperview]; [self.footerView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.payloadView]; [self.footerView autoPinEdgeToSuperviewEdge:ALEdgeBottom]; [self.footerView autoPinWidthToSuperview]; @@ -193,6 +195,28 @@ NS_ASSUME_NONNULL_BEGIN return (CGFloat)ceil([self tapForMoreFont].lineHeight * 1.25); } +- (BOOL)hasFailedSendBadge +{ + if (![self.viewItem.interaction isKindOfClass:[TSOutgoingMessage class]]) { + return NO; + } + TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)self.viewItem.interaction; + return outgoingMessage.messageState == TSOutgoingMessageStateUnsent; +} + +- (UIImage *)failedSendBadge +{ + UIImage *image = [UIImage imageNamed:@"message_send_failure"]; + OWSAssert(image); + OWSAssert(image.size.width == self.failedSendBadgeSize && image.size.height == self.failedSendBadgeSize); + return image; +} + +- (CGFloat)failedSendBadgeSize +{ + return 20.f; +} + - (OWSMessageCellType)cellType { return self.viewItem.messageCellType; @@ -243,6 +267,25 @@ NS_ASSUME_NONNULL_BEGIN OWSAssert(self.viewItem.interaction); OWSAssert([self.viewItem.interaction isKindOfClass:[TSMessage class]]); + if (self.hasFailedSendBadge) { + self.failedSendBadgeView = [UIImageView new]; + self.failedSendBadgeView.image = + [self.failedSendBadge imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + self.failedSendBadgeView.tintColor = [UIColor ows_destructiveRedColor]; + [self.contentView addSubview:self.failedSendBadgeView]; + + self.payloadConstraints = @[ + [self.payloadView autoPinLeadingToSuperview], + [self.failedSendBadgeView autoPinLeadingToTrailingOfView:self.payloadView], + [self.failedSendBadgeView autoPinTrailingToSuperview], + [self.failedSendBadgeView autoAlignAxis:ALAxisHorizontal toSameAxisOfView:self.payloadView], + [self.failedSendBadgeView autoSetDimension:ALDimensionWidth toSize:self.failedSendBadgeSize], + [self.failedSendBadgeView autoSetDimension:ALDimensionHeight toSize:self.failedSendBadgeSize], + ]; + } else { + self.payloadConstraints = [self.payloadView autoPinWidthToSuperview]; + } + JSQMessagesBubbleImage *bubbleImageData; if ([self.viewItem.interaction isKindOfClass:[TSOutgoingMessage class]]) { TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)self.viewItem.interaction; @@ -856,6 +899,10 @@ NS_ASSUME_NONNULL_BEGIN cellSize.height += self.dateHeaderHeight; cellSize.height += self.footerHeight; + if (self.hasFailedSendBadge) { + cellSize.width += self.failedSendBadgeSize; + } + cellSize.width = ceil(cellSize.width); cellSize.height = ceil(cellSize.height); @@ -928,6 +975,8 @@ NS_ASSUME_NONNULL_BEGIN { [super prepareForReuse]; + [NSLayoutConstraint deactivateConstraints:self.payloadConstraints]; + self.payloadConstraints = nil; [NSLayoutConstraint deactivateConstraints:self.contentConstraints]; self.contentConstraints = nil; [NSLayoutConstraint deactivateConstraints:self.dateHeaderConstraints]; @@ -940,6 +989,8 @@ NS_ASSUME_NONNULL_BEGIN self.textView.text = nil; self.textView.hidden = YES; self.textView.dataDetectorTypes = UIDataDetectorTypeNone; + [self.failedSendBadgeView removeFromSuperview]; + self.failedSendBadgeView = nil; [self.tapForMoreLabel removeFromSuperview]; self.tapForMoreLabel = nil; self.footerLabel.text = nil; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewLayout.m b/Signal/src/ViewControllers/ConversationView/ConversationViewLayout.m index 072f2c97b..bf87bf3e6 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewLayout.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewLayout.m @@ -105,8 +105,8 @@ NS_ASSUME_NONNULL_BEGIN switch (layoutItem.layoutAlignment) { case ConversationViewLayoutAlignment_Incoming: case ConversationViewLayoutAlignment_Outgoing: { - BOOL isLeft = ((layoutItem.layoutAlignment == ConversationViewLayoutAlignment_Incoming && !isRTL) - || (layoutItem.layoutAlignment == ConversationViewLayoutAlignment_Outgoing && isRTL)); + BOOL isIncoming = layoutItem.layoutAlignment == ConversationViewLayoutAlignment_Incoming; + BOOL isLeft = isIncoming ^ isRTL; if (isLeft) { itemFrame = CGRectMake(hInset, y, layoutSize.width, layoutSize.height); } else {