From 8d74c68f9de6f9d422f1aa53905704149ab8132b Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 28 Mar 2018 16:10:35 -0400 Subject: [PATCH] Bubble collapse. --- .../ConversationView/Cells/OWSMessageCell.m | 20 ++- .../ConversationView/ConversationViewItem.m | 4 - .../ViewControllers/DebugUI/DebugUIMessages.m | 120 +++++++++++++----- .../DebugUI/DebugUIMessagesAssetLoader.m | 2 +- .../Messages/Attachments/TSAttachmentStream.m | 30 ++--- 5 files changed, 119 insertions(+), 57 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m index 9e673e526..c0b4fb018 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m @@ -505,6 +505,7 @@ CG_INLINE CGSize CGSizeCeil(CGSize size) - (nullable id)tryToLoadCellMedia:(nullable id (^)(void))loadCellMediaBlock mediaView:(UIView *)mediaView cacheKey:(NSString *)cacheKey + shouldSkipCache:(BOOL)shouldSkipCache { OWSAssert(self.attachmentStream); OWSAssert(mediaView); @@ -525,7 +526,9 @@ CG_INLINE CGSize CGSizeCeil(CGSize size) cellMedia = loadCellMediaBlock(); if (cellMedia) { DDLogVerbose(@"%@ cell media cache miss", self.logTag); - [cellMediaCache setObject:cellMedia forKey:cacheKey]; + if (!shouldSkipCache) { + [cellMediaCache setObject:cellMedia forKey:cacheKey]; + } } else { DDLogError(@"%@ Failed to load cell media: %@", [self logTag], [self.attachmentStream mediaURL]); self.viewItem.didCellMediaFailToLoad = YES; @@ -804,12 +807,17 @@ CG_INLINE CGSize CGSizeCeil(CGSize size) if (stillImageView.image) { return; } + // Don't cache large still images. + const NSUInteger kMaxCachableSize = 1024 * 1024; + BOOL shouldSkipCache = + [OWSFileSystem fileSizeOfPath:strongSelf.attachmentStream.filePath].unsignedIntegerValue < kMaxCachableSize; stillImageView.image = [strongSelf tryToLoadCellMedia:^{ OWSCAssert([strongSelf.attachmentStream isImage]); return strongSelf.attachmentStream.image; } mediaView:stillImageView - cacheKey:strongSelf.attachmentStream.uniqueId]; + cacheKey:strongSelf.attachmentStream.uniqueId + shouldSkipCache:shouldSkipCache]; }; self.unloadCellContentBlock = ^{ stillImageView.image = nil; @@ -849,7 +857,8 @@ CG_INLINE CGSize CGSizeCeil(CGSize size) return animatedImage; } mediaView:animatedImageView - cacheKey:strongSelf.attachmentStream.uniqueId]; + cacheKey:strongSelf.attachmentStream.uniqueId + shouldSkipCache:NO]; }; self.unloadCellContentBlock = ^{ animatedImageView.image = nil; @@ -918,7 +927,8 @@ CG_INLINE CGSize CGSizeCeil(CGSize size) return strongSelf.attachmentStream.image; } mediaView:stillImageView - cacheKey:strongSelf.attachmentStream.uniqueId]; + cacheKey:strongSelf.attachmentStream.uniqueId + shouldSkipCache:NO]; }; self.unloadCellContentBlock = ^{ stillImageView.image = nil; @@ -1071,7 +1081,7 @@ CG_INLINE CGSize CGSizeCeil(CGSize size) CGFloat contentAspectRatio = self.mediaSize.width / self.mediaSize.height; // Clamp the aspect ratio so that very thin/wide content is presented // in a reasonable way. - const CGFloat minAspectRatio = 0.25f; + const CGFloat minAspectRatio = 0.35f; const CGFloat maxAspectRatio = 1 / minAspectRatio; contentAspectRatio = MAX(minAspectRatio, MIN(maxAspectRatio, contentAspectRatio)); diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m index 9bde6eaf7..a26eac86f 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m @@ -86,8 +86,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) [self ensureViewState:transaction]; - // OWSAssert(self.hasViewState); - return self; } @@ -107,8 +105,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) [self clearCachedLayoutState]; [self ensureViewState:transaction]; - - // OWSAssert(self.hasViewState); } - (BOOL)hasText diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m index db6e9d9bf..016a83c0a 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m @@ -60,7 +60,7 @@ NS_ASSUME_NONNULL_BEGIN [DebugUIMessages fakeAllTextAction:thread], [DebugUIMessages fakeRandomTextAction:thread], // Exemplary - [DebugUIMessages allExemplaryAction:thread], + [DebugUIMessages allFakeAction:thread], ]) { [items addObject:[OWSTableItem itemWithTitle:action.label actionBlock:^{ @@ -89,9 +89,13 @@ NS_ASSUME_NONNULL_BEGIN // actionBlock:^{ // [DebugUIMessages sendSelectedMediaTypeInThread:thread]; // }], - [OWSTableItem itemWithTitle:@"Select Action" + [OWSTableItem itemWithTitle:@"Select Fake" actionBlock:^{ - [DebugUIMessages selectExemplaryAction:thread]; + [DebugUIMessages selectFakeAction:thread]; + }], + [OWSTableItem itemWithTitle:@"Select Send Media" + actionBlock:^{ + [DebugUIMessages selectSendMediaAction:thread]; }], #pragma mark - Misc. @@ -360,6 +364,8 @@ NS_ASSUME_NONNULL_BEGIN + (void)sendAttachment:(NSString *)filePath thread:(TSThread *)thread + label:(NSString *)label + hasCaption:(BOOL)hasCaption success:(nullable void (^)(void))success failure:(nullable void (^)(void))failure { @@ -373,9 +379,18 @@ NS_ASSUME_NONNULL_BEGIN [dataSource setSourceFilename:filename]; SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType imageQuality:TSImageQualityOriginal]; - if (arc4random_uniform(100) > 50) { - attachment.captionText = [self randomCaptionText]; + + NSString *messageBody = nil; + if (hasCaption) { + // We want a message body that is "more than one line on all devices, + // using all dynamic type sizes." + NSString *sampleText = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, " + @"consectetur adipiscing elit."; + messageBody = [[label stringByAppendingString:@" "] stringByAppendingString:sampleText]; + + messageBody = [messageBody stringByAppendingString:@" 🔤"]; } + attachment.captionText = messageBody; OWSAssert(attachment); if ([attachment hasError]) { @@ -423,50 +438,72 @@ NS_ASSUME_NONNULL_BEGIN OWSAssert(thread); NSArray *actions = @[ - [self sendJpegAction:thread], - [self sendGifAction:thread], - [self sendMp3Action:thread], - [self sendMp4Action:thread], + [self sendJpegAction:thread hasCaption:NO], + [self sendJpegAction:thread hasCaption:YES], + [self sendGifAction:thread hasCaption:NO], + [self sendGifAction:thread hasCaption:YES], + [self sendMp3Action:thread hasCaption:NO], + [self sendMp3Action:thread hasCaption:YES], + [self sendMp4Action:thread hasCaption:NO], + [self sendMp4Action:thread hasCaption:YES], ]; return actions; } -+ (DebugUIMessagesAction *)sendJpegAction:(TSThread *)thread ++ (DebugUIMessagesAction *)sendJpegAction:(TSThread *)thread hasCaption:(BOOL)hasCaption { OWSAssert(thread); - return [self sendMediaAction:@"Send Jpeg" fakeAssetLoader:[DebugUIMessagesAssetLoader jpegInstance] thread:thread]; + return [self sendMediaAction:@"Send Jpeg" + hasCaption:hasCaption + fakeAssetLoader:[DebugUIMessagesAssetLoader jpegInstance] + thread:thread]; } -+ (DebugUIMessagesAction *)sendGifAction:(TSThread *)thread ++ (DebugUIMessagesAction *)sendGifAction:(TSThread *)thread hasCaption:(BOOL)hasCaption { OWSAssert(thread); - return [self sendMediaAction:@"Send Gif" fakeAssetLoader:[DebugUIMessagesAssetLoader gifInstance] thread:thread]; + return [self sendMediaAction:@"Send Gif" + hasCaption:hasCaption + fakeAssetLoader:[DebugUIMessagesAssetLoader gifInstance] + thread:thread]; } -+ (DebugUIMessagesAction *)sendMp3Action:(TSThread *)thread ++ (DebugUIMessagesAction *)sendMp3Action:(TSThread *)thread hasCaption:(BOOL)hasCaption { OWSAssert(thread); - return [self sendMediaAction:@"Send Mp3" fakeAssetLoader:[DebugUIMessagesAssetLoader mp3Instance] thread:thread]; + return [self sendMediaAction:@"Send Mp3" + hasCaption:hasCaption + fakeAssetLoader:[DebugUIMessagesAssetLoader mp3Instance] + thread:thread]; } -+ (DebugUIMessagesAction *)sendMp4Action:(TSThread *)thread ++ (DebugUIMessagesAction *)sendMp4Action:(TSThread *)thread hasCaption:(BOOL)hasCaption { OWSAssert(thread); - return [self sendMediaAction:@"Send Mp4" fakeAssetLoader:[DebugUIMessagesAssetLoader mp4Instance] thread:thread]; + return [self sendMediaAction:@"Send Mp4" + hasCaption:hasCaption + fakeAssetLoader:[DebugUIMessagesAssetLoader mp4Instance] + thread:thread]; } -+ (DebugUIMessagesAction *)sendMediaAction:(NSString *)label ++ (DebugUIMessagesAction *)sendMediaAction:(NSString *)labelParam + hasCaption:(BOOL)hasCaption fakeAssetLoader:(DebugUIMessagesAssetLoader *)fakeAssetLoader thread:(TSThread *)thread { - OWSAssert(label.length > 0); + OWSAssert(labelParam.length > 0); OWSAssert(fakeAssetLoader); OWSAssert(thread); + NSString *label = labelParam; + if (hasCaption) { + label = [label stringByAppendingString:@" 🔤"]; + } + return [DebugUIMessagesSingleAction actionWithLabel:label staggeredActionBlock:^(NSUInteger index, @@ -475,7 +512,12 @@ NS_ASSUME_NONNULL_BEGIN ActionFailureBlock failure) { dispatch_async(dispatch_get_main_queue(), ^{ OWSAssert(fakeAssetLoader.filePath.length > 0); - [self sendAttachment:fakeAssetLoader.filePath thread:thread success:success failure:failure]; + [self sendAttachment:fakeAssetLoader.filePath + thread:thread + label:label + hasCaption:hasCaption + success:success + failure:failure]; }); } prepareBlock:fakeAssetLoader.prepareBlock]; @@ -485,7 +527,7 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssert(thread); - return [DebugUIMessagesGroupAction allGroupActionWithLabel:@"Send All Media" + return [DebugUIMessagesGroupAction allGroupActionWithLabel:@"All Send Media" subactions:[self allSendMediaActions:thread]]; } @@ -493,10 +535,17 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssert(thread); - return [DebugUIMessagesGroupAction randomGroupActionWithLabel:@"Send Random Media" + return [DebugUIMessagesGroupAction randomGroupActionWithLabel:@"Random Send Media" subactions:[self allSendMediaActions:thread]]; } ++ (void)selectSendMediaAction:(TSThread *)thread +{ + OWSAssert(thread); + + [self selectActionUI:[self allSendMediaActions:thread] label:@"Select Send Media"]; +} + #pragma mark - Fake Outgoing Media + (DebugUIMessagesAction *)fakeOutgoingJpegAction:(TSThread *)thread @@ -1669,7 +1718,7 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Exemplary -+ (NSArray *)allExemplaryActions:(TSThread *)thread includeLabels:(BOOL)includeLabels ++ (NSArray *)allFakeActions:(TSThread *)thread includeLabels:(BOOL)includeLabels { OWSAssert(thread); @@ -1679,21 +1728,28 @@ NS_ASSUME_NONNULL_BEGIN return actions; } -+ (DebugUIMessagesAction *)allExemplaryAction:(TSThread *)thread ++ (DebugUIMessagesAction *)allFakeAction:(TSThread *)thread { OWSAssert(thread); - return [DebugUIMessagesGroupAction allGroupActionWithLabel:@"Exemplary Permutations" - subactions:[self allExemplaryActions:thread includeLabels:YES]]; + return [DebugUIMessagesGroupAction allGroupActionWithLabel:@"All Fake" + subactions:[self allFakeActions:thread includeLabels:YES]]; } -+ (void)selectExemplaryAction:(TSThread *)thread ++ (void)selectFakeAction:(TSThread *)thread { - OWSAssertIsOnMainThread() OWSAssert(thread); - UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Select Action" - message:nil - preferredStyle:UIAlertControllerStyleActionSheet]; - for (DebugUIMessagesAction *action in [self allExemplaryActions:thread includeLabels:NO]) { + OWSAssertIsOnMainThread(); + OWSAssert(thread); + + [self selectActionUI:[self allFakeActions:thread includeLabels:NO] label:@"Select Fake"]; +} + ++ (void)selectActionUI:(NSArray *)actions label:(NSString *)label +{ + OWSAssertIsOnMainThread(); + UIAlertController *alert = + [UIAlertController alertControllerWithTitle:label message:nil preferredStyle:UIAlertControllerStyleActionSheet]; + for (DebugUIMessagesAction *action in actions) { [alert addAction:[UIAlertAction actionWithTitle:action.label style:UIAlertActionStyleDefault handler:^(UIAlertAction *ignore) { diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessagesAssetLoader.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessagesAssetLoader.m index 073171031..079854474 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMessagesAssetLoader.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessagesAssetLoader.m @@ -349,7 +349,7 @@ NS_ASSUME_NONNULL_BEGIN dispatch_once(&onceToken, ^{ instance = [DebugUIMessagesAssetLoader fakeAssetLoaderWithUrl:@"https://s3.amazonaws.com/ows-data/example_attachment_media/random-mp3.mp3" - mimeType:@"audio/mpeg"]; + mimeType:@"audio/mp3"]; }); return instance; } diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m index 727175897..33bcd2141 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m @@ -572,21 +572,21 @@ NS_ASSUME_NONNULL_BEGIN OWSAssertIsOnMainThread(); OWSAssert([self isAudio]); - return 0; - - // NSError *error; - // AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:self.mediaURL error:&error]; - // if (error && [error.domain isEqualToString:NSOSStatusErrorDomain] - // && (error.code == kAudioFileInvalidFileError || error.code == kAudioFileStreamError_InvalidFile)) { - // // Ignore "invalid audio file" errors. - // return 0.f; - // } - // if (!error) { - // return (CGFloat)[audioPlayer duration]; - // } else { - // OWSFail(@"Could not find audio duration: %@", self.mediaURL); - // return 0; - // } + // return 0; + + NSError *error; + AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:self.mediaURL error:&error]; + if (error && [error.domain isEqualToString:NSOSStatusErrorDomain] + && (error.code == kAudioFileInvalidFileError || error.code == kAudioFileStreamError_InvalidFile)) { + // Ignore "invalid audio file" errors. + return 0.f; + } + if (!error) { + return (CGFloat)[audioPlayer duration]; + } else { + OWSFail(@"Could not find audio duration: %@", self.mediaURL); + return 0; + } } - (CGFloat)audioDurationSeconds