|
|
|
@ -23,12 +23,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
@property (nonatomic) UILabel *dateTimeLabel;
|
|
|
|
|
@property (nonatomic) MessageStatusView *messageStatusView;
|
|
|
|
|
@property (nonatomic) TypingIndicatorView *typingIndicatorView;
|
|
|
|
|
@property (nonatomic) UIStackView *previewStackView;
|
|
|
|
|
|
|
|
|
|
@property (nonatomic) UIView *unreadBadge;
|
|
|
|
|
@property (nonatomic) UILabel *unreadLabel;
|
|
|
|
|
|
|
|
|
|
@property (nonatomic, nullable) ThreadViewModel *thread;
|
|
|
|
|
@property (nonatomic, nullable) NSAttributedString *overrideSnippet;
|
|
|
|
|
@property (nonatomic) BOOL isBlocked;
|
|
|
|
|
|
|
|
|
|
@property (nonatomic, readonly) NSMutableArray<NSLayoutConstraint *> *viewConstraints;
|
|
|
|
|
|
|
|
|
@ -118,25 +119,19 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
self.snippetLabel.font = [self snippetFont];
|
|
|
|
|
self.snippetLabel.numberOfLines = 1;
|
|
|
|
|
self.snippetLabel.lineBreakMode = NSLineBreakByTruncatingTail;
|
|
|
|
|
[self.snippetLabel setContentHuggingHorizontalLow];
|
|
|
|
|
[self.snippetLabel setCompressionResistanceHorizontalLow];
|
|
|
|
|
|
|
|
|
|
self.typingIndicatorView = [TypingIndicatorView new];
|
|
|
|
|
|
|
|
|
|
self.previewStackView = [[UIStackView alloc] initWithArrangedSubviews:@[
|
|
|
|
|
self.snippetLabel,
|
|
|
|
|
self.typingIndicatorView,
|
|
|
|
|
]];
|
|
|
|
|
self.previewStackView.axis = UILayoutConstraintAxisVertical;
|
|
|
|
|
self.previewStackView.alignment = UIStackViewAlignmentLeading;
|
|
|
|
|
[self.previewStackView setContentHuggingHorizontalLow];
|
|
|
|
|
[self.previewStackView setCompressionResistanceHorizontalLow];
|
|
|
|
|
[self.contentView addSubview:self.typingIndicatorView];
|
|
|
|
|
|
|
|
|
|
UIStackView *bottomRowView = [[UIStackView alloc] initWithArrangedSubviews:@[
|
|
|
|
|
self.previewStackView,
|
|
|
|
|
self.snippetLabel,
|
|
|
|
|
self.messageStatusView,
|
|
|
|
|
]];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bottomRowView.axis = UILayoutConstraintAxisHorizontal;
|
|
|
|
|
bottomRowView.alignment = UIStackViewAlignmentCenter;
|
|
|
|
|
bottomRowView.alignment = UIStackViewAlignmentLastBaseline;
|
|
|
|
|
bottomRowView.spacing = 6.f;
|
|
|
|
|
|
|
|
|
|
UIStackView *vStackView = [[UIStackView alloc] initWithArrangedSubviews:@[
|
|
|
|
@ -171,6 +166,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
|
|
|
|
|
[self.contentView addSubview:self.unreadBadge];
|
|
|
|
|
[self.unreadBadge autoAlignAxis:ALAxisHorizontal toSameAxisOfView:self.nameLabel];
|
|
|
|
|
|
|
|
|
|
[self.typingIndicatorView autoPinEdge:ALEdgeLeading toEdge:ALEdgeLeading ofView:self.snippetLabel];
|
|
|
|
|
[self.typingIndicatorView autoAlignAxis:ALAxisHorizontal toSameAxisOfView:self.snippetLabel];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)dealloc
|
|
|
|
@ -213,6 +211,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
[OWSTableItem configureCell:self];
|
|
|
|
|
|
|
|
|
|
self.thread = thread;
|
|
|
|
|
self.overrideSnippet = overrideSnippet;
|
|
|
|
|
self.isBlocked = isBlocked;
|
|
|
|
|
|
|
|
|
|
BOOL hasUnreadMessages = thread.hasUnreadMessages;
|
|
|
|
|
|
|
|
|
@ -231,18 +231,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
// changes to the dynamic type settings are reflected.
|
|
|
|
|
self.snippetLabel.font = [self snippetFont];
|
|
|
|
|
|
|
|
|
|
if (overrideSnippet) {
|
|
|
|
|
self.snippetLabel.attributedText = overrideSnippet;
|
|
|
|
|
} else {
|
|
|
|
|
self.snippetLabel.attributedText = [self attributedSnippetForThread:thread isBlocked:isBlocked];
|
|
|
|
|
}
|
|
|
|
|
[self updatePreview];
|
|
|
|
|
CGFloat previewHeight = MAX(self.snippetLabel.font.lineHeight,
|
|
|
|
|
TypingIndicatorView.kMaxRadiusPt);
|
|
|
|
|
[self.viewConstraints addObjectsFromArray:@[
|
|
|
|
|
[self.previewStackView autoSetDimension:ALDimensionHeight
|
|
|
|
|
toSize:previewHeight],
|
|
|
|
|
]];
|
|
|
|
|
|
|
|
|
|
self.dateTimeLabel.text
|
|
|
|
|
= (overrideDate ? [self stringForDate:overrideDate] : [self stringForDate:thread.lastMessageDate]);
|
|
|
|
|
|
|
|
|
@ -469,6 +459,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
[self.viewConstraints removeAllObjects];
|
|
|
|
|
|
|
|
|
|
self.thread = nil;
|
|
|
|
|
self.overrideSnippet = nil;
|
|
|
|
|
self.avatarView.image = nil;
|
|
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
|
|
@ -532,11 +523,20 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
- (void)updatePreview
|
|
|
|
|
{
|
|
|
|
|
if ([self.typingIndicators typingRecipientIdForThread:self.thread.threadRecord] != nil) {
|
|
|
|
|
self.snippetLabel.hidden = YES;
|
|
|
|
|
// If we hide snippetLabel, our layout will break since UIStackView will remove
|
|
|
|
|
// it from the layout. Wrapping the preview views (the snippet label and the
|
|
|
|
|
// typing indicator) in a UIStackView proved non-trivial since we're using
|
|
|
|
|
// UIStackViewAlignmentLastBaseline. Therefore we hide the _contents_ of the
|
|
|
|
|
// snippet label using an empty string.
|
|
|
|
|
self.snippetLabel.text = @" ";
|
|
|
|
|
self.typingIndicatorView.hidden = NO;
|
|
|
|
|
[self.typingIndicatorView startAnimation];
|
|
|
|
|
} else {
|
|
|
|
|
self.snippetLabel.hidden = NO;
|
|
|
|
|
if (self.overrideSnippet) {
|
|
|
|
|
self.snippetLabel.attributedText = self.overrideSnippet;
|
|
|
|
|
} else {
|
|
|
|
|
self.snippetLabel.attributedText = [self attributedSnippetForThread:self.thread isBlocked:self.isBlocked];
|
|
|
|
|
}
|
|
|
|
|
self.typingIndicatorView.hidden = YES;
|
|
|
|
|
[self.typingIndicatorView stopAnimation];
|
|
|
|
|
}
|
|
|
|
|