// // MessageCell.m // xplan-ios // // Created by zu on 2021/11/28. // #import "MessageCell.h" #import "MessageContentProtocol.h" #import "MessageContentText.h" #import "MessageContentImage.h" #import "MessageContentTextClickable.h" #import "MessageContentCustomView.h" #import "MessageContentGiftView.h" #import "MessageContentGuildView.h" #import "MessageContentUnSupportView.h" #import "MessageContentOpenLiveView.h" #import "MessageContentApplicationShareView.h" #import "MessageContentLevelUpgradeView.h" #import "MessageConentAudioView.h" #import "MessageContentTweetView.h" #import "MessageContentSkillCardView.h" #import "MessageContentFindNewGreetView.h" #import "MessageContentRiskAlertView.h" #import "MessageContentMonentsView.h" #import "MessageContentMonentsAutoView.h" #import "MessageContentRedPacketView.h" #import "MessageContentGameView.h" #import "AttachmentModel.h" #import "NetImageView.h" #import "ThemeColor.h" #import "XPMacro.h" #import @interface MessageCell() @property (nonatomic, assign) NIMMessageType messageType; /** 左侧头像(私聊对象) */ @property (nonatomic, strong) NetImageView * leftAvatar; /** 右侧头像(自己) */ @property (nonatomic, strong) NetImageView * rightAvatar; ///处理失败的 @property (nonatomic,strong) UIButton *failButton; /** 消息背景 */ @property (nonatomic, strong) UIView * messageBackground; @property (nonatomic, strong) MASConstraint * messageBackgroundLeft; @property (nonatomic, strong) MASConstraint * messageBackgroundRight; /** 消息内容实体 */ @property (nonatomic, strong) UIView * messageContent; ///当前的消息 @property (nonatomic,strong) NIMMessage *currentMessage; @end @implementation MessageCell + (CGFloat)measureHeight:(NIMMessage *)message { CGFloat minHeight = AVATAR_SIZE + AVATAR_MARGIN_H * 2; if (!message) { return minHeight; } CGFloat mesuredHeight = 0; switch (message.messageType) { case NIMMessageTypeText: case NIMMessageTypeTip: mesuredHeight = [MessageContentText measureHeight:message]; break; case NIMMessageTypeImage: mesuredHeight = [MessageContentImage measureHeight:message]; break; case NIMMessageTypeAudio: mesuredHeight = [MessageConentAudioView measureHeight:message]; break; case NIMMessageTypeCustom: mesuredHeight = [self customMessageMeasureHeight:message]; break; default: break; } return MAX(minHeight, mesuredHeight); } - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { self.selectionStyle = UITableViewCellSelectionStyleNone; [self initViews]; [self initLayout]; } return self; } - (void)initViews { self.backgroundColor = UIColor.clearColor; [self.contentView addSubview:self.leftAvatar]; [self.contentView addSubview:self.rightAvatar]; [self.contentView addSubview:self.messageBackground]; [self.contentView addSubview:self.failButton]; } - (void)initLayout { [self.leftAvatar mas_makeConstraints:^(MASConstraintMaker *make) { make.left.top.mas_equalTo(self).offset(15); make.width.height.mas_equalTo(45); }]; [self.rightAvatar mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(self).offset(15); make.right.mas_equalTo(self).offset(-15); make.width.height.mas_equalTo(45); }]; [self.messageBackground mas_makeConstraints:^(MASConstraintMaker *make) { self.messageBackgroundLeft = make.left.mas_equalTo(self.leftAvatar.mas_right).offset(15); self.messageBackgroundRight = make.right.mas_equalTo(self.rightAvatar.mas_left).offset(-15); make.top.mas_equalTo(self).offset(20); }]; [self.failButton mas_makeConstraints:^(MASConstraintMaker *make) { make.size.mas_equalTo(CGSizeMake(20, 20)); make.centerY.mas_equalTo(self.messageBackground); make.left.mas_equalTo(self.messageBackground.mas_right).offset(10); }]; } - (void)renderWithMessage:(NIMMessage *)message { self.currentMessage = message; NSString * avatarUrl = [[NIMSDK sharedSDK].userManager userInfo:message.from].userInfo.avatarUrl; avatarUrl = [avatarUrl stringByReplacingOccurrencesOfString:@"https" withString:@"http"]; BOOL isSelf = [[NIMSDK sharedSDK].loginManager.currentAccount isEqualToString:message.from]; if (isSelf) { self.leftAvatar.hidden = YES; self.rightAvatar.hidden = NO; [self.messageBackgroundLeft uninstall]; [self.messageBackgroundRight install]; self.rightAvatar.imageUrl = avatarUrl; } else { self.leftAvatar.hidden = NO; self.rightAvatar.hidden = YES; [self.messageBackgroundLeft install]; [self.messageBackgroundRight uninstall]; self.leftAvatar.imageUrl = avatarUrl; } [self handleMessageFail:message]; if ([self messageShowAvatar:message]) { self.leftAvatar.hidden= [self messageShowAvatar:message]; self.rightAvatar.hidden = [self messageShowAvatar:message]; } if (self.messageContent) { [self.messageContent removeFromSuperview]; } switch (message.messageType) { case NIMMessageTypeText: case NIMMessageTypeTip: if (![self.messageContent isKindOfClass:[MessageContentText class]]) { self.messageContent = [[MessageContentText alloc] init]; } break; case NIMMessageTypeImage: if (![self.messageContent isKindOfClass:[MessageContentImage class]]) { self.messageContent = [[MessageContentImage alloc] init]; } break; case NIMMessageTypeAudio: if (![self.messageContent isKindOfClass:[MessageConentAudioView class]]) { self.messageContent = [[MessageConentAudioView alloc] init]; } break; case NIMMessageTypeCustom: self.messageContent = [self getCustomMessageContentView:message]; break; default: if (![self.messageContent isKindOfClass:[MessageContentUnSupportView class]]) { self.messageContent = [[MessageContentUnSupportView alloc] init]; } break; } [self.messageBackground addSubview:self.messageContent]; [self.messageContent mas_makeConstraints:^(MASConstraintMaker *make) { make.left.top.right.bottom.mas_equalTo(self.messageBackground); }]; [self.messageContent render:message]; } - (void)handleMessageFail:(NIMMessage *)message { BOOL isHiddenFail = YES; if (!message.isReceivedMsg) { isHiddenFail = message.deliveryState != NIMMessageDeliveryStateFailed; if (message.localExt) { NSDictionary * dic = message.localExt; if (((NSString *)dic[@"suggestion"]).integerValue == 2) { isHiddenFail = NO; } } } else { isHiddenFail = message.attachmentDownloadState != NIMMessageAttachmentDownloadStateFailed; } self.failButton.hidden = isHiddenFail; if (!isHiddenFail) { if (message.isReceivedMsg) { [self.failButton mas_remakeConstraints:^(MASConstraintMaker *make) { make.size.mas_equalTo(CGSizeMake(20, 20)); make.centerY.mas_equalTo(self.messageBackground); make.left.mas_equalTo(self.messageBackground.mas_right).offset(10); }]; } else { [self.failButton mas_remakeConstraints:^(MASConstraintMaker *make) { make.size.mas_equalTo(CGSizeMake(20, 20)); make.centerY.mas_equalTo(self.messageBackground); make.right.mas_equalTo(self.messageBackground.mas_left).offset(-10); }]; } } } + (NSString *)cellContent:(NIMMessage *)message { if (message.messageType == NIMMessageTypeText || message.messageType == NIMMessageTypeTip) { return @"MessageContentText"; } else if(message.messageType == NIMMessageTypeImage) { return @"MessageContentImage"; }else if(message.messageType == NIMMessageTypeAudio) { return @"MessageConentAudioView"; } else if(message.messageType == NIMMessageTypeCustom) { NIMCustomObject *obj = (NIMCustomObject *)message.messageObject; AttachmentModel *attachment = (AttachmentModel *)obj.attachment; if (attachment.first == CustomMessageType_Gift && attachment.second == Custom_Message_Sub_Gift_Send) { return @"MessageContentGiftView"; } else if(attachment.first == CustomMessageType_Secretary) { return @"MessageContentTextClickable"; } else if(attachment.first == CustomMessageType_Hall) { return @"MessageContentGuildView"; } else if(attachment.first == CustomMessageType_Member_Online && attachment.second == Custom_Message_Type_Attention_Member_Online) { return @"MessageContentOpenLiveView"; } else if(attachment.first == CustomMessageType_Application_Share && attachment.second == Custom_Message_Sub_Application_Share_Room) { return @"MessageContentOpenLiveView"; } else if(attachment.first == CustomMessageType_User_UpGrade && (attachment.second == Custom_Message_Sub_User_UpGrade_Charm || attachment.second == Custom_Message_Sub_User_UpGrade_Exper)) { return @"MessageContentLevelUpgradeView"; } else if(attachment.first == CustomMessageType_Tweet && attachment.second == Custom_Message_Sub_Tweet_News) { return @"MessageContentTweetView"; } else if(attachment.first == CustomMessageType_Skill_Card) { return @"MessageContentSkillCardView"; } else if(attachment.first == CustomMessageType_FindNew){ return @"MessageContentFindNewGreetView"; } else if(attachment.first == CustomMessageType_Chat_Risk_Alert) { return @"MessageContentRiskAlertView"; }else if(attachment.first == CustomMessageType_Monents && attachment.second == Custom_Message_Sub_Monents_Share) { return @"MessageContentMonentsView"; }else if(attachment.first == CustomMessageType_Monents && (attachment.second == Custom_Message_Sub_Monents_Approved | attachment.second == Custom_Message_Sub_Monents_Ban_Delete)) { return @"MessageContentMonentsAutoView"; } else if(attachment.first == CustomMessageType_Message_Handle && attachment.second == Custom_Message_Sub_Message_Handle_Content) { return @"MessageContentMonentsAutoView"; } else if (attachment.first == CustomMessageType_RedPacket && attachment.second == Custom_Message_Sub_AllDiamandRedPacket) { return @"MessageContentRedPacketView"; }else if(attachment.first == CustomMessageType_Initiat_Invitation && attachment.second == Custom_Message_Sub_Initiat_Invitation_Initiating_User){ return @"MessageContentGameView"; }else { return @"MessageContentUnSupportView"; } } else { return @"MessageContentUnSupportView"; } } - (BOOL)messageShowAvatar:(NIMMessage *)message { if (message.messageType == NIMMessageTypeCustom) { NIMCustomObject *obj = (NIMCustomObject *)message.messageObject; AttachmentModel *attachment = (AttachmentModel *)obj.attachment; if (attachment.first == CustomMessageType_Chat_Risk_Alert) { return YES; } } return NO; } + (CGFloat)customMessageMeasureHeight:(NIMMessage *)message { NIMCustomObject *obj = (NIMCustomObject *)message.messageObject; AttachmentModel *attachment = (AttachmentModel *)obj.attachment; if (attachment.first == CustomMessageType_Gift && attachment.second == Custom_Message_Sub_Gift_Send) { return [MessageContentGiftView measureHeight:message]; } else if(attachment.first == CustomMessageType_Secretary && attachment.second == Custom_Message_Sub_Secretary_Router) { return [MessageContentTextClickable measureHeight:message]; } else if(attachment.first == CustomMessageType_Hall) { return [MessageContentGuildView measureHeight:message]; } else if(attachment.first == CustomMessageType_Member_Online && attachment.second == Custom_Message_Type_Attention_Member_Online) { return [MessageContentOpenLiveView measureHeight:message]; } else if(attachment.first == CustomMessageType_Application_Share && attachment.second == Custom_Message_Sub_Application_Share_Room) { return [MessageContentApplicationShareView measureHeight:message]; } else if(attachment.first == CustomMessageType_User_UpGrade && (attachment.second == Custom_Message_Sub_User_UpGrade_Charm || attachment.second == Custom_Message_Sub_User_UpGrade_Exper)) { return [MessageContentLevelUpgradeView measureHeight:message]; } else if(attachment.first == CustomMessageType_Tweet && attachment.second == Custom_Message_Sub_Tweet_News) { return [MessageContentTweetView measureHeight:message]; } else if(attachment.first == CustomMessageType_Skill_Card) { return [MessageContentSkillCardView measureHeight:message]; } else if(attachment.first == CustomMessageType_FindNew) { return [MessageContentFindNewGreetView measureHeight:message]; } else if(attachment.first == CustomMessageType_Chat_Risk_Alert) { return [MessageContentRiskAlertView measureHeight:message]; } else if(attachment.first == CustomMessageType_Monents && attachment.second == Custom_Message_Sub_Monents_Share) { return [MessageContentMonentsView measureHeight:message]; } else if(attachment.first == CustomMessageType_Monents && (attachment.second == Custom_Message_Sub_Monents_Approved | attachment.second == Custom_Message_Sub_Monents_Ban_Delete)) { return [MessageContentMonentsAutoView measureHeight:message]; }else if(attachment.first == CustomMessageType_Message_Handle && attachment.second == Custom_Message_Sub_Message_Handle_Content) { return [MessageContentMonentsAutoView measureHeight:message]; } else if (attachment.first == CustomMessageType_RedPacket && attachment.second == Custom_Message_Sub_AllDiamandRedPacket){ return [MessageContentRedPacketView measureHeight:message]; }else if(attachment.first == CustomMessageType_Initiat_Invitation && attachment.second == Custom_Message_Sub_Initiat_Invitation_Initiating_User){ return [MessageContentGameView measureHeight:message]; } else { return [MessageContentUnSupportView measureHeight:message]; } } - (UIView *)getCustomMessageContentView:(NIMMessage *)message { NIMCustomObject *obj = (NIMCustomObject *)message.messageObject; AttachmentModel *attachment = (AttachmentModel *)obj.attachment; if (attachment.first == CustomMessageType_Gift && attachment.second == Custom_Message_Sub_Gift_Send) { if ([self.messageContent isKindOfClass:[MessageContentGiftView class]]) { return self.messageContent; } return [[MessageContentGiftView alloc] init]; } else if(attachment.first == CustomMessageType_Secretary && attachment.second == Custom_Message_Sub_Secretary_Router) { if ([self.messageContent isKindOfClass:[MessageContentTextClickable class]]) { return self.messageContent; } return [[MessageContentTextClickable alloc] init]; } else if(attachment.first == CustomMessageType_Hall) { if ([self.messageContent isKindOfClass:[MessageContentTextClickable class]]) { return self.messageContent; } MessageContentGuildView * hallView =[[MessageContentGuildView alloc] init]; hallView.delegate = self; return hallView; } else if(attachment.first == CustomMessageType_Member_Online && attachment.second == Custom_Message_Type_Attention_Member_Online) { if ([self.messageContent isKindOfClass:[MessageContentOpenLiveView class]]) { return self.messageContent; } return [[MessageContentOpenLiveView alloc] init]; } else if(attachment.first == CustomMessageType_Application_Share && attachment.second == Custom_Message_Sub_Application_Share_Room) { if ([self.messageContent isKindOfClass:[MessageContentApplicationShareView class]]) { return self.messageContent; } return [[MessageContentApplicationShareView alloc] init]; }else if(attachment.first == CustomMessageType_User_UpGrade && (attachment.second == Custom_Message_Sub_User_UpGrade_Charm || attachment.second == Custom_Message_Sub_User_UpGrade_Exper)) { if ([self.messageContent isKindOfClass:[MessageContentLevelUpgradeView class]]) { return self.messageContent; } return [[MessageContentLevelUpgradeView alloc] init]; }else if(attachment.first == CustomMessageType_Tweet && attachment.second == Custom_Message_Sub_Tweet_News) { if ([self.messageContent isKindOfClass:[MessageContentTweetView class]]) { return self.messageContent; } return [[MessageContentTweetView alloc] init]; } else if(attachment.first == CustomMessageType_Skill_Card) { if ([self.messageContent isKindOfClass:[MessageContentSkillCardView class]]) { return self.messageContent; } return [[MessageContentSkillCardView alloc] init]; }else if(attachment.first == CustomMessageType_FindNew) { if ([self.messageContent isKindOfClass:[MessageContentFindNewGreetView class]]) { return self.messageContent; } return [[MessageContentFindNewGreetView alloc] init]; } else if(attachment.first == CustomMessageType_Chat_Risk_Alert) { if ([self.messageContent isKindOfClass:[MessageContentRiskAlertView class]]) { return self.messageContent; } return [[MessageContentRiskAlertView alloc] init]; }else if(attachment.first == CustomMessageType_Monents && attachment.second == Custom_Message_Sub_Monents_Share) { if ([self.messageContent isKindOfClass:[MessageContentMonentsView class]]) { return self.messageContent; } return [[MessageContentMonentsView alloc] init]; }else if(attachment.first == CustomMessageType_Monents && (attachment.second == Custom_Message_Sub_Monents_Approved | attachment.second == Custom_Message_Sub_Monents_Ban_Delete)) { if ([self.messageContent isKindOfClass:[MessageContentMonentsAutoView class]]) { return self.messageContent; } return [[MessageContentMonentsAutoView alloc] init]; }else if(attachment.first == CustomMessageType_Message_Handle && attachment.second == Custom_Message_Sub_Message_Handle_Content) { if ([self.messageContent isKindOfClass:[MessageContentMonentsAutoView class]]) { return self.messageContent; } return [[MessageContentMonentsAutoView alloc] init]; } else if(attachment.first == CustomMessageType_RedPacket && attachment.second == Custom_Message_Sub_AllDiamandRedPacket) { self.messageBackground.backgroundColor = [UIColor clearColor]; if ([self.messageContent isKindOfClass:[MessageContentRedPacketView class]]) { return self.messageContent; } return [[MessageContentRedPacketView alloc] init]; } else if(attachment.first == CustomMessageType_Initiat_Invitation && attachment.second == Custom_Message_Sub_Initiat_Invitation_Initiating_User){ if ([self.messageContent isKindOfClass:[MessageContentGameView class]]) { return self.messageContent; } MessageContentGameView*gameView = [[MessageContentGameView alloc] init]; gameView.delegate = self; return gameView; }else { if ([self.messageContent isKindOfClass:[MessageContentUnSupportView class]]) { return self.messageContent; } return [[MessageContentUnSupportView alloc] init]; } } #pragma mark - MessageContentCustomViewDelegate - (void)updateMessageSuccess:(NIMMessage *)message { if (self.delegate && [self.delegate respondsToSelector:@selector(updateMessageSuccess:)]) { [self.delegate updateMessageSuccess:message]; } } - (void)checkGameListInfo:(NIMMessage *)message{ if(self.delegate && [self.delegate respondsToSelector:@selector(checkGameListInfo:)]){ [self.delegate checkGameListInfo:message]; } } #pragma mark - Event Response - (void)rightAvatarTapRecognizer { if (self.delegate && [self.delegate respondsToSelector:@selector(didTapAvatar:)]) { [self.delegate didTapAvatar:self.currentMessage.from]; } } - (void)leftAvatarTapRecognizer { if (self.delegate && [self.delegate respondsToSelector:@selector(didTapAvatar:)]) { [self.delegate didTapAvatar:self.currentMessage.from]; } } - (void)failButtonAction:(UIButton *)sender { if (self.delegate && [self.delegate respondsToSelector:@selector(didFailRetry:)]) { [self.delegate didFailRetry:self.currentMessage]; } } #pragma mark - Getters And Setters - (NetImageView *)leftAvatar { if (!_leftAvatar) { NetImageConfig * config = [[NetImageConfig alloc] init]; config.placeHolder = [UIImageConstant defaultAvatarPlaceholder]; config.radius = MAXFLOAT; config.imageType = ImageTypeUserIcon; _leftAvatar = [[NetImageView alloc] initWithConfig:config]; _leftAvatar.layer.masksToBounds = YES; _leftAvatar.layer.cornerRadius = 45.f / 2; _leftAvatar.hidden = YES; _leftAvatar.userInteractionEnabled = YES; UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(leftAvatarTapRecognizer)]; [_leftAvatar addGestureRecognizer:tap]; } return _leftAvatar; } - (NetImageView *)rightAvatar { if (!_rightAvatar) { NetImageConfig * config = [[NetImageConfig alloc] init]; config.placeHolder = [UIImageConstant defaultAvatarPlaceholder]; config.radius = MAXFLOAT; config.imageType = ImageTypeUserIcon; _rightAvatar = [[NetImageView alloc] initWithConfig:config]; _rightAvatar.layer.masksToBounds = YES; _rightAvatar.layer.cornerRadius = 45.f / 2; _rightAvatar.hidden = YES; _rightAvatar.userInteractionEnabled = YES; UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(rightAvatarTapRecognizer)]; [_rightAvatar addGestureRecognizer:tap]; } return _rightAvatar; } - (UIView *)messageBackground { if (!_messageBackground) { _messageBackground = [[UIView alloc]init]; _messageBackground.backgroundColor = [ThemeColor appCellBackgroundColor]; _messageBackground.layer.masksToBounds = YES; _messageBackground.layer.cornerRadius = 8.f; } return _messageBackground; } - (UIButton *)failButton { if (!_failButton) { _failButton = [UIButton buttonWithType:UIButtonTypeCustom]; [_failButton setImage:[UIImage imageNamed:@"message_session_download_fail"] forState:UIControlStateNormal]; [_failButton setImage:[UIImage imageNamed:@"message_session_download_fail"] forState:UIControlStateSelected]; [_failButton addTarget:self action:@selector(failButtonAction:) forControlEvents:UIControlEventTouchUpInside]; _failButton.hidden = YES; } return _failButton; } @end