// // MessageCell.m // YUMI // // 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 "MessageTimeView.h" #import "AttachmentModel.h" #import "NetImageView.h" #import "DJDKMIMOMColor.h" #import "PLTimeUtil.h" #import "XPSkillCardPlayerManager.h" #import "YUMIMacroUitls.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; ///当前的实体 @property (nonatomic,strong) MessageBaseModel *currentModel; @end @implementation MessageCell - (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]; //在自定义cell中的init方法加入 UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressCellHandle:)]; longPressGesture.minimumPressDuration = 0.5; [self.messageBackground addGestureRecognizer:longPressGesture]; } - (void)initLayout { [self.leftAvatar mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.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.trailing.mas_equalTo(self).offset(-15); make.width.height.mas_equalTo(45); }]; [self.messageBackground mas_makeConstraints:^(MASConstraintMaker *make) { self.messageBackgroundLeft = make.leading.mas_equalTo(self.leftAvatar.mas_trailing).offset(15); self.messageBackgroundRight = make.trailing.mas_equalTo(self.rightAvatar.mas_leading).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.leading.mas_equalTo(self.messageBackground.mas_trailing).offset(10); }]; } //并加上几个方法 -(void)longPressCellHandle:(UILongPressGestureRecognizer *)gesture { if (!self.currentMessage) { return; } if(gesture.state==UIGestureRecognizerStateBegan) { [self becomeFirstResponder]; UIMenuController *menuController = [UIMenuController sharedMenuController]; UIMenuItem *copyItem = [[UIMenuItem alloc] initWithTitle:YMLocalizedString(@"MessageCell0") action:@selector(menuCopyBtnPressed:)]; UIMenuItem *deleteItem = [[UIMenuItem alloc] initWithTitle:YMLocalizedString(@"MessageCell1") action:@selector(menuDeleteCopyBtnPressed:)]; UIMenuItem *revokeItem = [[UIMenuItem alloc] initWithTitle:YMLocalizedString(@"MessageCell2") action:@selector(menuRevokeBtnPressed:)]; NSMutableArray * array = [NSMutableArray array]; if ((self.currentMessage.messageType == NIMMessageTypeText) && !self.currentModel.isHiddenAvatar) { [array addObject:copyItem]; } if (!self.currentModel.isHiddenAvatar) { [array addObject:deleteItem]; } if (self.currentMessage.isOutgoingMsg && [self checkDataWith:self.currentMessage.timestamp] && (self.currentMessage.messageType == NIMMessageTypeText || self.currentMessage.messageType == NIMMessageTypeImage || self.currentMessage.messageType == NIMMessageTypeAudio)){ [array addObject:revokeItem]; } menuController.menuItems = array; [menuController setTargetRect:gesture.view.frame inView:gesture.view.superview]; [menuController setMenuVisible:YES animated:YES]; [UIMenuController sharedMenuController].menuItems=nil; } } - (BOOL)checkDataWith:(long)currentStr { NSDate* date = [NSDate dateWithTimeIntervalSince1970:currentStr]; NSCalendar * calendar = [NSCalendar currentCalendar]; NSCalendarUnit unit =NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; NSDateComponents * cmps = [calendar components:unit fromDate:date toDate:[NSDate date] options:0]; if (cmps.minute <= 2) { return YES; } return NO; } -(void)menuCopyBtnPressed:(UIMenuItem *)menuItem { [UIPasteboard generalPasteboard].string = self.currentMessage.text; } - (void)menuDeleteCopyBtnPressed:(UIMenuItem *)menuItem { NIMDeleteMessageOption * opt = [[NIMDeleteMessageOption alloc] init]; opt.removeFromDB = YES; [[NIMSDK sharedSDK].conversationManager deleteMessage:self.currentMessage option:opt]; if (self.delegate && [self.delegate respondsToSelector:@selector(deleteMessageSuccess:)]) { [self.delegate deleteMessageSuccess:self.currentMessage]; } } - (void)menuRevokeBtnPressed:(UIMenuItem *)menuItem { if (self.currentMessage) { NIMRevokeMessageOption * option = [[NIMRevokeMessageOption alloc] init]; option.shouldBeCounted = NO; [[NIMSDK sharedSDK].chatManager revokeMessage:self.currentMessage option:option completion:^(NSError * _Nullable error) { if (error == nil) { if (self.delegate && [self.delegate respondsToSelector:@selector(revokeMessageSuccess:)]) { [self.delegate revokeMessageSuccess:self.currentMessage]; } } }]; } } -(BOOL)canBecomeFirstResponder { return YES; } -(BOOL)canPerformAction:(SEL)action withSender:(id)sender { if (action == @selector(menuCopyBtnPressed:) || action == @selector(menuDeleteCopyBtnPressed:) || action == @selector(menuRevokeBtnPressed:)) { return YES; } return NO; } - (void)renderWithMessage:(MessageBaseModel *)model { NIMMessage * message = model.message; self.currentModel = model; self.currentMessage = message; NSString * avatarUrl = [[NIMSDK sharedSDK].userManager userInfo:message.from].userInfo.avatarUrl; BOOL isSelf = [[NIMSDK sharedSDK].loginManager.currentAccount isEqualToString:message.from]; if (isSelf) { avatarUrl = [[[XPSkillCardPlayerManager shareInstance] userInfoModel] avatar]; 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:model]; if (self.messageContent) { [self.messageContent removeFromSuperview]; } NSString * classStr = [model cellContent:model]; if (classStr) { if (![self.messageContent isKindOfClass:NSClassFromString(classStr)]) { self.messageContent = [[NSClassFromString(classStr) alloc] init]; if([self.messageContent isKindOfClass:[MessageContentCustomView class]]){ MessageContentCustomView *messageContent = (MessageContentCustomView *)self.messageContent; messageContent.delegate = self; } } } else { NSAssert(classStr != nil, @"message should not be nil"); } [self.messageBackground addSubview:self.messageContent]; //MARK: 不太理解原来的 layout 关系,对开黑卡特殊处理 if ([classStr isEqualToString:@"MessageGameOrderView"]) { [self.messageBackground mas_remakeConstraints:^(MASConstraintMaker *make) { self.messageBackgroundLeft = make.leading.mas_equalTo(self.leftAvatar.mas_trailing).offset(15); self.messageBackgroundRight = make.trailing.mas_equalTo(self.rightAvatar.mas_leading).offset(-15); make.top.mas_equalTo(self).offset(20); make.height.mas_equalTo(98 + MESSAGE_PADDING); }]; [self.messageContent mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.top.trailing.mas_equalTo(self.messageBackground); make.height.mas_equalTo(98 + MESSAGE_PADDING); }]; } else { [self.messageContent mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.top.trailing.bottom.mas_equalTo(self.messageBackground); }]; } [self.messageContent.superview layoutIfNeeded]; if (model.isHiddenAvatar) { self.leftAvatar.hidden= YES; self.rightAvatar.hidden = YES; [self.messageBackground mas_remakeConstraints:^(MASConstraintMaker *make) { make.centerX.mas_equalTo(self.contentView); make.top.mas_equalTo(self.contentView).offset(0); make.height.mas_equalTo(model.height); }]; } [self.messageContent render:model]; } - (void)handleMessageFail:(MessageBaseModel *)model { NIMMessage * message = model.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 || model.isHiddenAvatar; 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.leading.mas_equalTo(self.messageBackground.mas_trailing).offset(10); }]; } else { [self.failButton mas_remakeConstraints:^(MASConstraintMaker *make) { make.size.mas_equalTo(CGSizeMake(20, 20)); make.centerY.mas_equalTo(self.messageBackground); make.trailing.mas_equalTo(self.messageBackground.mas_leading).offset(-10); }]; } } } #pragma mark - MessageContentCustomViewDelegate - (void)updateMessageSuccess:(NIMMessage *)message { if (self.delegate && [self.delegate respondsToSelector:@selector(updateMessageSuccess:)]) { [self.delegate updateMessageSuccess: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 = [DJDKMIMOMColor 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