From a0b612c64ba83890d5a0d8cb98ece44e79f5ccb2 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 27 Jun 2018 14:53:31 -0400 Subject: [PATCH] Tweak generic attachments. --- .../generic-attachment.imageset/Contents.json | 23 +++ .../generic-attachment.imageset/File@1x.png | Bin 0 -> 808 bytes .../generic-attachment.imageset/File@2x.png | Bin 0 -> 1859 bytes .../generic-attachment.imageset/File@3x.png | Bin 0 -> 3091 bytes .../Cells/OWSGenericAttachmentView.h | 4 +- .../Cells/OWSGenericAttachmentView.m | 82 +++----- .../Cells/OWSMessageBubbleView.m | 186 +++++++++++------- 7 files changed, 163 insertions(+), 132 deletions(-) create mode 100644 Signal/Images.xcassets/generic-attachment.imageset/Contents.json create mode 100644 Signal/Images.xcassets/generic-attachment.imageset/File@1x.png create mode 100644 Signal/Images.xcassets/generic-attachment.imageset/File@2x.png create mode 100644 Signal/Images.xcassets/generic-attachment.imageset/File@3x.png diff --git a/Signal/Images.xcassets/generic-attachment.imageset/Contents.json b/Signal/Images.xcassets/generic-attachment.imageset/Contents.json new file mode 100644 index 000000000..53e5e34c0 --- /dev/null +++ b/Signal/Images.xcassets/generic-attachment.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "File@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "File@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "File@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/generic-attachment.imageset/File@1x.png b/Signal/Images.xcassets/generic-attachment.imageset/File@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..cd817594a1171f79cd89c312432c1acb3d49ae74 GIT binary patch literal 808 zcmV+@1K0eCP)Px%;z>k7R9Fe^n9r`#P!Psj5J8v3a=22`=59L4aHiAKnP0#5kes^CzPbB{i5vxSstACL zyfzOn!;4{z!EU8e>EOh2x!fQ*h5uD2V?psc0?`ZAYV~q78h!FS?>dNSo6RPe&*xX| zcKbDIJyvz~4I_QK2}};tE(jBo!%Qa(eYIKzlgY$uwOVgc?+KiBr3b?Qn@r|~PtQ?C zZh%1R^*WeNr@?SI^t#>dSx^Kb4BwqgDSpmKAly(eo6Um3V89Yyr_*_dx+g0|5HSIh zTmsAdlc6+_ zrOtUNJ~kTOCtX0GULkq(@udb-C={IWcx;3EfOqOB6mLbGtLzz8#&>;NabsNXVCg%H z#lpezcYNPJC;*3>Rc{ooQDi1nO|qF-r$Fg?NG{leb6d m{2ufW6{KDCSn_F)JFtHW&{^I)Y8A8q0000005(qcJ3!cp5&&m z;7K<_jG!j~J#fEl1JL`STmTR}LfKhkVn7>3POfU6GF@>uNly*jIK{8UhS_?vcCYiQ zafz3lL1_#-VNU~)7ADlLPIRdOs@Eh?=g`mp5Gs_v9ZCpQzN=L^yl{Wwuf65 zB|?*DAer0O!&@`fSa&3FSJ&4cHNJbdb@cP+&ywZkWtLlFA@sbBm6_SNmygfk?OV4N zq*Ld?+!Udy%xtFf)T8;O>joq`hr`L*-P!s5&ZTTzT>BHag+(SBjsA0LYU)@+L!+5I zJVWju$2G-1nortVk~btAy8rf%iL|(u)ZoN~_oLy6zdZ8RYQG!^zQENG2GB_GatI^!cCFNg{;@w0OUi7laTm8iny;~b8gnkO_oJlvj2r9Q)q)+4a$s_0JI=4|6#NpB)vmfiPx zVQM9jmfTm{1M^NU?g|SD;VMI+VUFqy0^rbaTI8!|c<`wFm2qL@XW@|0(8|*CLNQ_e znpiD`p#Q12eQQ;e3?ppqeV;FRQ(kT*SEo8g(M5#7p_BDEYi5*)k|@>(SXF;YNp z)(I{oQm@QY$clU@e(X?^4Jxj*45NT=D(@sf`R?vYrsG}OEm3RA^71jvrluc@dwY9l zv9KIsJMs*qWjsa12)Waak>m@+(jZ7gz*zL&vhhKHa-^xL>En};AEAdIQ>4Y!C+ChM z{!TpC(&(9F7Z51GWpDBb5(PUOTrOTs;|G71J$AOWUi~euM!DMkN*O3=93+t0191J6x*|iK~FVA>pY-4TJ{zP2wHz*>UuoH(TmpS1`ZDn zEXm-Rwp$a0@ZG?Gu&^*(K){!Xo<%!zS3SpUth1vo>6K8h%6{5bW18KLaFN6!gKpLB zfiDqz_rBIs8tbs$4PvNha%sv7X+_Uq@)Tz?NuS9Ik0AxfQ4}|3*5rd!Y`&uMrzfFp z#zF&Y1R}Arl%41Iho^fDdF2xwBvqipsP87DSmc{p`dJPNxg*KkIaz6-)!}m3?A465 zbmQ1xcN@Vyjrg!t()vZ2G1Jj|)3=T9RxDSS(v^D`K|OERjuiF#)0DbOiz9gyIccEH zTayx%G4*D7+kC7FX}&oK35@Riu#X8!$SHdDQr%B!OvcXu54Qg-X%)2u@q3}WJlk8N z!;sn-PCxfPDZ4eeJjpvt;jyUjA5Cg?77@MRbX{XYQw`B-ha(a=G_svQW9Sy%@W`nV zY|pC=oA$k$;B9h|LhE|kY){U$4k+r>)Z@TmrVQ#(t2KF>P|;Q1+X~k*&p!s424zRy Tt9H9|@`?b;9&JarxtZ`UA|`ej literal 0 HcmV?d00001 diff --git a/Signal/Images.xcassets/generic-attachment.imageset/File@3x.png b/Signal/Images.xcassets/generic-attachment.imageset/File@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..26c2172dbab39e20df37514f4b385c270aeb90b9 GIT binary patch literal 3091 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≪hONJhQLgDhJpWyDWaRP7vP(mWfi!G>UNuP4cxo_S z89C{9h*SNyOd{aLv^(P6(2l= zQNvTz*wwBnMLRobO@SUqTx8^?PKLDg1qjVHY@XYEY`UB(;#O1CV(z0}xp^)w*Af)s zpV45xs8A *)textViews +- (BOOL)canFooterOverlayMedia +{ + return self.hasBodyMediaWithThumbnail; +} + +- (nullable UIView *)insertAnyTextViewsIntoStackView:(NSArray *)textViews { if (textViews.count < 1) { - return; + return nil; } UIStackView *textStackView = [[UIStackView alloc] initWithArrangedSubviews:textViews]; @@ -497,6 +508,7 @@ NS_ASSUME_NONNULL_BEGIN self.conversationStyle.textInsetBottom, self.conversationStyle.textInsetHorizontal); [self.stackView addArrangedSubview:textStackView]; + return textStackView; } // We now eagerly create our view hierarchy (to do this exactly once per cell usage) @@ -930,13 +942,13 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Measurement // Size of "message body" text, not quoted reply text. -- (CGSize)bodyTextSizeWithIncludeMargins:(BOOL)includeMargins +- (nullable NSValue *)bodyTextSize { OWSAssert(self.conversationStyle); OWSAssert(self.conversationStyle.maxMessageWidth > 0); if (!self.hasBodyText) { - return CGSizeZero; + return nil; } CGFloat hMargins = self.conversationStyle.textInsetHorizontal * 2; @@ -947,15 +959,10 @@ NS_ASSUME_NONNULL_BEGIN const int kMaxIterations = 5; CGSize result = [self.bodyTextView compactSizeThatFitsMaxWidth:maxTextWidth maxIterations:kMaxIterations]; - if (includeMargins) { - result.width += hMargins; - result.height += (self.conversationStyle.textInsetTop + self.conversationStyle.textInsetBottom); - } - - return CGSizeCeil(result); + return [NSValue valueWithCGSize:CGSizeCeil(result)]; } -- (CGSize)bodyMediaSize +- (nullable NSValue *)bodyMediaSize { OWSAssert(self.conversationStyle); OWSAssert(self.conversationStyle.maxMessageWidth > 0); @@ -967,8 +974,7 @@ NS_ASSUME_NONNULL_BEGIN case OWSMessageCellType_Unknown: case OWSMessageCellType_TextMessage: case OWSMessageCellType_OversizeTextMessage: { - result = CGSizeZero; - break; + return nil; } case OWSMessageCellType_StillImage: case OWSMessageCellType_AnimatedImage: @@ -1024,10 +1030,10 @@ NS_ASSUME_NONNULL_BEGIN break; } - return CGSizeCeil(result); + return [NSValue valueWithCGSize:CGSizeCeil(result)]; } -- (CGSize)quotedMessageSize +- (nullable NSValue *)quotedMessageSize { OWSAssert(self.conversationStyle); OWSAssert(self.conversationStyle.maxMessageWidth > 0); @@ -1035,7 +1041,7 @@ NS_ASSUME_NONNULL_BEGIN OWSAssert([self.viewItem.interaction isKindOfClass:[TSMessage class]]); if (!self.isQuotedReply) { - return CGSizeZero; + return nil; } BOOL isOutgoing = [self.viewItem.interaction isKindOfClass:TSOutgoingMessage.class]; @@ -1047,16 +1053,16 @@ NS_ASSUME_NONNULL_BEGIN displayableQuotedText:displayableQuotedText isOutgoing:isOutgoing]; CGSize result = [quotedMessageView sizeForMaxWidth:self.conversationStyle.maxMessageWidth]; - return CGSizeCeil(result); + return [NSValue valueWithCGSize:CGSizeCeil(result)]; } -- (CGSize)senderNameSizeWithBodyMediaSize:(CGSize)bodyMediaSize includeMargins:(BOOL)includeMargins +- (nullable NSValue *)senderNameSize { OWSAssert(self.conversationStyle); OWSAssert(self.conversationStyle.maxMessageWidth > 0); if (!self.shouldShowSenderName) { - return CGSizeZero; + return nil; } CGFloat hMargins = self.conversationStyle.textInsetHorizontal * 2; @@ -1064,18 +1070,7 @@ NS_ASSUME_NONNULL_BEGIN [self configureSenderNameLabel]; CGSize result = CGSizeCeil([self.senderNameLabel sizeThatFits:CGSizeMake(maxTextWidth, CGFLOAT_MAX)]); - BOOL hasSeparateTextStackView = (self.isQuotedReply || bodyMediaSize.width > 0 || bodyMediaSize.height > 0); - - if (includeMargins) { - result.width += hMargins; - - if (hasSeparateTextStackView) { - result.height += (self.conversationStyle.textInsetTop + self.conversationStyle.textInsetBottom); - } else { - result.height += self.textViewVSpacing; - } - } - return result; + return [NSValue valueWithCGSize:result]; } - (CGSize)measureSize @@ -1087,24 +1082,56 @@ NS_ASSUME_NONNULL_BEGIN CGSize cellSize = CGSizeZero; - // TODO: Reflect "sender name" and "footer" layout. - // shouldFooterOverlayMedia = self.canFooterOverlayMedia; + NSMutableArray *textViewSizes = [NSMutableArray new]; - CGSize quotedMessageSize = [self quotedMessageSize]; - cellSize.width = MAX(cellSize.width, quotedMessageSize.width); - cellSize.height += quotedMessageSize.height; + NSValue *_Nullable senderNameSize = [self senderNameSize]; + if (senderNameSize) { + [textViewSizes addObject:senderNameSize]; + } - CGSize bodyMediaSize = [self bodyMediaSize]; - cellSize.width = MAX(cellSize.width, bodyMediaSize.width); - cellSize.height += bodyMediaSize.height; + NSValue *_Nullable quotedMessageSize = [self quotedMessageSize]; + if (quotedMessageSize) { + cellSize.width = MAX(cellSize.width, quotedMessageSize.CGSizeValue.width); + cellSize.height += quotedMessageSize.CGSizeValue.height; + } - CGSize senderNameSize = [self senderNameSizeWithBodyMediaSize:bodyMediaSize includeMargins:YES]; - cellSize.width = MAX(cellSize.width, senderNameSize.width); - cellSize.height += senderNameSize.height; + NSValue *_Nullable bodyMediaSize = [self bodyMediaSize]; + if (bodyMediaSize) { + if (self.hasBodyMediaWithThumbnail) { + cellSize.width = MAX(cellSize.width, bodyMediaSize.CGSizeValue.width); + cellSize.height += bodyMediaSize.CGSizeValue.height; + } else { + DDLogVerbose(@"%@ ---- bodyMediaSize: %@", self.logTag, bodyMediaSize); + [textViewSizes addObject:bodyMediaSize]; + bodyMediaSize = nil; + } + } - CGSize textContentSize = [self bodyTextSizeWithIncludeMargins:YES]; - cellSize.width = MAX(cellSize.width, textContentSize.width); - cellSize.height += textContentSize.height; + if (bodyMediaSize || quotedMessageSize) { + if (textViewSizes.count > 0) { + CGSize groupSize = [self sizeForTextViewGroup:textViewSizes]; + cellSize.width = MAX(cellSize.width, groupSize.width); + cellSize.height += groupSize.height; + [textViewSizes removeAllObjects]; + } + } + + NSValue *_Nullable bodyTextSize = [self bodyTextSize]; + if (bodyTextSize) { + [textViewSizes addObject:bodyTextSize]; + } + + BOOL shouldFooterOverlayMedia = (self.canFooterOverlayMedia && !self.hasBodyText); + if (!self.viewItem.shouldHideFooter && !shouldFooterOverlayMedia) { + CGSize footerSize = [self.footerView measureWithConversationViewItem:self.viewItem]; + [textViewSizes addObject:[NSValue valueWithCGSize:footerSize]]; + } + + if (textViewSizes.count > 0) { + CGSize groupSize = [self sizeForTextViewGroup:textViewSizes]; + cellSize.width = MAX(cellSize.width, groupSize.width); + cellSize.height += groupSize.height; + } // Make sure the bubble is always wide enough to complete it's bubble shape. cellSize.width = MAX(cellSize.width, OWSBubbleView.minWidth); @@ -1115,23 +1142,32 @@ NS_ASSUME_NONNULL_BEGIN cellSize.height += self.tapForMoreHeight + self.textViewVSpacing; } - // TODO: Update this to reflect generic attachment, downloading attachments and - // contact shares. - BOOL shouldFooterOverlayMedia = (self.canFooterOverlayMedia && !self.hasBodyText); - if (!self.viewItem.shouldHideFooter && !shouldFooterOverlayMedia) { - CGSize footerSize = [self.footerView measureWithConversationViewItem:self.viewItem]; - cellSize.width = MAX(cellSize.width, footerSize.width + self.conversationStyle.textInsetHorizontal * 2); - cellSize.height += self.textViewVSpacing + footerSize.height; - if (!self.hasBodyText) { - cellSize.height += (self.conversationStyle.textInsetTop + self.conversationStyle.textInsetBottom); - } - } - cellSize = CGSizeCeil(cellSize); + DDLogVerbose(@"%@ ---- cellSize: %@", self.logTag, NSStringFromCGSize(cellSize)); + return cellSize; } +- (CGSize)sizeForTextViewGroup:(NSArray *)textViewSizes +{ + OWSAssert(textViewSizes); + OWSAssert(textViewSizes.count > 0); + OWSAssert(self.conversationStyle); + OWSAssert(self.conversationStyle.maxMessageWidth > 0); + + CGSize result = CGSizeZero; + for (NSValue *size in textViewSizes) { + result.width = MAX(result.width, size.CGSizeValue.width); + result.height += size.CGSizeValue.height; + } + result.height += self.textViewVSpacing * (textViewSizes.count - 1); + result.height += (self.conversationStyle.textInsetTop + self.conversationStyle.textInsetBottom); + result.width += self.conversationStyle.textInsetHorizontal * 2; + + return result; +} + - (UIFont *)tapForMoreFont { return UIFont.ows_dynamicTypeCaption1Font;