diff --git a/Signal/src/ViewControllers/ConversationView/Cells/ConversationViewCell.h b/Signal/src/ViewControllers/ConversationView/Cells/ConversationViewCell.h index 64c5d4ecd..84ad462c1 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/ConversationViewCell.h +++ b/Signal/src/ViewControllers/ConversationView/Cells/ConversationViewCell.h @@ -18,7 +18,6 @@ NS_ASSUME_NONNULL_BEGIN @class TSMessage; @class TSOutgoingMessage; @class TSQuotedMessage; -@class YapDatabaseReadTransaction; @protocol ConversationViewCellDelegate @@ -85,9 +84,9 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, nullable) ConversationStyle *conversationStyle; -- (void)loadForDisplayWithTransaction:(YapDatabaseReadTransaction *)transaction; +- (void)loadForDisplay; -- (CGSize)cellSizeWithTransaction:(YapDatabaseReadTransaction *)transaction; +- (CGSize)cellSize; @end diff --git a/Signal/src/ViewControllers/ConversationView/Cells/ConversationViewCell.m b/Signal/src/ViewControllers/ConversationView/Cells/ConversationViewCell.m index 0737f4feb..b49e302b5 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/ConversationViewCell.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/ConversationViewCell.m @@ -19,12 +19,12 @@ NS_ASSUME_NONNULL_BEGIN self.conversationStyle = nil; } -- (void)loadForDisplayWithTransaction:(YapDatabaseReadTransaction *)transaction +- (void)loadForDisplay { OWS_ABSTRACT_METHOD(); } -- (CGSize)cellSizeWithTransaction:(YapDatabaseReadTransaction *)transaction +- (CGSize)cellSize { OWS_ABSTRACT_METHOD(); diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSContactOffersCell.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSContactOffersCell.m index f66679fe8..ed32df9ba 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSContactOffersCell.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSContactOffersCell.m @@ -108,7 +108,7 @@ NS_ASSUME_NONNULL_BEGIN return NSStringFromClass([self class]); } -- (void)loadForDisplayWithTransaction:(YapDatabaseReadTransaction *)transaction +- (void)loadForDisplay { OWSAssert(self.conversationStyle); OWSAssert(self.conversationStyle.viewWidth > 0); @@ -173,7 +173,7 @@ NS_ASSUME_NONNULL_BEGIN return (24.f + self.addToContactsButton.titleLabel.font.lineHeight); } -- (CGSize)cellSizeWithTransaction:(YapDatabaseReadTransaction *)transaction +- (CGSize)cellSize { OWSAssert(self.conversationStyle); OWSAssert(self.conversationStyle.viewWidth > 0); diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m index fe158bf3c..6a651f944 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m @@ -124,7 +124,7 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Load -- (void)loadForDisplayWithTransaction:(YapDatabaseReadTransaction *)transaction +- (void)loadForDisplay { OWSAssert(self.conversationStyle); OWSAssert(self.viewItem); @@ -320,7 +320,7 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Measurement -- (CGSize)cellSizeWithTransaction:(YapDatabaseReadTransaction *)transaction +- (CGSize)cellSize { OWSAssert(self.conversationStyle); OWSAssert(self.conversationStyle.viewWidth > 0); diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSSystemMessageCell.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSSystemMessageCell.m index 45e8bfa10..8bfaee5a8 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSSystemMessageCell.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSSystemMessageCell.m @@ -161,11 +161,10 @@ typedef void (^SystemMessageActionBlock)(void); return NSStringFromClass([self class]); } -- (void)loadForDisplayWithTransaction:(YapDatabaseReadTransaction *)transaction +- (void)loadForDisplay { OWSAssert(self.conversationStyle); OWSAssert(self.viewItem); - OWSAssert(transaction); self.cellBackgroundView.backgroundColor = [Theme backgroundColor]; @@ -185,7 +184,7 @@ typedef void (^SystemMessageActionBlock)(void); } self.titleLabel.textColor = [self textColor]; - [self applyTitleForInteraction:interaction label:self.titleLabel transaction:transaction]; + [self applyTitleForInteraction:interaction label:self.titleLabel]; CGSize titleSize = [self titleSize]; if (self.action) { @@ -312,52 +311,14 @@ typedef void (^SystemMessageActionBlock)(void); - (void)applyTitleForInteraction:(TSInteraction *)interaction label:(UILabel *)label - transaction:(YapDatabaseReadTransaction *)transaction { OWSAssert(interaction); OWSAssert(label); - OWSAssert(transaction); + OWSAssert(self.viewItem.systemMessageText.length > 0); [self configureFonts]; - // TODO: Should we move the copy generation into this view? - - if ([interaction isKindOfClass:[TSErrorMessage class]]) { - TSErrorMessage *errorMessage = (TSErrorMessage *)interaction; - label.text = [errorMessage previewTextWithTransaction:transaction]; - } else if ([interaction isKindOfClass:[TSInfoMessage class]]) { - TSInfoMessage *infoMessage = (TSInfoMessage *)interaction; - if ([infoMessage isKindOfClass:[OWSVerificationStateChangeMessage class]]) { - OWSVerificationStateChangeMessage *verificationMessage = (OWSVerificationStateChangeMessage *)infoMessage; - BOOL isVerified = verificationMessage.verificationState == OWSVerificationStateVerified; - NSString *displayName = - [[Environment current].contactsManager displayNameForPhoneIdentifier:verificationMessage.recipientId]; - NSString *titleFormat = (isVerified - ? (verificationMessage.isLocalChange - ? NSLocalizedString(@"VERIFICATION_STATE_CHANGE_FORMAT_VERIFIED_LOCAL", - @"Format for info message indicating that the verification state was verified on " - @"this device. Embeds {{user's name or phone number}}.") - : NSLocalizedString(@"VERIFICATION_STATE_CHANGE_FORMAT_VERIFIED_OTHER_DEVICE", - @"Format for info message indicating that the verification state was verified on " - @"another device. Embeds {{user's name or phone number}}.")) - : (verificationMessage.isLocalChange - ? NSLocalizedString(@"VERIFICATION_STATE_CHANGE_FORMAT_NOT_VERIFIED_LOCAL", - @"Format for info message indicating that the verification state was unverified on " - @"this device. Embeds {{user's name or phone number}}.") - : NSLocalizedString(@"VERIFICATION_STATE_CHANGE_FORMAT_NOT_VERIFIED_OTHER_DEVICE", - @"Format for info message indicating that the verification state was unverified on " - @"another device. Embeds {{user's name or phone number}}."))); - label.text = [NSString stringWithFormat:titleFormat, displayName]; - } else { - label.text = [infoMessage previewTextWithTransaction:transaction]; - } - } else if ([interaction isKindOfClass:[TSCall class]]) { - TSCall *call = (TSCall *)interaction; - label.text = [call previewTextWithTransaction:transaction]; - } else { - OWSFail(@"Unknown interaction type: %@", [interaction class]); - label.text = nil; - } + label.text = self.viewItem.systemMessageText; } - (CGFloat)topVMargin @@ -389,7 +350,7 @@ typedef void (^SystemMessageActionBlock)(void); return [self.titleLabel sizeThatFits:CGSizeMake(maxTitleWidth, CGFLOAT_MAX)]; } -- (CGSize)cellSizeWithTransaction:(YapDatabaseReadTransaction *)transaction +- (CGSize)cellSize { OWSAssert(self.conversationStyle); OWSAssert(self.viewItem); @@ -409,7 +370,7 @@ typedef void (^SystemMessageActionBlock)(void); result.height += self.iconSize + self.iconVSpacing; } - [self applyTitleForInteraction:interaction label:self.titleLabel transaction:transaction]; + [self applyTitleForInteraction:interaction label:self.titleLabel]; CGSize titleSize = [self titleSize]; result.height += titleSize.height; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 8d0be3f44..425d7105e 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -569,8 +569,7 @@ typedef enum : NSUInteger { { OWSAssert(self.conversationStyle); - _layout = [[ConversationViewLayout alloc] initWithConversationStyle:self.conversationStyle - uiDatabaseConnection:self.uiDatabaseConnection]; + _layout = [[ConversationViewLayout alloc] initWithConversationStyle:self.conversationStyle]; self.conversationStyle.viewWidth = self.view.width; self.layout.delegate = self; @@ -5167,9 +5166,7 @@ typedef enum : NSUInteger { } cell.conversationStyle = self.conversationStyle; - [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - [cell loadForDisplayWithTransaction:transaction]; - }]; + [cell loadForDisplay]; return cell; } diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.h b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.h index 46f5bbf81..794d250b6 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.h +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.h @@ -109,6 +109,8 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType); @property (nonatomic, readonly, nullable) ContactShareViewModel *contactShare; +@property (nonatomic, nullable) NSString *systemMessageText; + #pragma mark - MessageActions @property (nonatomic, readonly) BOOL hasBodyTextActionContent; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m index edb6b0fc9..c4d8900d9 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m @@ -113,6 +113,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) self.mediaSize = CGSizeZero; self.displayableQuotedText = nil; self.quotedReply = nil; + self.systemMessageText = nil; [self clearCachedLayoutState]; @@ -215,9 +216,8 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) self.cachedCellSize = nil; } -- (CGSize)cellSizeWithTransaction:(YapDatabaseReadTransaction *)transaction +- (CGSize)cellSize { - OWSAssert(transaction); OWSAssertIsOnMainThread(); OWSAssert(self.conversationStyle); @@ -225,7 +225,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) ConversationViewCell *_Nullable measurementCell = [self measurementCell]; measurementCell.viewItem = self; measurementCell.conversationStyle = self.conversationStyle; - CGSize cellSize = [measurementCell cellSizeWithTransaction:transaction]; + CGSize cellSize = [measurementCell cellSize]; self.cachedCellSize = [NSValue valueWithCGSize:cellSize]; [measurementCell prepareForReuse]; } @@ -438,12 +438,27 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) OWSAssert(transaction); OWSAssert(!self.hasViewState); - if (![self.interaction isKindOfClass:[TSOutgoingMessage class]] - && ![self.interaction isKindOfClass:[TSIncomingMessage class]]) { - // Only text & attachment messages have "view state". - return; + switch (self.interaction.interactionType) { + case OWSInteractionType_Unknown: + case OWSInteractionType_Offer: + return; + case OWSInteractionType_Error: + case OWSInteractionType_Info: + case OWSInteractionType_Call: + self.systemMessageText = [self systemMessageTextWithTransaction:transaction]; + OWSAssert(self.systemMessageText.length > 0); + return; + case OWSInteractionType_IncomingMessage: + case OWSInteractionType_OutgoingMessage: + break; + default: + OWSFail(@"%@ Unknown interaction type.", self.logTag); + return; } + OWSAssert([self.interaction isKindOfClass:[TSOutgoingMessage class]] || + [self.interaction isKindOfClass:[TSIncomingMessage class]]); + self.hasViewState = YES; TSMessage *message = (TSMessage *)self.interaction; @@ -533,6 +548,57 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) } } +- (NSString *)systemMessageTextWithTransaction:(YapDatabaseReadTransaction *)transaction +{ + OWSAssert(transaction); + + switch (self.interaction.interactionType) { + case OWSInteractionType_Error: { + TSErrorMessage *errorMessage = (TSErrorMessage *)self.interaction; + return [errorMessage previewTextWithTransaction:transaction]; + } + case OWSInteractionType_Info: { + TSInfoMessage *infoMessage = (TSInfoMessage *)self.interaction; + if ([infoMessage isKindOfClass:[OWSVerificationStateChangeMessage class]]) { + OWSVerificationStateChangeMessage *verificationMessage + = (OWSVerificationStateChangeMessage *)infoMessage; + BOOL isVerified = verificationMessage.verificationState == OWSVerificationStateVerified; + NSString *displayName = [[Environment current].contactsManager + displayNameForPhoneIdentifier:verificationMessage.recipientId]; + NSString *titleFormat = (isVerified + ? (verificationMessage.isLocalChange + ? NSLocalizedString(@"VERIFICATION_STATE_CHANGE_FORMAT_VERIFIED_LOCAL", + @"Format for info message indicating that the verification state was verified " + @"on " + @"this device. Embeds {{user's name or phone number}}.") + : NSLocalizedString(@"VERIFICATION_STATE_CHANGE_FORMAT_VERIFIED_OTHER_DEVICE", + @"Format for info message indicating that the verification state was verified " + @"on " + @"another device. Embeds {{user's name or phone number}}.")) + : (verificationMessage.isLocalChange + ? NSLocalizedString(@"VERIFICATION_STATE_CHANGE_FORMAT_NOT_VERIFIED_LOCAL", + @"Format for info message indicating that the verification state was " + @"unverified on " + @"this device. Embeds {{user's name or phone number}}.") + : NSLocalizedString(@"VERIFICATION_STATE_CHANGE_FORMAT_NOT_VERIFIED_OTHER_DEVICE", + @"Format for info message indicating that the verification state was " + @"unverified on " + @"another device. Embeds {{user's name or phone number}}."))); + return [NSString stringWithFormat:titleFormat, displayName]; + } else { + return [infoMessage previewTextWithTransaction:transaction]; + } + } + case OWSInteractionType_Call: { + TSCall *call = (TSCall *)self.interaction; + return [call previewTextWithTransaction:transaction]; + } + default: + OWSFail(@"%@ not a system message.", self.logTag); + return nil; + } +} + - (nullable NSString *)quotedAttachmentMimetype { return self.quotedReply.contentType; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewLayout.h b/Signal/src/ViewControllers/ConversationView/ConversationViewLayout.h index ddffd0e57..ac0ed1d4c 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewLayout.h +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewLayout.h @@ -5,12 +5,10 @@ NS_ASSUME_NONNULL_BEGIN @class ConversationStyle; -@class YapDatabaseConnection; -@class YapDatabaseReadTransaction; @protocol ConversationViewLayoutItem -- (CGSize)cellSizeWithTransaction:(YapDatabaseReadTransaction *)transaction; +- (CGSize)cellSize; - (CGFloat)vSpacingWithPreviousLayoutItem:(id)previousLayoutItem; @@ -39,8 +37,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithConversationStyle:(ConversationStyle *)conversationStyle - uiDatabaseConnection:(YapDatabaseConnection *)uiDatabaseConnection; +- (instancetype)initWithConversationStyle:(ConversationStyle *)conversationStyle; @end diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewLayout.m b/Signal/src/ViewControllers/ConversationView/ConversationViewLayout.m index 305b9686b..4e15a6a1b 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewLayout.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewLayout.m @@ -10,8 +10,6 @@ NS_ASSUME_NONNULL_BEGIN @interface ConversationViewLayout () -@property (nonatomic, readonly) YapDatabaseConnection *uiDatabaseConnection; - @property (nonatomic) CGSize contentSize; @property (nonatomic, readonly) NSMutableDictionary *itemAttributesMap; @@ -31,12 +29,10 @@ NS_ASSUME_NONNULL_BEGIN @implementation ConversationViewLayout - (instancetype)initWithConversationStyle:(ConversationStyle *)conversationStyle - uiDatabaseConnection:(YapDatabaseConnection *)uiDatabaseConnection { if (self = [super init]) { _itemAttributesMap = [NSMutableDictionary new]; _conversationStyle = conversationStyle; - _uiDatabaseConnection = uiDatabaseConnection; } return self; @@ -98,15 +94,11 @@ NS_ASSUME_NONNULL_BEGIN // TODO: Remove this log statement after we've reduced the invalidation churn. DDLogVerbose(@"%@ prepareLayout", self.logTag); - [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - [self prepareLayoutWithTransaction:transaction]; - }]; + [self prepareLayoutOfItems]; } -- (void)prepareLayoutWithTransaction:(YapDatabaseReadTransaction *)transaction +- (void)prepareLayoutOfItems { - OWSAssert(transaction); - const CGFloat viewWidth = self.conversationStyle.viewWidth; NSArray> *layoutItems = self.delegate.layoutItems; @@ -121,7 +113,7 @@ NS_ASSUME_NONNULL_BEGIN y += [layoutItem vSpacingWithPreviousLayoutItem:previousLayoutItem]; } - CGSize layoutSize = CGSizeCeil([layoutItem cellSizeWithTransaction:transaction]); + CGSize layoutSize = CGSizeCeil([layoutItem cellSize]); // Ensure cell fits within view. OWSAssert(layoutSize.width <= viewWidth);