Files
fanyin-ios/TUIKit/TIMCommon/BaseCell/TUIMessageCell.m
2025-08-12 14:27:12 +08:00

681 lines
26 KiB
Objective-C

//
// TUIMessageCell.m
// UIKit
//
// Created by kennethmiao on 2018/9/17.
// Copyright © 2018 Tencent. All rights reserved.
//
#import "TUIMessageCell.h"
#import <TIMCommon/TIMDefine.h>
#import <TUICore/TUIThemeManager.h>
#import <TUICore/TUITool.h>
#import "NSString+TUIEmoji.h"
#import "TUISystemMessageCellData.h"
#import <TUICore/TUICore.h>
@interface TUIMessageCell () <CAAnimationDelegate>
@property(nonatomic, strong) TUIMessageCellData *messageData;
@end
@implementation TUIMessageCell
#pragma mark - Life cycle
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self setupSubViews];
[self setupRAC];
}
return self;
}
- (void)setupSubViews {
// head
_avatarView = [[UIImageView alloc] init];
_avatarView.contentMode = UIViewContentModeScaleAspectFill;
[self.contentView addSubview:_avatarView];
UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onSelectMessageAvatar:)];
[_avatarView addGestureRecognizer:tap1];
UILongPressGestureRecognizer *tap2 = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onLongSelectMessageAvatar:)];
[_avatarView addGestureRecognizer:tap2];
[_avatarView setUserInteractionEnabled:YES];
// nameLabel
_nameLabel = [[UILabel alloc] init];
_nameLabel.font = [self fontWithSize:13];
_nameLabel.textColor = [UIColor d_systemGrayColor];
[self.contentView addSubview:_nameLabel];
// container
_container = [[UIView alloc] init];
_container.backgroundColor = [UIColor clearColor];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onSelectMessage:)];
tap.cancelsTouchesInView = NO;
[_container addGestureRecognizer:tap];
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onLongPress:)];
[_container addGestureRecognizer:longPress];
[self.contentView addSubview:_container];
// indicator
_indicator = [[UIActivityIndicatorView alloc] init];
_indicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
[_indicator sizeToFit];
[self.contentView addSubview:_indicator];
// error
_retryView = [[UIImageView alloc] init];
_retryView.userInteractionEnabled = YES;
UITapGestureRecognizer *resendTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onRetryMessage:)];
[_retryView addGestureRecognizer:resendTap];
[self.contentView addSubview:_retryView];
// messageModifyRepliesLabel
_messageModifyRepliesButton = [[TUIFitButton alloc] initWithFrame:CGRectMake(0, 0, 12, 12)];
_messageModifyRepliesButton.imageSize = CGSizeMake(12, 12);
[_messageModifyRepliesButton addTarget:self action:@selector(onJumpToRepliesDetailPage:) forControlEvents:UIControlEventTouchUpInside];
[_messageModifyRepliesButton.titleLabel setFont:[self fontWithSize:12]];
[_messageModifyRepliesButton setTitleColor:TIMCommonDynamicColor(@"chat_message_read_name_date_text_color", @"#999999") forState:UIControlStateNormal];
[_messageModifyRepliesButton setImage:TIMCommonBundleThemeImage(@"chat_messageReplyIcon_img", @"messageReplyIcon") forState:UIControlStateNormal];
[self.contentView addSubview:_messageModifyRepliesButton];
_readReceiptLabel = [[UILabel alloc] init];
_readReceiptLabel.hidden = YES;
_readReceiptLabel.font = [self fontWithSize:12];
_readReceiptLabel.textColor = TIMCommonDynamicColor(@"chat_message_read_status_text_gray_color", @"#BBBBBB");
_readReceiptLabel.lineBreakMode = NSLineBreakByCharWrapping;
UITapGestureRecognizer *showReadReceiptTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onSelectReadReceipt:)];
[_readReceiptLabel addGestureRecognizer:showReadReceiptTap];
_readReceiptLabel.userInteractionEnabled = YES;
[self.contentView addSubview:_readReceiptLabel];
// selectedIcon
_selectedIcon = [[UIImageView alloc] init];
[self.contentView addSubview:_selectedIcon];
// selectedView
_selectedView = [UIButton buttonWithType:UIButtonTypeCustom];
_selectedView.backgroundColor = [UIColor clearColor];
[_selectedView addTarget:self action:@selector(onSelectMessage:) forControlEvents:UIControlEventTouchUpInside];
[self.contentView addSubview:_selectedView];
// timeLabel
_timeLabel = [[UILabel alloc] init];
_timeLabel.textColor = [UIColor darkGrayColor];
_timeLabel.font = [self fontWithSize:11.0];
[self.contentView addSubview:_timeLabel];
self.selectionStyle = UITableViewCellSelectionStyleNone;
self.backgroundColor = UIColor.clearColor;
self.contentView.backgroundColor = UIColor.clearColor;
[self makeConstraints];
}
- (void)makeConstraints {
[self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.mas_equalTo(_container.mas_leading).mas_offset(7);
make.top.mas_equalTo(self.avatarView.mas_top);
make.width.mas_equalTo(1);
make.height.mas_equalTo(20);
}];
[self.selectedIcon mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.mas_equalTo(self.contentView.mas_leading).mas_offset(3);
make.top.mas_equalTo(self.avatarView.mas_centerY).mas_offset(-10);
make.width.mas_equalTo(20);
make.height.mas_equalTo(20);
}];
[self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.trailing.mas_equalTo(self.contentView.mas_trailing).mas_offset(-10);
make.top.mas_equalTo(self.avatarView);
make.width.mas_greaterThanOrEqualTo(10);
make.height.mas_equalTo(10);
}];
[self.selectedView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(self.contentView);
}];
}
+ (BOOL)requiresConstraintBasedLayout {
return YES;
}
// this is Apple's recommended place for adding/updating constraints
- (void)updateConstraints {
TUIMessageCellLayout *cellLayout = self.messageData.cellLayout;
BOOL isInComing = (self.messageData.direction == MsgDirectionIncoming);
[self.nameLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
if (isInComing) {
make.leading.mas_equalTo(_container.mas_leading).mas_offset(7);
make.trailing.mas_equalTo(self.contentView).mas_offset(-7);
} else {
make.leading.mas_equalTo(self.contentView).mas_offset(7);
make.trailing.mas_equalTo(self.container.mas_trailing);
}
if (self.messageData.showName) {
make.width.mas_greaterThanOrEqualTo(20);
make.height.mas_greaterThanOrEqualTo(20);
} else {
make.height.mas_equalTo(0);
}
make.top.mas_equalTo(self.avatarView.mas_top);
}];
[self.selectedIcon mas_updateConstraints:^(MASConstraintMaker *make) {
if (self.messageData.showCheckBox) {
make.width.mas_equalTo(20);
make.height.mas_equalTo(20);
} else {
make.size.mas_equalTo(CGSizeZero);
}
}];
[self.timeLabel sizeToFit];
[self.timeLabel mas_updateConstraints:^(MASConstraintMaker *make) {
if (self.messageData.showMessageTime) {
make.width.mas_equalTo(self.timeLabel.frame.size.width);
make.height.mas_equalTo(self.timeLabel.frame.size.height);
} else {
make.width.mas_equalTo(0);
make.height.mas_equalTo(0);
}
}];
CGSize csize = [self.class getContentSize:self.messageData];
CGFloat contentWidth = csize.width;
CGFloat contentHeight = csize.height;
if (!CGSizeEqualToSize(self.messageData.messageContainerAppendSize, CGSizeZero)) {
/**
* Taking the maximum width between the "emoji reply message" and the text content
*/
contentWidth = MAX(self.messageData.messageContainerAppendSize.width, csize.width);
/**
* Limit the maximum width to Screen_Width *0.25 * 3
*/
contentWidth = MIN(contentWidth, Screen_Width * 0.25 * 3);
contentHeight = csize.height + self.messageData.messageContainerAppendSize.height;
}
if (self.messageData.direction == MsgDirectionIncoming) {
self.avatarView.hidden = !self.messageData.showAvatar;
[self.avatarView mas_remakeConstraints:^(MASConstraintMaker *make) {
if (self.messageData.showCheckBox) {
make.leading.mas_equalTo(self.selectedIcon.mas_trailing).mas_offset(cellLayout.avatarInsets.left);
} else {
make.leading.mas_equalTo(self.contentView.mas_leading).mas_offset(cellLayout.avatarInsets.left);
}
make.top.mas_equalTo(cellLayout.avatarInsets.top);
make.size.mas_equalTo(cellLayout.avatarSize);
}];
[self.container mas_remakeConstraints:^(MASConstraintMaker *make) {
make.leading.mas_equalTo(self.avatarView.mas_trailing).mas_offset(cellLayout.messageInsets.left);
make.top.mas_equalTo(self.nameLabel.mas_bottom).mas_offset(cellLayout.messageInsets.top);
make.width.mas_equalTo(contentWidth);
make.height.mas_equalTo(contentHeight);
}];
CGRect indicatorFrame = self.indicator.frame;
[self.indicator mas_remakeConstraints:^(MASConstraintMaker *make) {
make.leading.mas_equalTo(self.container.mas_trailing).mas_offset(8);
make.centerY.mas_equalTo(self.container.mas_centerY);
make.size.mas_equalTo(indicatorFrame.size);
}];
self.retryView.frame = self.indicator.frame;
self.readReceiptLabel.hidden = YES;
} else {
if (!self.messageData.showAvatar) {
cellLayout.avatarSize = CGSizeZero;
}
[self.avatarView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.trailing.mas_equalTo(self.contentView.mas_trailing).mas_offset(-cellLayout.avatarInsets.right);
make.top.mas_equalTo(cellLayout.avatarInsets.top);
make.size.mas_equalTo(cellLayout.avatarSize);
}];
[self.container mas_remakeConstraints:^(MASConstraintMaker *make) {
make.trailing.mas_equalTo(self.avatarView.mas_leading).mas_offset(-cellLayout.messageInsets.right);
make.top.mas_equalTo(self.nameLabel.mas_bottom).mas_offset(cellLayout.messageInsets.top);
make.width.mas_equalTo(contentWidth);
make.height.mas_equalTo(contentHeight);
}];
CGRect indicatorFrame = self.indicator.frame;
[self.indicator mas_remakeConstraints:^(MASConstraintMaker *make) {
make.trailing.mas_equalTo(self.container.mas_leading).mas_offset(-8);
make.centerY.mas_equalTo(self.container.mas_centerY);
make.size.mas_equalTo(indicatorFrame.size);
}];
self.retryView.frame = self.indicator.frame;
[self.readReceiptLabel sizeToFit];
[self.readReceiptLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(self.container.mas_bottom);
make.trailing.mas_equalTo(self.container.mas_leading).mas_offset(-8);
make.size.mas_equalTo(self.readReceiptLabel.frame.size);
}];
}
if (!self.messageModifyRepliesButton.isHidden) {
self.messageModifyRepliesButton.mm_sizeToFit();
CGFloat repliesBtnTextWidth = self.messageModifyRepliesButton.frame.size.width;
[self.messageModifyRepliesButton mas_remakeConstraints:^(MASConstraintMaker *make) {
if (isInComing) {
make.leading.mas_equalTo(self.container.mas_leading);
} else {
make.trailing.mas_equalTo(self.container.mas_trailing);
}
make.top.mas_equalTo(self.container.mas_bottom);
make.size.mas_equalTo(CGSizeMake(repliesBtnTextWidth + 10, 30));
}];
}
// according to apple super should be called at end of method
[super updateConstraints];
}
- (void)layoutSubviews {
[super layoutSubviews];
}
- (void)setupRAC {
@weakify(self);
[RACObserve(self, readReceiptLabel.text) subscribeNext:^(id _Nullable x) {
@strongify(self);
if ([self shouldHighlightReadReceiptLabel]) {
self.readReceiptLabel.textColor = TIMCommonDynamicColor(@"chat_message_read_status_text_color", @"#147AFF");
} else {
self.readReceiptLabel.textColor = TIMCommonDynamicColor(@"chat_message_read_status_text_gray_color", @"#BBBBBB");
}
}];
}
- (void)prepareForReuse {
[super prepareForReuse];
/**
* In the future, any UI problems caused by reuse can be solved by coding here.
*/
/**
* Once the message is reused, it means that a new message is about to appear, and the label content is changed to empty string.
*/
_readReceiptLabel.text = @"";
_readReceiptLabel.hidden = YES;
}
#pragma mark - Public
- (void)fillWithData:(TUIMessageCellData *)data {
[super fillWithData:data];
self.messageData = data;
[self loadAvatar:data];
if (self.messageData.showName) {
_nameLabel.hidden = NO;
} else {
_nameLabel.hidden = YES;
}
if (self.messageData.showCheckBox) {
_selectedIcon.hidden = NO;
_selectedView.hidden = NO;
} else {
_selectedIcon.hidden = YES;
_selectedView.hidden = YES;
}
if ([TUIConfig defaultConfig].avatarType == TAvatarTypeRounded) {
self.avatarView.layer.masksToBounds = YES;
self.avatarView.layer.cornerRadius = data.cellLayout.avatarSize.height / 2;
} else if ([TUIConfig defaultConfig].avatarType == TAvatarTypeRadiusCorner) {
self.avatarView.layer.masksToBounds = YES;
self.avatarView.layer.cornerRadius = [TUIConfig defaultConfig].avatarCornerRadius;
}
self.nameLabel.text = data.senderName;
if (data.direction == MsgDirectionIncoming) {
self.nameLabel.textColor = self.class.incommingNameColor;
self.nameLabel.font = self.class.incommingNameFont;
} else {
self.nameLabel.textColor = self.class.outgoingNameColor;
self.nameLabel.font = self.class.outgoingNameFont;
}
self.retryView.image = [UIImage imageNamed:TUIChatImagePath(@"msg_error")];
if (data.status == Msg_Status_Fail) {
[_indicator stopAnimating];
_readReceiptLabel.hidden = YES;
self.retryView.hidden = NO;
} else {
if (data.status == Msg_Status_Sending_2) {
[_indicator startAnimating];
_readReceiptLabel.hidden = YES;
} else if (data.status == Msg_Status_Succ) {
[_indicator stopAnimating];
/**
* The message is sent successfully, indicating that the indicator and error are no longer displayed on the label, and the read receipt label can be
* displayed.
*/
if (self.messageData.showReadReceipt && self.messageData.direction == MsgDirectionOutgoing && self.messageData.innerMessage.needReadReceipt &&
(self.messageData.innerMessage.userID || self.messageData.innerMessage.groupID) &&
![self.messageData isKindOfClass:TUISystemMessageCellData.class]) {
[self updateReadLabelText];
_readReceiptLabel.hidden = NO;
}
} else if (data.status == Msg_Status_Sending) {
[_indicator startAnimating];
_readReceiptLabel.hidden = YES;
}
self.retryView.hidden = YES;
}
self.messageModifyRepliesButton.hidden = !data.showMessageModifyReplies;
if (data.showMessageModifyReplies) {
NSString *title = [NSString stringWithFormat:@"%ld%@", data.messageModifyReplies.count, TIMCommonLocalizableString(TUIKitRepliesNum)];
[self.messageModifyRepliesButton setTitle:title forState:UIControlStateNormal];
[self.messageModifyRepliesButton sizeToFit];
[self.messageModifyRepliesButton setNeedsUpdateConstraints];
[self.messageModifyRepliesButton updateConstraintsIfNeeded];
[self.messageModifyRepliesButton layoutIfNeeded];
}
NSString *imageName = (data.showCheckBox && data.selected) ? TIMCommonImagePath(@"icon_select_selected") : TIMCommonImagePath(@"icon_select_normal");
self.selectedIcon.image = [UIImage imageNamed:imageName];
_timeLabel.text = [TUITool convertDateToStr:data.innerMessage.timestamp];
[_timeLabel sizeToFit];
_timeLabel.hidden = !data.showMessageTime;
/**
* Text highlighting - asynchronous operations are here to keep the order of execution consistent with subclasses
*/
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf highlightWhenMatchKeyword:data.highlightKeyword];
});
// tell constraints they need updating
[self setNeedsUpdateConstraints];
// update constraints now so we can animate the change
[self updateConstraintsIfNeeded];
[self layoutIfNeeded];
}
- (void)loadAvatar:(TUIMessageCellData *)data {
[self.avatarView setImage:DefaultAvatarImage];
@weakify(self);
[[[RACObserve(data, avatarUrl) takeUntil:self.rac_prepareForReuseSignal] ignore:nil] subscribeNext:^(NSURL *url) {
@strongify(self);
[self.avatarView sd_setImageWithURL:url placeholderImage:DefaultAvatarImage];
}];
if (data.isUseMsgReceiverAvatar) {
NSString *userId = @"";
if ([data.innerMessage.sender isEqualToString:V2TIMManager.sharedInstance.getLoginUser]) {
userId = data.innerMessage.userID;
} else {
userId = V2TIMManager.sharedInstance.getLoginUser;
}
[V2TIMManager.sharedInstance getUsersInfo:@[ userId?:@"" ]
succ:^(NSArray<V2TIMUserFullInfo *> *infoList) {
@strongify(self);
V2TIMUserFullInfo *info = infoList.firstObject;
if (info && [data isEqual:self.messageData]) {
data.avatarUrl = [NSURL URLWithString:info.faceURL];
[self.avatarView sd_setImageWithURL:data.avatarUrl placeholderImage:DefaultAvatarImage];
}
}
fail:^(int code, NSString *desc){
}];
}
}
- (void)highlightWhenMatchKeyword:(NSString *)keyword {
static NSString *const key = @"highlightAnimation";
if (keyword && keyword.length) {
if (self.highlightAnimating) {
return;
}
self.highlightAnimating = YES;
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"backgroundColor"];
animation.repeatCount = 3;
animation.values = @[
(id)[[UIColor orangeColor] colorWithAlphaComponent:0.2].CGColor,
(id)[[UIColor orangeColor] colorWithAlphaComponent:0.5].CGColor,
(id)[[UIColor orangeColor] colorWithAlphaComponent:0.2].CGColor,
];
animation.duration = 0.5;
animation.removedOnCompletion = YES;
animation.delegate = self;
[self.highlightAnimateView.layer addAnimation:animation forKey:key];
} else {
[self.highlightAnimateView.layer removeAnimationForKey:key];
}
}
- (void)updateReadLabelText {
if (self.messageData.innerMessage.groupID.length > 0) {
// group message
NSString *text = TIMCommonLocalizableString(Unread);
if (self.messageData.messageReceipt == nil) {
// haven't received the message receipt yet
return;
}
NSInteger readCount = self.messageData.messageReceipt.readCount;
NSInteger unreadCount = self.messageData.messageReceipt.unreadCount;
if (unreadCount == 0) {
// show "All read"
text = TIMCommonLocalizableString(TUIKitMessageReadAllRead);
} else if (readCount > 0) {
// show "x read"
text = [NSString stringWithFormat:@"%ld %@", (long)readCount, TIMCommonLocalizableString(TUIKitMessageReadPartRead)];
}
self.readReceiptLabel.text = text;
} else {
// c2c message
BOOL isPeerRead = self.messageData.messageReceipt.isPeerRead;
NSString *text = isPeerRead ? TIMCommonLocalizableString(TUIKitMessageReadC2CRead) : TIMCommonLocalizableString(TUIKitMessageReadC2CUnRead);
self.readReceiptLabel.text = text;
}
[self.readReceiptLabel sizeToFit];
[self.readReceiptLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(self.container.mas_bottom);
make.trailing.mas_equalTo(self.container.mas_leading).mas_offset(-8);
make.size.mas_equalTo(self.readReceiptLabel.frame.size);
}];
self.readReceiptLabel.textColor = [self shouldHighlightReadReceiptLabel] ? TIMCommonDynamicColor(@"chat_message_read_status_text_color", @"#147AFF")
: TIMCommonDynamicColor(@"chat_message_read_status_text_gray_color", @"#BBBBBB");
}
- (UIView *)highlightAnimateView {
return self.container;
}
#pragma mark - TUIMessageCellProtocol
+ (CGFloat)getEstimatedHeight:(TUIMessageCellData *)data {
return 60.f;
}
+ (CGFloat)getHeight:(TUIMessageCellData *)data withWidth:(CGFloat)width {
CGFloat height = 0;
if (data.showName) height += kScale375(20);
if (data.showMessageModifyReplies) height += kScale375(22);
if (data.messageContainerAppendSize.height > 0) {
height += data.messageContainerAppendSize.height;
}
CGSize containerSize = [self getContentSize:data];
height += containerSize.height;
height += data.cellLayout.messageInsets.top;
height += data.cellLayout.messageInsets.bottom;
if (height < 55) height = 55;
return height;
}
+ (CGSize)getContentSize:(TUIMessageCellData *)data {
return CGSizeZero;
}
#pragma mark - Private
- (void)animationDidStart:(CAAnimation *)anim {
self.highlightAnimating = YES;
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
self.highlightAnimating = NO;
}
#pragma mark-- Event
- (void)onLongPress:(UIGestureRecognizer *)recognizer {
if ([recognizer isKindOfClass:[UILongPressGestureRecognizer class]] && recognizer.state == UIGestureRecognizerStateBegan) {
if (_delegate && [_delegate respondsToSelector:@selector(onLongPressMessage:)]) {
[_delegate onLongPressMessage:self];
}
}
}
- (void)onRetryMessage:(UIGestureRecognizer *)recognizer {
if (_messageData.status == Msg_Status_Fail)
if (_delegate && [_delegate respondsToSelector:@selector(onRetryMessage:)]) {
[_delegate onRetryMessage:self];
}
}
- (void)onSelectMessage:(UIGestureRecognizer *)recognizer {
if (_delegate && [_delegate respondsToSelector:@selector(onSelectMessage:)]) {
[_delegate onSelectMessage:self];
}
}
- (void)onSelectMessageAvatar:(UIGestureRecognizer *)recognizer {
if (_delegate && [_delegate respondsToSelector:@selector(onSelectMessageAvatar:)]) {
[_delegate onSelectMessageAvatar:self];
}
}
- (void)onLongSelectMessageAvatar:(UIGestureRecognizer *)recognizer {
if (_delegate && [_delegate respondsToSelector:@selector(onLongSelectMessageAvatar:)]) {
[_delegate onLongSelectMessageAvatar:self];
}
}
- (void)onSelectReadReceipt:(UITapGestureRecognizer *)gesture {
if (![self shouldHighlightReadReceiptLabel]) {
return;
}
if (_delegate && [_delegate respondsToSelector:@selector(onSelectReadReceipt:)]) {
[_delegate onSelectReadReceipt:self.messageData];
}
}
- (void)onJumpToRepliesDetailPage:(UIButton *)btn {
NSLog(@"click onJumpToRepliesDetailPage");
NSLog(@"%@", self.messageData.messageModifyReplies);
if (_delegate && [_delegate respondsToSelector:@selector(onJumpToRepliesDetailPage:)]) {
[_delegate onJumpToRepliesDetailPage:self.messageData];
}
}
- (BOOL)shouldHighlightReadReceiptLabel {
if (self.messageData.innerMessage.groupID.length == 0) {
return ![self.readReceiptLabel.text isEqualToString:TIMCommonLocalizableString(TUIKitMessageReadC2CRead)];
} else {
return ![self.readReceiptLabel.text isEqualToString:TIMCommonLocalizableString(TUIKitMessageReadAllRead)];
}
}
- (UIFont *)fontWithSize:(CGFloat)size {
static NSCache *fontCache;
if (fontCache == nil) {
fontCache = [[NSCache alloc] init];
}
UIFont *font = [fontCache objectForKey:@(size)];
if (font == nil) {
font = [UIFont systemFontOfSize:size];
[fontCache setObject:font forKey:@(size)];
}
return font;
}
- (void)notifyBottomContainerReadyOfData:(TUIMessageCellData *)cellData {
// Override by subclass.
}
@end
@implementation TUIMessageCell (TUILayoutConfiguration)
static UIColor *gOutgoingNameColor;
+ (UIColor *)outgoingNameColor {
if (!gOutgoingNameColor) {
gOutgoingNameColor = [UIColor d_systemGrayColor];
}
return gOutgoingNameColor;
}
+ (void)setOutgoingNameColor:(UIColor *)outgoingNameColor {
gOutgoingNameColor = outgoingNameColor;
}
static UIFont *gOutgoingNameFont;
+ (UIFont *)outgoingNameFont {
if (!gOutgoingNameFont) {
gOutgoingNameFont = [UIFont systemFontOfSize:14];
}
return gOutgoingNameFont;
}
+ (void)setOutgoingNameFont:(UIFont *)outgoingNameFont {
gOutgoingNameFont = outgoingNameFont;
}
static UIColor *gIncommingNameColor;
+ (UIColor *)incommingNameColor {
if (!gIncommingNameColor) {
gIncommingNameColor = [UIColor d_systemGrayColor];
}
return gIncommingNameColor;
}
+ (void)setIncommingNameColor:(UIColor *)incommingNameColor {
gIncommingNameColor = incommingNameColor;
}
static UIFont *gIncommingNameFont;
+ (UIFont *)incommingNameFont {
if (!gIncommingNameFont) {
gIncommingNameFont = [UIFont systemFontOfSize:14];
}
return gIncommingNameFont;
}
+ (void)setIncommingNameFont:(UIFont *)incommingNameFont {
gIncommingNameFont = incommingNameFont;
}
@end