diff --git a/Signal/Images.xcassets/empty-group-avatar.imageset/Contents.json b/Signal/Images.xcassets/empty-group-avatar.imageset/Contents.json index c8b0525d9..00c7b2c36 100644 --- a/Signal/Images.xcassets/empty-group-avatar.imageset/Contents.json +++ b/Signal/Images.xcassets/empty-group-avatar.imageset/Contents.json @@ -2,7 +2,16 @@ "images" : [ { "idiom" : "universal", - "filename" : "group-avi.pdf" + "filename" : "empty-group-avatar.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" } ], "info" : { diff --git a/Signal/Images.xcassets/empty-group-avatar.imageset/empty-group-avatar.png b/Signal/Images.xcassets/empty-group-avatar.imageset/empty-group-avatar.png new file mode 100644 index 000000000..c18015bbf Binary files /dev/null and b/Signal/Images.xcassets/empty-group-avatar.imageset/empty-group-avatar.png differ diff --git a/Signal/Images.xcassets/empty-group-avatar_old.imageset/Contents.json b/Signal/Images.xcassets/empty-group-avatar_old.imageset/Contents.json new file mode 100644 index 000000000..c8b0525d9 --- /dev/null +++ b/Signal/Images.xcassets/empty-group-avatar_old.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "group-avi.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/empty-group-avatar.imageset/group-avi.pdf b/Signal/Images.xcassets/empty-group-avatar_old.imageset/group-avi.pdf similarity index 100% rename from Signal/Images.xcassets/empty-group-avatar.imageset/group-avi.pdf rename to Signal/Images.xcassets/empty-group-avatar_old.imageset/group-avi.pdf diff --git a/Signal/Images.xcassets/system_message_call.imageset/Contents.json b/Signal/Images.xcassets/system_message_call.imageset/Contents.json new file mode 100644 index 000000000..4d7738bb3 --- /dev/null +++ b/Signal/Images.xcassets/system_message_call.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "system_message_call@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "system_message_call@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "system_message_call@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/system_message_call.imageset/system_message_call@1x.png b/Signal/Images.xcassets/system_message_call.imageset/system_message_call@1x.png new file mode 100644 index 000000000..41257d76a Binary files /dev/null and b/Signal/Images.xcassets/system_message_call.imageset/system_message_call@1x.png differ diff --git a/Signal/Images.xcassets/system_message_call.imageset/system_message_call@2x.png b/Signal/Images.xcassets/system_message_call.imageset/system_message_call@2x.png new file mode 100644 index 000000000..46e4d44a3 Binary files /dev/null and b/Signal/Images.xcassets/system_message_call.imageset/system_message_call@2x.png differ diff --git a/Signal/Images.xcassets/system_message_call.imageset/system_message_call@3x.png b/Signal/Images.xcassets/system_message_call.imageset/system_message_call@3x.png new file mode 100644 index 000000000..befa6647a Binary files /dev/null and b/Signal/Images.xcassets/system_message_call.imageset/system_message_call@3x.png differ diff --git a/Signal/Images.xcassets/system_message_group.imageset/Contents.json b/Signal/Images.xcassets/system_message_group.imageset/Contents.json new file mode 100644 index 000000000..b08517114 --- /dev/null +++ b/Signal/Images.xcassets/system_message_group.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "system_message_group@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "system_message_group@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "system_message_group@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/system_message_group.imageset/system_message_group@1x.png b/Signal/Images.xcassets/system_message_group.imageset/system_message_group@1x.png new file mode 100644 index 000000000..282b5bbef Binary files /dev/null and b/Signal/Images.xcassets/system_message_group.imageset/system_message_group@1x.png differ diff --git a/Signal/Images.xcassets/system_message_group.imageset/system_message_group@2x.png b/Signal/Images.xcassets/system_message_group.imageset/system_message_group@2x.png new file mode 100644 index 000000000..03abe643a Binary files /dev/null and b/Signal/Images.xcassets/system_message_group.imageset/system_message_group@2x.png differ diff --git a/Signal/Images.xcassets/system_message_group.imageset/system_message_group@3x.png b/Signal/Images.xcassets/system_message_group.imageset/system_message_group@3x.png new file mode 100644 index 000000000..b57da5eb1 Binary files /dev/null and b/Signal/Images.xcassets/system_message_group.imageset/system_message_group@3x.png differ diff --git a/Signal/Images.xcassets/system_message_info.imageset/Contents.json b/Signal/Images.xcassets/system_message_info.imageset/Contents.json new file mode 100644 index 000000000..17efdbeb5 --- /dev/null +++ b/Signal/Images.xcassets/system_message_info.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "system_message_info@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "system_message_info@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "system_message_info@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/system_message_info.imageset/system_message_info@1x.png b/Signal/Images.xcassets/system_message_info.imageset/system_message_info@1x.png new file mode 100644 index 000000000..6215ddf3c Binary files /dev/null and b/Signal/Images.xcassets/system_message_info.imageset/system_message_info@1x.png differ diff --git a/Signal/Images.xcassets/system_message_info.imageset/system_message_info@2x.png b/Signal/Images.xcassets/system_message_info.imageset/system_message_info@2x.png new file mode 100644 index 000000000..5b012a899 Binary files /dev/null and b/Signal/Images.xcassets/system_message_info.imageset/system_message_info@2x.png differ diff --git a/Signal/Images.xcassets/system_message_info.imageset/system_message_info@3x.png b/Signal/Images.xcassets/system_message_info.imageset/system_message_info@3x.png new file mode 100644 index 000000000..fdc2760ce Binary files /dev/null and b/Signal/Images.xcassets/system_message_info.imageset/system_message_info@3x.png differ diff --git a/Signal/Images.xcassets/system_message_security.imageset/system_message_security@1x.png b/Signal/Images.xcassets/system_message_security.imageset/system_message_security@1x.png index efdaa2b0c..ce619b653 100644 Binary files a/Signal/Images.xcassets/system_message_security.imageset/system_message_security@1x.png and b/Signal/Images.xcassets/system_message_security.imageset/system_message_security@1x.png differ diff --git a/Signal/Images.xcassets/system_message_security.imageset/system_message_security@2x.png b/Signal/Images.xcassets/system_message_security.imageset/system_message_security@2x.png index 7b995d812..62e683435 100644 Binary files a/Signal/Images.xcassets/system_message_security.imageset/system_message_security@2x.png and b/Signal/Images.xcassets/system_message_security.imageset/system_message_security@2x.png differ diff --git a/Signal/Images.xcassets/system_message_security.imageset/system_message_security@3x.png b/Signal/Images.xcassets/system_message_security.imageset/system_message_security@3x.png index 315db7973..a82724734 100644 Binary files a/Signal/Images.xcassets/system_message_security.imageset/system_message_security@3x.png and b/Signal/Images.xcassets/system_message_security.imageset/system_message_security@3x.png differ diff --git a/Signal/Images.xcassets/system_message_timer.imageset/Contents.json b/Signal/Images.xcassets/system_message_timer.imageset/Contents.json new file mode 100644 index 000000000..b1af6ed5c --- /dev/null +++ b/Signal/Images.xcassets/system_message_timer.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "system_message_timer@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "system_message_timer@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "system_message_timer@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/system_message_timer.imageset/system_message_timer@1x.png b/Signal/Images.xcassets/system_message_timer.imageset/system_message_timer@1x.png new file mode 100644 index 000000000..d71210f4b Binary files /dev/null and b/Signal/Images.xcassets/system_message_timer.imageset/system_message_timer@1x.png differ diff --git a/Signal/Images.xcassets/system_message_timer.imageset/system_message_timer@2x.png b/Signal/Images.xcassets/system_message_timer.imageset/system_message_timer@2x.png new file mode 100644 index 000000000..db3014728 Binary files /dev/null and b/Signal/Images.xcassets/system_message_timer.imageset/system_message_timer@2x.png differ diff --git a/Signal/Images.xcassets/system_message_timer.imageset/system_message_timer@3x.png b/Signal/Images.xcassets/system_message_timer.imageset/system_message_timer@3x.png new file mode 100644 index 000000000..7622d0c1a Binary files /dev/null and b/Signal/Images.xcassets/system_message_timer.imageset/system_message_timer@3x.png differ diff --git a/Signal/Images.xcassets/system_message_warning.imageset/Contents.json b/Signal/Images.xcassets/system_message_warning.imageset/Contents.json new file mode 100644 index 000000000..6f24ed02a --- /dev/null +++ b/Signal/Images.xcassets/system_message_warning.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "system_message_warning@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "system_message_warning@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "system_message_warning@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/system_message_warning.imageset/system_message_warning@1x.png b/Signal/Images.xcassets/system_message_warning.imageset/system_message_warning@1x.png new file mode 100644 index 000000000..5a7836dee Binary files /dev/null and b/Signal/Images.xcassets/system_message_warning.imageset/system_message_warning@1x.png differ diff --git a/Signal/Images.xcassets/system_message_warning.imageset/system_message_warning@2x.png b/Signal/Images.xcassets/system_message_warning.imageset/system_message_warning@2x.png new file mode 100644 index 000000000..104e745e7 Binary files /dev/null and b/Signal/Images.xcassets/system_message_warning.imageset/system_message_warning@2x.png differ diff --git a/Signal/Images.xcassets/system_message_warning.imageset/system_message_warning@3x.png b/Signal/Images.xcassets/system_message_warning.imageset/system_message_warning@3x.png new file mode 100644 index 000000000..ec37d5752 Binary files /dev/null and b/Signal/Images.xcassets/system_message_warning.imageset/system_message_warning@3x.png differ diff --git a/Signal/src/Models/OWSMessagesBubblesSizeCalculator.m b/Signal/src/Models/OWSMessagesBubblesSizeCalculator.m index 1ed99b553..524574816 100644 --- a/Signal/src/Models/OWSMessagesBubblesSizeCalculator.m +++ b/Signal/src/Models/OWSMessagesBubblesSizeCalculator.m @@ -9,7 +9,9 @@ #import "OWSUnreadIndicatorCell.h" #import "TSGenericAttachmentAdapter.h" #import "TSMessageAdapter.h" +#import "TSUnreadIndicatorInteraction.h" #import "UIFont+OWS.h" +#import "UIView+OWS.h" #import "tgmath.h" // generic math allows fmax to handle CGFLoat correctly on 32 & 64bit. #import #import @@ -49,22 +51,59 @@ NS_ASSUME_NONNULL_BEGIN atIndexPath:(NSIndexPath *)indexPath withLayout:(JSQMessagesCollectionViewFlowLayout *)layout { + // DDLogError(@"----- ?? %@", + // [messageData class]); + if ([messageData isKindOfClass:[TSMessageAdapter class]]) { TSMessageAdapter *message = (TSMessageAdapter *)messageData; - if (message.messageType == TSErrorMessageAdapter) { - return [OWSSystemMessageCell cellSizeForInteraction:((TSMessageAdapter *)messageData).interaction - collectionViewWidth:layout.collectionView.bounds.size.width]; - } else if (message.messageType == TSInfoMessageAdapter || message.messageType == TSErrorMessageAdapter) { - return [self messageBubbleSizeForInfoMessageData:messageData atIndexPath:indexPath withLayout:layout]; - } else if (message.messageType == TSUnreadIndicatorAdapter) { - return [OWSUnreadIndicatorCell - cellSizeForInteraction:(TSUnreadIndicatorInteraction *)((TSMessageAdapter *)messageData).interaction - collectionViewWidth:layout.collectionView.bounds.size.width]; - } - } - if ([messageData isKindOfClass:[OWSCall class]]) { - return [self messageBubbleSizeForCallData:messageData atIndexPath:indexPath withLayout:layout]; + // DDLogError(@"----- ???? %d", (int) message.messageType); + + switch (message.messageType) { + case TSCallAdapter: + case TSInfoMessageAdapter: + case TSErrorMessageAdapter: { + id cacheKey = [self cacheKeyForMessageData:messageData]; + TSInteraction *interaction = ((TSMessageAdapter *)messageData).interaction; + return [self sizeForSystemMessage:interaction cacheKey:cacheKey layout:layout]; + } + case TSUnreadIndicatorAdapter: { + id cacheKey = [self cacheKeyForMessageData:messageData]; + + TSUnreadIndicatorInteraction *interaction + = (TSUnreadIndicatorInteraction *)((TSMessageAdapter *)messageData).interaction; + + NSValue *cachedSize = [self.cache objectForKey:cacheKey]; + if (cachedSize != nil) { + // DDLogError(@"----- cache hit[%@,%@], %@ %@", + // [interaction class], + // cacheKey, + // NSStringFromCGSize([cachedSize CGSizeValue]), + // interaction.description); + return [cachedSize CGSizeValue]; + } + + CGSize result = [OWSUnreadIndicatorCell cellSizeForInteraction:interaction + collectionViewWidth:layout.collectionView.width]; + + [self.cache setObject:[NSValue valueWithCGSize:result] forKey:cacheKey]; + + // DDLogError(@"----- cache miss[%@,%@], %@ %@", + // [interaction class], + // cacheKey, + // NSStringFromCGSize(result), + // interaction.description); + + return result; + } + default: + // TODO: we need to examine the other cases. + break; + } + } else if ([messageData isKindOfClass:[OWSCall class]]) { + id cacheKey = [self cacheKeyForMessageData:messageData]; + TSInteraction *interaction = ((OWSCall *)messageData).interaction; + return [self sizeForSystemMessage:interaction cacheKey:cacheKey layout:layout]; } // BEGIN HACK iOS10EmojiBug see: https://github.com/WhisperSystems/Signal-iOS/issues/1368 @@ -79,6 +118,37 @@ NS_ASSUME_NONNULL_BEGIN } } +- (CGSize)sizeForSystemMessage:(TSInteraction *)interaction + cacheKey:(id)cacheKey + layout:(JSQMessagesCollectionViewFlowLayout *)layout +{ + OWSAssert(interaction); + OWSAssert(cacheKey); + + NSValue *cachedSize = [self.cache objectForKey:cacheKey]; + if (cachedSize != nil) { + // DDLogError(@"----- cache hit[%@,%@], %@ %@", + // [interaction class], + // cacheKey, + // NSStringFromCGSize([cachedSize CGSizeValue]), + // interaction.description); + return [cachedSize CGSizeValue]; + } + + CGSize result = + [OWSSystemMessageCell cellSizeForInteraction:interaction collectionViewWidth:layout.collectionView.width]; + + [self.cache setObject:[NSValue valueWithCGSize:result] forKey:cacheKey]; + + // DDLogError(@"----- cache miss[%@,%@], %@ %@", + // [interaction class], + // cacheKey, + // NSStringFromCGSize(result), + // interaction.description); + + return result; +} + /** * Emoji sizing bug only affects iOS10. Unfortunately the "fix" for emoji font breaks some other fonts, so it's * important @@ -137,120 +207,6 @@ NS_ASSUME_NONNULL_BEGIN return CGSizeMake(superSize.width, superSize.height + (CGFloat)1.5 * lines); } - -- (CGSize)messageBubbleSizeForInfoMessageData:(id)messageData - atIndexPath:(NSIndexPath *)indexPath - withLayout:(JSQMessagesCollectionViewFlowLayout *)layout -{ - id cacheKey = [self cacheKeyForMessageData:messageData]; - - NSValue *cachedSize = [self.cache objectForKey:cacheKey]; - if (cachedSize != nil) { - return [cachedSize CGSizeValue]; - } - - CGSize finalSize = CGSizeZero; - - if ([messageData isMediaMessage]) { - finalSize = [[messageData media] mediaViewDisplaySize]; - } else { - /////////////////// - // BEGIN InfoMessage sizing HACK - // Braindead, and painstakingly produced. - // If you want to change, check for clipping / excess space on 1, 2, and 3 line messages with short and long - // words very near the edge. - -// CGSize avatarSize = [self jsq_avatarSizeForMessageData:messageData withLayout:layout]; -// // from the cell xibs, there is a 2 point space between avatar and bubble -// CGFloat spacingBetweenAvatarAndBubble = 2.0f; -// CGFloat horizontalContainerInsets = layout.messageBubbleTextViewTextContainerInsets.left + layout.messageBubbleTextViewTextContainerInsets.right; -// CGFloat horizontalFrameInsets = layout.messageBubbleTextViewFrameInsets.left + layout.messageBubbleTextViewFrameInsets.right; -// CGFloat horizontalInsetsTotal = horizontalContainerInsets + horizontalFrameInsets + spacingBetweenAvatarAndBubble; -// CGFloat maximumTextWidth = [self textBubbleWidthForLayout:layout] - avatarSize.width - layout.messageBubbleLeftRightMargin - horizontalInsetsTotal; - - // The full layout width, less the textView margins from xib. -// CGFloat horizontalInsetsTotal = 12.0; cropped 3rd line - CGFloat horizontalInsetsTotal = 50.0; - CGFloat maximumTextWidth = [self textBubbleWidthForLayout:layout] - horizontalInsetsTotal; - - CGRect stringRect = [[messageData text] - boundingRectWithSize:CGSizeMake(maximumTextWidth, CGFLOAT_MAX) - options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) - attributes:@{ - NSFontAttributeName : [UIFont ows_dynamicTypeBodyFont] - } // Hack to use a slightly larger than actual font, because I'm seeing messages with higher line count get clipped. - context:nil]; - // END InfoMessage sizing HACK - //////////////////// - - CGSize stringSize = CGRectIntegral(stringRect).size; - - CGFloat verticalContainerInsets = layout.messageBubbleTextViewTextContainerInsets.top - + layout.messageBubbleTextViewTextContainerInsets.bottom; - - CGFloat verticalFrameInsets - = layout.messageBubbleTextViewFrameInsets.top + layout.messageBubbleTextViewFrameInsets.bottom; - /////////////////// - // BEGIN InfoMessage sizing HACK - - CGFloat topIconPortrusion = 28; - - verticalFrameInsets += topIconPortrusion; - - // END InfoMessage sizing HACK - /////////////////// - - // add extra 2 points of space (`self.additionalInset`), because `boundingRectWithSize:` is slightly off - // not sure why. magix. (shrug) if you know, submit a PR - CGFloat verticalInsets = verticalContainerInsets + verticalFrameInsets + self.additionalInset; - - // same as above, an extra 2 points of magix - CGFloat finalWidth - = MAX(stringSize.width + horizontalInsetsTotal, self.minimumBubbleWidth) + self.additionalInset; - - finalSize = CGSizeMake(finalWidth, stringSize.height + verticalInsets); - } - - [self.cache setObject:[NSValue valueWithCGSize:finalSize] forKey:cacheKey]; - - return finalSize; -} - -- (CGSize)messageBubbleSizeForCallData:(id)messageData - atIndexPath:(NSIndexPath *)indexPath - withLayout:(JSQMessagesCollectionViewFlowLayout *)layout -{ - id cacheKey = [self cacheKeyForMessageData:messageData]; - - NSValue *cachedSize = [self.cache objectForKey:cacheKey]; - if (cachedSize != nil) { - return [cachedSize CGSizeValue]; - } - - CGFloat horizontalInsetsTotal = 0.0; - CGFloat maximumTextWidth = [self textBubbleWidthForLayout:layout] - horizontalInsetsTotal; - - CGRect stringRect = [[messageData text] - boundingRectWithSize:CGSizeMake(maximumTextWidth, CGFLOAT_MAX) - options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) - attributes:@{ - NSFontAttributeName : [UIFont ows_dynamicTypeBodyFont] - } // Hack to use a slightly larger than actual font, because I'm seeing messages with higher line - // count get clipped. - context:nil]; - - CGSize stringSize = CGRectIntegral(stringRect).size; - - CGFloat verticalInsets = 0; - CGFloat finalWidth = maximumTextWidth + horizontalInsetsTotal; - - CGSize finalSize = CGSizeMake(finalWidth, stringSize.height + verticalInsets); - - [self.cache setObject:[NSValue valueWithCGSize:finalSize] forKey:cacheKey]; - - return finalSize; -} - - (id)cacheKeyForMessageData:(id)messageData { OWSAssert(messageData); diff --git a/Signal/src/ViewControllers/ConversationView/MessagesViewController.m b/Signal/src/ViewControllers/ConversationView/MessagesViewController.m index 54d6beb8e..fe28c5c71 100644 --- a/Signal/src/ViewControllers/ConversationView/MessagesViewController.m +++ b/Signal/src/ViewControllers/ConversationView/MessagesViewController.m @@ -1460,16 +1460,18 @@ typedef enum : NSUInteger { JSQMessagesCollectionViewCell *cell; switch (message.messageType) { case TSCallAdapter: { - OWSCall *call = (OWSCall *)message; - cell = [self loadCallCellForCall:call atIndexPath:indexPath]; + // OWSCall *call = (OWSCall *)message; + // cell = [self loadCallCellForCall:call atIndexPath:indexPath]; + cell = [self loadSystemMessageCell:indexPath interaction:message.interaction]; break; } case TSInfoMessageAdapter: { - cell = [self loadInfoMessageCellForMessage:(TSMessageAdapter *)message atIndexPath:indexPath]; + // TODO: There's more work to here. + cell = [self loadSystemMessageCell:indexPath interaction:message.interaction]; break; } case TSErrorMessageAdapter: { - cell = [self loadErrorMessageCell:indexPath interaction:message.interaction]; + cell = [self loadSystemMessageCell:indexPath interaction:message.interaction]; break; } case TSIncomingMessageAdapter: { @@ -1573,38 +1575,38 @@ typedef enum : NSUInteger { 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.textView.text = nil; - callCell.textView.attributedText = attributedText; - - callCell.textView.textAlignment = NSTextAlignmentCenter; - callCell.textView.textColor = [UIColor ows_materialBlueColor]; - callCell.layer.shouldRasterize = YES; - callCell.layer.rasterizationScale = [UIScreen mainScreen].scale; - - // Disable text selectability. Specifying this in prepareForReuse/awakeFromNib was not sufficient. - callCell.textView.userInteractionEnabled = NO; - callCell.textView.selectable = NO; - - return callCell; -} +//- (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.textView.text = nil; +// callCell.textView.attributedText = attributedText; +// +// callCell.textView.textAlignment = NSTextAlignmentCenter; +// callCell.textView.textColor = [UIColor ows_materialBlueColor]; +// callCell.layer.shouldRasterize = YES; +// callCell.layer.rasterizationScale = [UIScreen mainScreen].scale; +// +// // Disable text selectability. Specifying this in prepareForReuse/awakeFromNib was not sufficient. +// callCell.textView.userInteractionEnabled = NO; +// callCell.textView.selectable = NO; +// +// return callCell; +//} - (OWSDisplayedMessageCollectionViewCell *)loadDisplayedMessageCollectionViewCellForIndexPath:(NSIndexPath *)indexPath { @@ -1620,38 +1622,70 @@ typedef enum : NSUInteger { return messageCell; } -- (OWSDisplayedMessageCollectionViewCell *)loadInfoMessageCellForMessage:(TSMessageAdapter *)infoMessage - atIndexPath:(NSIndexPath *)indexPath -{ - OWSDisplayedMessageCollectionViewCell *infoCell = - [self loadDisplayedMessageCollectionViewCellForIndexPath:indexPath]; - - // HACK this will get called when we get a new info message, but there's gotta be a better spot for this. - OWSDisappearingMessagesConfiguration *configuration = - [OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:self.thread.uniqueId]; - [self setBarButtonItemsForDisappearingMessagesConfiguration:configuration]; - - infoCell.textView.text = [infoMessage text]; - - // Disable text selectability. Specifying this in prepareForReuse/awakeFromNib was not sufficient. - infoCell.textView.userInteractionEnabled = NO; - infoCell.textView.selectable = NO; - - infoCell.messageBubbleContainerView.layer.borderColor = [[UIColor ows_infoMessageBorderColor] CGColor]; - if (infoMessage.infoMessageType == TSInfoMessageTypeDisappearingMessagesUpdate) { - infoCell.headerImageView.image = [UIImage imageNamed:@"ic_timer"]; - infoCell.headerImageView.backgroundColor = [UIColor whiteColor]; - // Lighten up the broad stroke header icon to match the perceived color of the border. - infoCell.headerImageView.tintColor = [UIColor ows_infoMessageBorderColor]; - } else { - infoCell.headerImageView.image = [UIImage imageNamed:@"warning_white"]; - } - - - return infoCell; -} - -- (OWSSystemMessageCell *)loadErrorMessageCell:(NSIndexPath *)indexPath interaction:(TSInteraction *)interaction +//- (OWSDisplayedMessageCollectionViewCell *)loadInfoMessageCellForMessage:(TSMessageAdapter *)infoMessage +// atIndexPath:(NSIndexPath *)indexPath +//{ +// OWSDisplayedMessageCollectionViewCell *infoCell = +// [self loadDisplayedMessageCollectionViewCellForIndexPath:indexPath]; +// +// // HACK this will get called when we get a new info message, but there's gotta be a better spot for this. +// OWSDisappearingMessagesConfiguration *configuration = +// [OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:self.thread.uniqueId]; +// [self setBarButtonItemsForDisappearingMessagesConfiguration:configuration]; +// +// infoCell.textView.text = [infoMessage text]; +// +// // Disable text selectability. Specifying this in prepareForReuse/awakeFromNib was not sufficient. +// infoCell.textView.userInteractionEnabled = NO; +// infoCell.textView.selectable = NO; +// +// infoCell.messageBubbleContainerView.layer.borderColor = [[UIColor ows_infoMessageBorderColor] CGColor]; +// if (infoMessage.infoMessageType == TSInfoMessageTypeDisappearingMessagesUpdate) { +// infoCell.headerImageView.image = [UIImage imageNamed:@"ic_timer"]; +// infoCell.headerImageView.backgroundColor = [UIColor whiteColor]; +// // Lighten up the broad stroke header icon to match the perceived color of the border. +// infoCell.headerImageView.tintColor = [UIColor ows_infoMessageBorderColor]; +// } else { +// infoCell.headerImageView.image = [UIImage imageNamed:@"warning_white"]; +// } +// +// +// return infoCell; +//} + +//- (OWSSystemMessageCell *)loadErrorMessageCell:(NSIndexPath *)indexPath interaction:(TSInteraction *)interaction +//// ForMessage:(TSMessageAdapter *)errorMessage +//// atIndexPath:(NSIndexPath *)indexPath +//{ +// OWSAssert(indexPath); +// OWSAssert(interaction); +// // OWSAssert([interaction isKindOfClass:[TSUnreadIndicatorInteraction class]]); +// +// // TSUnreadIndicatorInteraction *unreadIndicator = (TSUnreadIndicatorInteraction *)interaction; +// +// OWSSystemMessageCell *cell = +// [self.collectionView dequeueReusableCellWithReuseIdentifier:[OWSSystemMessageCell cellReuseIdentifier] +// forIndexPath:indexPath]; +// cell.interaction = interaction; +// [cell configure]; +// +// return cell; +// +// // OWSDisplayedMessageCollectionViewCell *errorCell = +// // [self loadDisplayedMessageCollectionViewCellForIndexPath:indexPath]; +// // errorCell.textView.text = [errorMessage text]; +// // +// // // Disable text selectability. Specifying this in prepareForReuse/awakeFromNib was not sufficient. +// // errorCell.textView.userInteractionEnabled = NO; +// // errorCell.textView.selectable = NO; +// // +// // errorCell.messageBubbleContainerView.layer.borderColor = [[UIColor ows_errorMessageBorderColor] CGColor]; +// // errorCell.headerImageView.image = [UIImage imageNamed:@"error_white"]; +// // +// // return errorCell; +//} + +- (OWSSystemMessageCell *)loadSystemMessageCell:(NSIndexPath *)indexPath interaction:(TSInteraction *)interaction // ForMessage:(TSMessageAdapter *)errorMessage // atIndexPath:(NSIndexPath *)indexPath { @@ -3930,7 +3964,8 @@ typedef enum : NSUInteger { // TODO: TSInteraction *interaction = [self interactionAtIndexPath:indexPath]; return ([interaction isKindOfClass:[TSUnreadIndicatorInteraction class]] || - [interaction isKindOfClass:[TSErrorMessage class]]); + [interaction isKindOfClass:[TSInfoMessage class]] || [interaction isKindOfClass:[TSErrorMessage class]] || + [interaction isKindOfClass:[TSCall class]]); } #pragma mark - Class methods diff --git a/Signal/src/ViewControllers/SignalsViewController.m b/Signal/src/ViewControllers/SignalsViewController.m index ac4a23fc6..ef90c011a 100644 --- a/Signal/src/ViewControllers/SignalsViewController.m +++ b/Signal/src/ViewControllers/SignalsViewController.m @@ -202,6 +202,10 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS object:nil]; [self updateBarButtonItems]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self tableView:self.tableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; + }); } - (void)updateBarButtonItems { diff --git a/Signal/src/environment/NotificationsManager.m b/Signal/src/environment/NotificationsManager.m index 2e72eadbc..7d009d9cf 100644 --- a/Signal/src/environment/NotificationsManager.m +++ b/Signal/src/environment/NotificationsManager.m @@ -21,6 +21,8 @@ @property (nonatomic) SystemSoundID newMessageSound; @property (nonatomic, readonly) NSMutableDictionary *currentNotifications; @property (nonatomic, readonly) NotificationType notificationPreviewType; +//@property (nonatomic, readonly) NSMutableArray *recentErrorTimestamps; +//@property (nonatomic, readonly) NSMutableArray *recentIncomingMessageTimestamps; @end @@ -36,6 +38,8 @@ } _currentNotifications = [NSMutableDictionary new]; + // _recentErrorTimestamps = [NSMutableArray new]; + // _recentIncomingMessageTimestamps = [NSMutableArray new]; NSURL *newMessageURL = [[NSBundle mainBundle] URLForResource:@"NewMessage" withExtension:@"aifc"]; AudioServicesCreateSystemSoundID((__bridge CFURLRef)newMessageURL, &_newMessageSound); @@ -258,6 +262,18 @@ } } +//- (BOOL)addNotificationTimestamp:(NSMutableArray *)timestamps +//{ +// OWSAssert(timestamps); +// +// [timestamps addObject:[NSDate date]]; +// +// // Cull old timestamps. +// const CGFloat kThrottlingDuration = 5.f; +//} +//_recentErrorTimestamps = [NSMutableArray new]; +//_recentIncomingMessageTimestamps = [NSMutableArray new]; + #pragma mark - Util - (NotificationType)notificationPreviewType diff --git a/Signal/src/views/OWSSystemMessageCell.m b/Signal/src/views/OWSSystemMessageCell.m index 5163aca2a..052d0cffa 100644 --- a/Signal/src/views/OWSSystemMessageCell.m +++ b/Signal/src/views/OWSSystemMessageCell.m @@ -9,7 +9,9 @@ #import "UIFont+OWS.h" #import "UIView+OWS.h" #import +#import #import +#import @interface OWSSystemMessageCell () @@ -75,7 +77,7 @@ // [self.imageView addRedBorder]; // [self addRedBorder]; - UIColor *contentColor = [UIColor ows_darkGrayColor]; + UIColor *contentColor = [self colorForInteraction:self.interaction]; UIImage *icon = [self iconForInteraction:self.interaction]; self.imageView.image = [icon imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; // self.imageView.tintColor = [UIColor colorWithRGBHex:0x505050]; @@ -84,15 +86,114 @@ self.titleLabel.text = [OWSSystemMessageCell titleForInteraction:self.interaction]; self.titleLabel.textColor = contentColor; + // DDLogError(@"----- %@ %@", + // [self.interaction class], + // self.interaction.description); + [self setNeedsLayout]; + // [self addRedBorder]; +} + +- (UIColor *)colorForInteraction:(TSInteraction *)interaction +{ + // UIImage *result = nil; + + if ([interaction isKindOfClass:[TSErrorMessage class]]) { + switch (((TSErrorMessage *)self.interaction).errorType) { + case TSErrorMessageInvalidKeyException: + return [UIColor ows_yellowColor]; + case TSErrorMessageNonBlockingIdentityChange: + case TSErrorMessageWrongTrustedIdentityKey: + case TSErrorMessageMissingKeyId: + // result = [UIImage imageNamed:@"system_message_security"]; + break; + case TSErrorMessageNoSession: + case TSErrorMessageInvalidMessage: + case TSErrorMessageDuplicateMessage: + case TSErrorMessageInvalidVersion: + case TSErrorMessageUnknownContactBlockOffer: + // result = [UIImage imageNamed:@"system_message_warning"]; + break; + } + } else if ([interaction isKindOfClass:[TSInfoMessage class]]) { + switch (((TSInfoMessage *)self.interaction).messageType) { + case TSInfoMessageUserNotRegistered: + // result = [UIImage imageNamed:@"system_message_warning"]; + break; + case TSInfoMessageTypeSessionDidEnd: + case TSInfoMessageTypeUnsupportedMessage: + case TSInfoMessageAddToContactsOffer: + // result = [UIImage imageNamed:@"system_message_info"]; + break; + case TSInfoMessageTypeGroupUpdate: + case TSInfoMessageTypeGroupQuit: + // TODO: + // result = [UIImage imageNamed:@"system_message_info"]; + break; + case TSInfoMessageTypeDisappearingMessagesUpdate: + // result = [UIImage imageNamed:@"system_message_timer"]; + break; + } + } else if ([interaction isKindOfClass:[TSCall class]]) { + // TODO: + // result = [UIImage imageNamed:@"system_message_call"]; + } else { + OWSFail(@"Unknown interaction type"); + return nil; + } + // return [UIColor ows_darkGrayColor]; + return [UIColor colorWithRGBHex:0x505050]; } - (UIImage *)iconForInteraction:(TSInteraction *)interaction { UIImage *result = nil; + if ([interaction isKindOfClass:[TSErrorMessage class]]) { + // DDLogError(@"----- %@ %@: %d", + // [self.interaction class], + // self.interaction.description, + // (int) ((TSErrorMessage *) self.interaction).errorType); + switch (((TSErrorMessage *)self.interaction).errorType) { + case TSErrorMessageInvalidKeyException: + case TSErrorMessageNonBlockingIdentityChange: + case TSErrorMessageWrongTrustedIdentityKey: + case TSErrorMessageMissingKeyId: + result = [UIImage imageNamed:@"system_message_security"]; + break; + case TSErrorMessageNoSession: + case TSErrorMessageInvalidMessage: + case TSErrorMessageDuplicateMessage: + case TSErrorMessageInvalidVersion: + case TSErrorMessageUnknownContactBlockOffer: + result = [UIImage imageNamed:@"system_message_warning"]; + break; + } + } else if ([interaction isKindOfClass:[TSInfoMessage class]]) { + // DDLogError(@"----- %@ %@: %d", + // [self.interaction class], + // self.interaction.description, + // (int) ((TSInfoMessage *) self.interaction).messageType); + switch (((TSInfoMessage *)self.interaction).messageType) { + case TSInfoMessageUserNotRegistered: + result = [UIImage imageNamed:@"system_message_warning"]; + break; + case TSInfoMessageTypeSessionDidEnd: + case TSInfoMessageTypeUnsupportedMessage: + case TSInfoMessageAddToContactsOffer: + result = [UIImage imageNamed:@"system_message_info"]; + break; + case TSInfoMessageTypeGroupUpdate: + case TSInfoMessageTypeGroupQuit: + result = [UIImage imageNamed:@"system_message_group"]; + break; + case TSInfoMessageTypeDisappearingMessagesUpdate: + result = [UIImage imageNamed:@"system_message_timer"]; + break; + } + } else if ([interaction isKindOfClass:[TSCall class]]) { // TODO: - result = [UIImage imageNamed:@"system_message_security"]; + result = [UIImage imageNamed:@"system_message_call"]; } else { OWSFail(@"Unknown interaction type"); return nil; @@ -109,6 +210,20 @@ if ([interaction isKindOfClass:[TSErrorMessage class]]) { // TODO: Should we move the copy generation into this view? return interaction.description; + } else if ([interaction isKindOfClass:[TSInfoMessage class]]) { + // TODO: Should we move the copy generation into this view? + return interaction.description; + } else if ([interaction isKindOfClass:[TSCall class]]) { + // switch (((TSCall *) self.interaction).callType) { + // case <#constant#>: + // <#statements#> + // break; + // + // default: + // break; + // } + // TODO: Should we move the copy generation into this view? + return interaction.description; } else { OWSFail(@"Unknown interaction type"); return nil; @@ -123,51 +238,6 @@ return [UIFont ows_regularFontWithSize:13.f]; } -//+ (UIFont *)subtitleFont -//{ -// return [UIFont ows_regularFontWithSize:12.f]; -//} - -//+ (NSString *)subtitleForInteraction:(TSUnreadIndicatorInteraction *)interaction -//{ -// if (!interaction.hasMoreUnseenMessages) { -// return nil; -// } -// NSString *subtitleFormat = (interaction.missingUnseenSafetyNumberChangeCount > 0 -// ? NSLocalizedString(@"MESSAGES_VIEW_UNREAD_INDICATOR_HAS_MORE_UNSEEN_MESSAGES_FORMAT", -// @"Messages that indicates that there are more unseen messages that be revealed by tapping the 'load -// " -// @"earlier messages' button. Embeds {{the name of the 'load earlier messages' button}}") -// : NSLocalizedString( -// @"MESSAGES_VIEW_UNREAD_INDICATOR_HAS_MORE_UNSEEN_MESSAGES_AND_SAFETY_NUMBER_CHANGES_FORMAT", -// @"Messages that indicates that there are more unseen messages including safety number changes that " -// @"be revealed by tapping the 'load earlier messages' button. Embeds {{the name of the 'load earlier -// " -// @"messages' button}}.")); -// NSString *loadMoreButtonName = [NSBundle jsq_localizedStringForKey:@"load_earlier_messages"]; -// return [NSString stringWithFormat:subtitleFormat, loadMoreButtonName]; -//} - -//+ (CGFloat)subtitleHMargin -//{ -// return 20.f; -//} -// -//+ (CGFloat)subtitleVSpacing -//{ -// return 3.f; -//} -// -//+ (CGFloat)titleInnerHMargin -//{ -// return 10.f; -//} -// -//+ (CGFloat)titleVMargin -//{ -// return 5.5f; -//} - + (CGFloat)hMargin { return 30.f; @@ -185,52 +255,21 @@ + (CGFloat)hSpacing { - return 10.f; + return 8.f; } + (CGFloat)iconSize { - return 30.f; + return 25.f; } - (void)layoutSubviews { [super layoutSubviews]; - // [self.titleLabel sizeToFit]; - // - // // It's a bit of a hack, but we use a view that extends _outside_ the cell's bounds - // // to draw its background, since we want the background to extend to the edges of the - // // collection view. - // // - // // This layout logic assumes that the cell insets are symmetrical and can be deduced - // // from the cell frame. - // CGRect bannerViewFrame = CGRectMake(-self.left, - // round(OWSSystemMessageCell.topVMargin), - // round(self.width + self.left * 2.f), - // round(self.titleLabel.height + OWSSystemMessageCell.titleVMargin * 2.f)); - // self.bannerView.frame = [self convertRect:bannerViewFrame toView:self.contentView]; - // - // // The highlights should be 1px (not 1pt), so adapt their thickness to - // // the device resolution. - // CGFloat kHighlightThickness = 1.f / [UIScreen mainScreen].scale; - // self.bannerTopHighlightView.frame = CGRectMake(0, 0, self.bannerView.width, kHighlightThickness); - // self.bannerBottomHighlightView1.frame - // = CGRectMake(0, self.bannerView.height - kHighlightThickness * 2.f, self.bannerView.width, - // kHighlightThickness); - // self.bannerBottomHighlightView2.frame - // = CGRectMake(0, self.bannerView.height - kHighlightThickness * 1.f, self.bannerView.width, - // kHighlightThickness); - // - // [self.titleLabel centerOnSuperview]; - CGFloat maxTitleWidth = (self.contentView.width - ([OWSSystemMessageCell hMargin] * 2.f + [OWSSystemMessageCell hSpacing] + [OWSSystemMessageCell iconSize])); CGSize titleSize = [self.titleLabel sizeThatFits:CGSizeMake(maxTitleWidth, CGFLOAT_MAX)]; - // CGFloat contentWidth = ceil([OWSSystemMessageCell iconSize] + - // [OWSSystemMessageCell hSpacing] + - // titleSize.width); - // self.imageView.frame = CGRectMake(round((self.contentView.width - contentWidth) * 0.5f), self.imageView.frame = CGRectMake(round([OWSSystemMessageCell hMargin]), round((self.contentView.height - [OWSSystemMessageCell iconSize]) * 0.5f), [OWSSystemMessageCell iconSize], @@ -239,30 +278,18 @@ round((self.contentView.height - titleSize.height) * 0.5f), ceil(titleSize.width + 1.f), ceil(titleSize.height + 1.f)); - // [self.titleLabel addRedBorder]; - // if (self.subtitleLabel.text.length > 0) { - // CGSize subtitleSize = [self.subtitleLabel - // sizeThatFits:CGSizeMake( - // self.contentView.width - [OWSSystemMessageCell subtitleHMargin] * 2.f, CGFLOAT_MAX)]; - // self.subtitleLabel.frame = CGRectMake(round((self.contentView.width - subtitleSize.width) * 0.5f), - // round(self.bannerView.bottom + OWSSystemMessageCell.subtitleVSpacing), - // ceil(subtitleSize.width), - // ceil(subtitleSize.height)); - // } } + (CGSize)cellSizeForInteraction:(TSInteraction *)interaction collectionViewWidth:(CGFloat)collectionViewWidth { CGSize result = CGSizeMake(collectionViewWidth, 0); - // result.height += self.titleVMargin * 2.f; result.height += self.topVMargin; result.height += self.bottomVMargin; NSString *title = [self titleForInteraction:interaction]; - // NSString *subtitle = [self subtitleForInteraction:interaction]; // Creating a UILabel to measure the layout is expensive, but it's the only - // reliable way to do it. Unread indicators should be rare, so this is acceptable. + // reliable way to do it. UILabel *label = [UILabel new]; label.font = [self titleFont]; label.text = title; @@ -273,19 +300,6 @@ CGFloat contentHeight = ceil(MAX([self iconSize], titleSize.height)); result.height += contentHeight; - // if (subtitle.length > 0) { - // result.height += self.subtitleVSpacing; - // - // label.font = [self subtitleFont]; - // label.text = subtitle; - // // The subtitle may wrap to a second line. - // label.lineBreakMode = NSLineBreakByWordWrapping; - // label.numberOfLines = 0; - // result.height += ceil( - // [label sizeThatFits:CGSizeMake(collectionViewWidth - self.subtitleHMargin * 2.f, - // CGFLOAT_MAX)].height); - // } - return result; } diff --git a/Signal/src/views/TSUnreadIndicatorInteraction.m b/Signal/src/views/TSUnreadIndicatorInteraction.m index a66919210..75a75a3ba 100644 --- a/Signal/src/views/TSUnreadIndicatorInteraction.m +++ b/Signal/src/views/TSUnreadIndicatorInteraction.m @@ -29,6 +29,13 @@ NS_ASSUME_NONNULL_BEGIN missingUnseenSafetyNumberChangeCount:(NSUInteger)missingUnseenSafetyNumberChangeCount { self = [super initWithTimestamp:timestamp inThread:thread]; + // self = [super initWithTimestamp:timestamp + // inThread:thread + // messageBody:nil + // attachmentIds:@[] + // expiresInSeconds:0 + // expireStartedAt:0]; + // - (instancetype)initWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread; if (!self) { return self;