2023-07-14 18:50:55 +08:00
|
|
|
|
//
|
|
|
|
|
// 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 "StatisticsServiceHelper.h"
|
|
|
|
|
|
|
|
|
|
#import "AttachmentModel.h"
|
|
|
|
|
#import "NetImageView.h"
|
|
|
|
|
#import "DJDKMIMOMColor.h"
|
|
|
|
|
#import "PLTimeUtil.h"
|
|
|
|
|
|
|
|
|
|
#import "YUMIMacroUitls.h"
|
|
|
|
|
#import <Masonry/Masonry.h>
|
|
|
|
|
|
|
|
|
|
@interface MessageCell()<MessageContentCustomViewDelegate>
|
|
|
|
|
|
|
|
|
|
@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<MessageContentProtocol> * 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) {
|
2024-04-11 17:05:27 +08:00
|
|
|
|
make.leading.top.mas_equalTo(self).offset(15);
|
2023-07-14 18:50:55 +08:00
|
|
|
|
make.width.height.mas_equalTo(45);
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
[self.rightAvatar mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
make.top.mas_equalTo(self).offset(15);
|
2024-04-11 17:05:27 +08:00
|
|
|
|
make.trailing.mas_equalTo(self).offset(-15);
|
2023-07-14 18:50:55 +08:00
|
|
|
|
make.width.height.mas_equalTo(45);
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
[self.messageBackground mas_makeConstraints:^(MASConstraintMaker *make) {
|
2024-04-11 17:05:27 +08:00
|
|
|
|
self.messageBackgroundLeft = make.leading.mas_equalTo(self.leftAvatar.mas_trailing).offset(15);
|
|
|
|
|
self.messageBackgroundRight = make.trailing.mas_equalTo(self.rightAvatar.mas_leading).offset(-15);
|
2023-07-14 18:50:55 +08:00
|
|
|
|
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);
|
2024-04-11 17:05:27 +08:00
|
|
|
|
make.leading.mas_equalTo(self.messageBackground.mas_trailing).offset(10);
|
2023-07-14 18:50:55 +08:00
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//并加上几个方法
|
|
|
|
|
|
|
|
|
|
-(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;
|
|
|
|
|
[StatisticsServiceHelper trackEventWithKey:StatisticsServiceEvent_chat_dialogue_copy_click];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (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];
|
|
|
|
|
}
|
|
|
|
|
[StatisticsServiceHelper trackEventWithKey:StatisticsServiceEvent_chat_dialogue_delete_click];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)menuRevokeBtnPressed:(UIMenuItem *)menuItem {
|
|
|
|
|
[StatisticsServiceHelper trackEventWithKey:StatisticsServiceEvent_chat_dialogue_revocation_click];
|
|
|
|
|
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;
|
|
|
|
|
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: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];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
NSAssert(classStr != nil, @"message should not be nil");
|
|
|
|
|
}
|
|
|
|
|
[self.messageBackground addSubview:self.messageContent];
|
|
|
|
|
[self.messageContent mas_makeConstraints:^(MASConstraintMaker *make) {
|
2024-04-11 17:05:27 +08:00
|
|
|
|
make.leading.top.trailing.bottom.mas_equalTo(self.messageBackground);
|
2023-07-14 18:50:55 +08:00
|
|
|
|
}];
|
2024-05-10 14:12:47 +08:00
|
|
|
|
[self.messageContent.superview layoutIfNeeded];
|
2023-07-14 18:50:55 +08:00
|
|
|
|
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);
|
2024-04-11 17:05:27 +08:00
|
|
|
|
make.leading.mas_equalTo(self.messageBackground.mas_trailing).offset(10);
|
2023-07-14 18:50:55 +08:00
|
|
|
|
}];
|
|
|
|
|
} else {
|
|
|
|
|
[self.failButton mas_remakeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
make.size.mas_equalTo(CGSizeMake(20, 20));
|
|
|
|
|
make.centerY.mas_equalTo(self.messageBackground);
|
2024-04-11 17:05:27 +08:00
|
|
|
|
make.trailing.mas_equalTo(self.messageBackground.mas_leading).offset(-10);
|
2023-07-14 18:50:55 +08:00
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#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
|