diff --git a/Signal/Images.xcassets/message_send_failure.imageset/Contents.json b/Signal/Images.xcassets/message_send_failed.imageset/Contents.json similarity index 64% rename from Signal/Images.xcassets/message_send_failure.imageset/Contents.json rename to Signal/Images.xcassets/message_send_failed.imageset/Contents.json index c1ca74cf9..6bd09fe32 100644 --- a/Signal/Images.xcassets/message_send_failure.imageset/Contents.json +++ b/Signal/Images.xcassets/message_send_failed.imageset/Contents.json @@ -2,17 +2,17 @@ "images" : [ { "idiom" : "universal", - "filename" : "message_send_failure@1x.png", + "filename" : "error-20@1x.png", "scale" : "1x" }, { "idiom" : "universal", - "filename" : "message_send_failure@2x.png", + "filename" : "error-20@2x.png", "scale" : "2x" }, { "idiom" : "universal", - "filename" : "message_send_failure@3x.png", + "filename" : "error-20@3x.png", "scale" : "3x" } ], diff --git a/Signal/Images.xcassets/message_send_failed.imageset/error-20@1x.png b/Signal/Images.xcassets/message_send_failed.imageset/error-20@1x.png new file mode 100644 index 000000000..d385cefad Binary files /dev/null and b/Signal/Images.xcassets/message_send_failed.imageset/error-20@1x.png differ diff --git a/Signal/Images.xcassets/message_send_failed.imageset/error-20@2x.png b/Signal/Images.xcassets/message_send_failed.imageset/error-20@2x.png new file mode 100644 index 000000000..391b7f3bc Binary files /dev/null and b/Signal/Images.xcassets/message_send_failed.imageset/error-20@2x.png differ diff --git a/Signal/Images.xcassets/message_send_failed.imageset/error-20@3x.png b/Signal/Images.xcassets/message_send_failed.imageset/error-20@3x.png new file mode 100644 index 000000000..35a740157 Binary files /dev/null and b/Signal/Images.xcassets/message_send_failed.imageset/error-20@3x.png differ 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 deleted file mode 100644 index faa7e18f0..000000000 Binary files a/Signal/Images.xcassets/message_send_failure.imageset/message_send_failure@1x.png and /dev/null differ 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 deleted file mode 100644 index 1e540f14b..000000000 Binary files a/Signal/Images.xcassets/message_send_failure.imageset/message_send_failure@2x.png and /dev/null differ 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 deleted file mode 100644 index 141311227..000000000 Binary files a/Signal/Images.xcassets/message_send_failure.imageset/message_send_failure@3x.png and /dev/null differ diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m index b6e43c341..9f0ced321 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m @@ -20,12 +20,15 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) UIView *dateStrokeView; @property (nonatomic) UILabel *dateHeaderLabel; @property (nonatomic) AvatarImageView *avatarView; +@property (nonatomic, nullable) UIImageView *sendFailureBadgeView; @property (nonatomic, nullable) NSMutableArray *viewConstraints; @property (nonatomic) BOOL isPresentingMenuController; @end +#pragma mark - + @implementation OWSMessageCell // `[UIView init]` invokes `[self initWithFrame:...]`. @@ -131,6 +134,15 @@ NS_ASSUME_NONNULL_BEGIN return self.viewItem.interaction.interactionType == OWSInteractionType_OutgoingMessage; } +- (BOOL)shouldHavesendFailureBadge +{ + if (![self.viewItem.interaction isKindOfClass:[TSOutgoingMessage class]]) { + return NO; + } + TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)self.viewItem.interaction; + return outgoingMessage.messageState == TSOutgoingMessageStateFailed; +} + #pragma mark - Load - (void)loadForDisplayWithTransaction:(YapDatabaseReadTransaction *)transaction @@ -158,13 +170,42 @@ NS_ASSUME_NONNULL_BEGIN relation:NSLayoutRelationGreaterThanOrEqual], ]]; } else { - [self.viewConstraints addObjectsFromArray:@[ - [self.messageBubbleView autoPinEdgeToSuperviewEdge:ALEdgeLeading - withInset:self.conversationStyle.gutterLeading - relation:NSLayoutRelationGreaterThanOrEqual], - [self.messageBubbleView autoPinEdgeToSuperviewEdge:ALEdgeTrailing - withInset:self.conversationStyle.gutterTrailing], - ]]; + if (self.shouldHavesendFailureBadge) { + self.sendFailureBadgeView = [UIImageView new]; + self.sendFailureBadgeView.image = + [self.sendFailureBadge imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + self.sendFailureBadgeView.tintColor = [UIColor ows_destructiveRedColor]; + [self.contentView addSubview:self.sendFailureBadgeView]; + + CGFloat sendFailureBadgeBottomMargin + = round(self.conversationStyle.lastTextLineAxis - self.sendFailureBadgeSize * 0.5f); + [self.viewConstraints addObjectsFromArray:@[ + [self.messageBubbleView autoPinEdgeToSuperviewEdge:ALEdgeLeading + withInset:self.conversationStyle.gutterLeading + relation:NSLayoutRelationGreaterThanOrEqual], + [self.sendFailureBadgeView autoPinLeadingToTrailingEdgeOfView:self.messageBubbleView + offset:self.sendFailureBadgeSpacing], + // V-align the "send failure" badge with the + // last line of the text (if any, or where it + // would be). + [self.messageBubbleView autoPinEdge:ALEdgeBottom + toEdge:ALEdgeBottom + ofView:self.sendFailureBadgeView + withOffset:sendFailureBadgeBottomMargin], + [self.sendFailureBadgeView autoPinEdgeToSuperviewEdge:ALEdgeTrailing + withInset:self.conversationStyle.gutterTrailing], + [self.sendFailureBadgeView autoSetDimension:ALDimensionWidth toSize:self.sendFailureBadgeSize], + [self.sendFailureBadgeView autoSetDimension:ALDimensionHeight toSize:self.sendFailureBadgeSize], + ]]; + } else { + [self.viewConstraints addObjectsFromArray:@[ + [self.messageBubbleView autoPinEdgeToSuperviewEdge:ALEdgeLeading + withInset:self.conversationStyle.gutterLeading + relation:NSLayoutRelationGreaterThanOrEqual], + [self.messageBubbleView autoPinEdgeToSuperviewEdge:ALEdgeTrailing + withInset:self.conversationStyle.gutterTrailing], + ]]; + } } [self updateDateHeader]; @@ -184,6 +225,24 @@ NS_ASSUME_NONNULL_BEGIN } } +- (UIImage *)sendFailureBadge +{ + UIImage *image = [UIImage imageNamed:@"message_send_failed"]; + OWSAssert(image); + OWSAssert(image.size.width == self.sendFailureBadgeSize && image.size.height == self.sendFailureBadgeSize); + return image; +} + +- (CGFloat)sendFailureBadgeSize +{ + return 20.f; +} + +- (CGFloat)sendFailureBadgeSpacing +{ + return 8.f; +} + // * If cell is visible, lazy-load (expensive) view contents. // * If cell is not visible, eagerly unload view contents. - (void)ensureMediaLoadState @@ -362,6 +421,10 @@ NS_ASSUME_NONNULL_BEGIN cellSize.height += self.dateHeaderHeight; + if (self.shouldHavesendFailureBadge) { + cellSize.width += self.sendFailureBadgeSize + self.sendFailureBadgeSpacing; + } + cellSize = CGSizeCeil(cellSize); return cellSize; @@ -404,6 +467,9 @@ NS_ASSUME_NONNULL_BEGIN self.avatarView.image = nil; [self.avatarView removeFromSuperview]; + [self.sendFailureBadgeView removeFromSuperview]; + self.sendFailureBadgeView = nil; + [self hideMenuControllerIfNecessary]; [[NSNotificationCenter defaultCenter] removeObserver:self]; diff --git a/SignalMessaging/categories/UIColor+OWS.m b/SignalMessaging/categories/UIColor+OWS.m index d8447eb65..4b73dc74b 100644 --- a/SignalMessaging/categories/UIColor+OWS.m +++ b/SignalMessaging/categories/UIColor+OWS.m @@ -79,7 +79,7 @@ NS_ASSUME_NONNULL_BEGIN + (UIColor *)ows_destructiveRedColor { - return [UIColor colorWithRed:0.98639106750488281 green:0.10408364236354828 blue:0.33135244250297546 alpha:1.f]; + return [UIColor colorWithRed:255.f / 255.f green:38.f / 255.f blue:31.f / 255.f alpha:1.0f]; } + (UIColor *)ows_errorMessageBorderColor