|
@@ -46,6 +46,14 @@ static const CGFloat kMediaCornerRadius = 4.0f;
|
|
|
@property (nonatomic, strong) UILabel * readStateLbl;
|
|
@property (nonatomic, strong) UILabel * readStateLbl;
|
|
|
@property (nonatomic, strong) UIButton * batchStateBtn;
|
|
@property (nonatomic, strong) UIButton * batchStateBtn;
|
|
|
|
|
|
|
|
|
|
+// 发送进度圆环
|
|
|
|
|
+@property (nonatomic, strong) CAShapeLayer *progressLayer;
|
|
|
|
|
+@property (nonatomic, strong) CAShapeLayer *progressBackgroundLayer;
|
|
|
|
|
+@property (nonatomic, strong) UIView *progressContainerView;
|
|
|
|
|
+
|
|
|
|
|
+// 发送失败按钮
|
|
|
|
|
+@property (nonatomic, strong) UIButton *resendButton;
|
|
|
|
|
+
|
|
|
// 内容视图
|
|
// 内容视图
|
|
|
@property (nonatomic, strong) UILabel *textLbl;
|
|
@property (nonatomic, strong) UILabel *textLbl;
|
|
|
@property (nonatomic, strong) UIImageView *imageContentView;
|
|
@property (nonatomic, strong) UIImageView *imageContentView;
|
|
@@ -62,7 +70,7 @@ static const CGFloat kMediaCornerRadius = 4.0f;
|
|
|
@property (nonatomic, strong) UILabel * deleateLbl;
|
|
@property (nonatomic, strong) UILabel * deleateLbl;
|
|
|
@property (nonatomic, strong) UILabel * quoteLbl;
|
|
@property (nonatomic, strong) UILabel * quoteLbl;
|
|
|
|
|
|
|
|
-@property (nonatomic, strong) UILabel * jinduLbl;
|
|
|
|
|
|
|
+//@property (nonatomic, strong) UILabel * jinduLbl;
|
|
|
|
|
|
|
|
@property (strong, nonatomic) AVPlayer *player;
|
|
@property (strong, nonatomic) AVPlayer *player;
|
|
|
@property (strong, nonatomic) AVPlayerViewController *playerViewController;
|
|
@property (strong, nonatomic) AVPlayerViewController *playerViewController;
|
|
@@ -89,6 +97,24 @@ static const CGFloat kMediaCornerRadius = 4.0f;
|
|
|
return self;
|
|
return self;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+- (void)layoutSubviews {
|
|
|
|
|
+ [super layoutSubviews];
|
|
|
|
|
+
|
|
|
|
|
+ if (_currentContentView && _messageModel.isSender) {
|
|
|
|
|
+ CGFloat offset = _messageModel.messageType == ChatMessageTypeFile ? 16 : 8;
|
|
|
|
|
+ [_progressContainerView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
+ make.width.height.mas_equalTo(30);
|
|
|
|
|
+ make.right.equalTo(_currentContentView.mas_left).offset(-offset);
|
|
|
|
|
+ make.centerY.equalTo(_currentContentView);
|
|
|
|
|
+ }];
|
|
|
|
|
+
|
|
|
|
|
+ [_resendButton mas_remakeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
+ make.right.equalTo(_currentContentView.mas_left).offset(-8);
|
|
|
|
|
+ make.centerY.equalTo(_currentContentView);
|
|
|
|
|
+ }];
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
|
|
|
-(void)initAlllSubviews{
|
|
-(void)initAlllSubviews{
|
|
|
//复选框
|
|
//复选框
|
|
@@ -146,9 +172,117 @@ static const CGFloat kMediaCornerRadius = 4.0f;
|
|
|
[self setupEventContentView];
|
|
[self setupEventContentView];
|
|
|
[self setupCallbackContentView];
|
|
[self setupCallbackContentView];
|
|
|
[self setupdeleateContentView];
|
|
[self setupdeleateContentView];
|
|
|
|
|
+
|
|
|
|
|
+ // 初始化进度圆环
|
|
|
|
|
+ [self setupProgressView];
|
|
|
|
|
+
|
|
|
|
|
+ // 初始化发送失败按钮
|
|
|
|
|
+ [self setupResendButton];
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+#pragma mark - 进度圆环配置
|
|
|
|
|
+- (void)setupProgressView {
|
|
|
|
|
+ // 容器视图
|
|
|
|
|
+ _progressContainerView = [[UIView alloc] init];
|
|
|
|
|
+ _progressContainerView.hidden = YES;
|
|
|
|
|
+ [self.contentView addSubview:_progressContainerView];
|
|
|
|
|
+
|
|
|
|
|
+ // 圆环尺寸
|
|
|
|
|
+ CGFloat size = 30.0f;
|
|
|
|
|
+ CGFloat lineWidth = 2.0f;
|
|
|
|
|
+ CGRect circleFrame = CGRectMake(0, 0, size, size);
|
|
|
|
|
+ UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(size/2, size/2)
|
|
|
|
|
+ radius:(size - lineWidth) / 2
|
|
|
|
|
+ startAngle:-M_PI_2
|
|
|
|
|
+ endAngle:M_PI_2 * 3
|
|
|
|
|
+ clockwise:YES];
|
|
|
|
|
+
|
|
|
|
|
+ // 背景圆环
|
|
|
|
|
+ _progressBackgroundLayer = [CAShapeLayer layer];
|
|
|
|
|
+ _progressBackgroundLayer.path = circlePath.CGPath;
|
|
|
|
|
+ _progressBackgroundLayer.fillColor = [UIColor clearColor].CGColor;
|
|
|
|
|
+ _progressBackgroundLayer.strokeColor = [UIColor colorWithWhite:1.0 alpha:0.3].CGColor;
|
|
|
|
|
+ _progressBackgroundLayer.lineWidth = lineWidth;
|
|
|
|
|
+ _progressBackgroundLayer.frame = circleFrame;
|
|
|
|
|
+ [_progressContainerView.layer addSublayer:_progressBackgroundLayer];
|
|
|
|
|
+
|
|
|
|
|
+ // 进度圆环
|
|
|
|
|
+ _progressLayer = [CAShapeLayer layer];
|
|
|
|
|
+ _progressLayer.path = circlePath.CGPath;
|
|
|
|
|
+ _progressLayer.fillColor = [UIColor clearColor].CGColor;
|
|
|
|
|
+ _progressLayer.strokeColor = [UIColor whiteColor].CGColor;
|
|
|
|
|
+ _progressLayer.lineWidth = lineWidth;
|
|
|
|
|
+ _progressLayer.lineCap = kCALineCapRound;
|
|
|
|
|
+ _progressLayer.strokeEnd = 0.0f;
|
|
|
|
|
+ _progressLayer.frame = circleFrame;
|
|
|
|
|
+ [_progressContainerView.layer addSublayer:_progressLayer];
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 更新进度圆环
|
|
|
|
|
+- (void)updateProgress:(CGFloat)progress {
|
|
|
|
|
+ if (progress < 0) progress = 0;
|
|
|
|
|
+ if (progress > 1) progress = 1;
|
|
|
|
|
+
|
|
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
+ self.progressLayer.strokeEnd = progress;
|
|
|
|
|
+
|
|
|
|
|
+// // 如果进度完成,隐藏圆环
|
|
|
|
|
+// if (progress >= 1.0) {
|
|
|
|
|
+// self.progressContainerView.hidden = YES;
|
|
|
|
|
+// }
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 显示进度圆环
|
|
|
|
|
+- (void)showProgressView {
|
|
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
+ self.progressContainerView.hidden = NO;
|
|
|
|
|
+ self.progressLayer.strokeEnd = 0.0f;
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 隐藏进度圆环
|
|
|
|
|
+- (void)hideProgressView {
|
|
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
+ self.progressContainerView.hidden = YES;
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#pragma mark - 发送失败按钮配置
|
|
|
|
|
+- (void)setupResendButton {
|
|
|
|
|
+ _resendButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
|
|
|
+ [_resendButton setImage:[UIImage imageNamed:@"icon_resend"] forState:UIControlStateNormal];
|
|
|
|
|
+ _resendButton.hidden = YES;
|
|
|
|
|
+ [_resendButton addTarget:self action:@selector(handleResendButtonTap) forControlEvents:UIControlEventTouchUpInside];
|
|
|
|
|
+ [self.contentView addSubview:_resendButton];
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 显示重发按钮
|
|
|
|
|
+- (void)showResendButton {
|
|
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
+ self.resendButton.hidden = NO;
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 隐藏重发按钮
|
|
|
|
|
+- (void)hideResendButton {
|
|
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
+ self.resendButton.hidden = YES;
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 重发按钮点击事件
|
|
|
|
|
+- (void)handleResendButtonTap {
|
|
|
|
|
+ NSLog(@"点击重发按钮: msgId=%@", _messageModel.msgId);
|
|
|
|
|
+
|
|
|
|
|
+ // 触发重发回调
|
|
|
|
|
+ if (self.resendMessageBlock) {
|
|
|
|
|
+ self.resendMessageBlock(_messageModel);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
#pragma mark - 内容视图配置
|
|
#pragma mark - 内容视图配置
|
|
|
- (void)setupTextContentView {
|
|
- (void)setupTextContentView {
|
|
|
_textLbl = [UILabel new];
|
|
_textLbl = [UILabel new];
|
|
@@ -232,25 +366,6 @@ static const CGFloat kMediaCornerRadius = 4.0f;
|
|
|
make.width.height.mas_equalTo(40);
|
|
make.width.height.mas_equalTo(40);
|
|
|
}];
|
|
}];
|
|
|
|
|
|
|
|
-
|
|
|
|
|
- _jinduLbl = [UILabel new];
|
|
|
|
|
- [_videoContentView addSubview:_jinduLbl];
|
|
|
|
|
- _jinduLbl.alpha = 0;
|
|
|
|
|
- _jinduLbl.numberOfLines = 1;
|
|
|
|
|
- _jinduLbl.font = SYSFONT(16);
|
|
|
|
|
- _jinduLbl.textColor = UIColor.whiteColor;
|
|
|
|
|
- _jinduLbl.layer.cornerRadius = 20.f;
|
|
|
|
|
- _jinduLbl.layer.masksToBounds = YES;
|
|
|
|
|
- _jinduLbl.textAlignment = NSTextAlignmentCenter;
|
|
|
|
|
- _jinduLbl.backgroundColor =[UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
|
|
|
|
|
- _jinduLbl.text = @"99";
|
|
|
|
|
- [_jinduLbl mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
- make.left.equalTo(_videoContentView).offset(8);
|
|
|
|
|
- make.top.equalTo(_videoContentView).offset(8);
|
|
|
|
|
- make.width.height.mas_equalTo(40);
|
|
|
|
|
- }];
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
[self.contentView addSubview:_videoContentView];
|
|
[self.contentView addSubview:_videoContentView];
|
|
|
|
|
|
|
|
// 添加点击手势
|
|
// 添加点击手势
|
|
@@ -505,6 +620,9 @@ static const CGFloat kMediaCornerRadius = 4.0f;
|
|
|
//长按事件
|
|
//长按事件
|
|
|
[self setupLongPressEvent];
|
|
[self setupLongPressEvent];
|
|
|
|
|
|
|
|
|
|
+ // 配置发送进度
|
|
|
|
|
+ [self setupSendingProgress];
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
#pragma mark - 批量状态
|
|
#pragma mark - 批量状态
|
|
|
- (void)setBatchState:(BOOL)batchState{
|
|
- (void)setBatchState:(BOOL)batchState{
|
|
@@ -618,6 +736,52 @@ static const CGFloat kMediaCornerRadius = 4.0f;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// 配置发送进度
|
|
|
|
|
+- (void)setupSendingProgress {
|
|
|
|
|
+ // 只有发送方才显示进度或失败按钮
|
|
|
|
|
+ if (!_messageModel.isSender || !_messageModel.isUploadFile) {
|
|
|
|
|
+ [self hideProgressView];
|
|
|
|
|
+ [self hideResendButton];
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 根据消息状态显示进度或失败按钮
|
|
|
|
|
+ switch (_messageModel.messageSendStatus) {
|
|
|
|
|
+ case MessageSending: {
|
|
|
|
|
+ // 发送中,显示进度圆环,隐藏失败按钮
|
|
|
|
|
+ [self showProgressView];
|
|
|
|
|
+ [self hideResendButton];
|
|
|
|
|
+
|
|
|
|
|
+ // 如果有上传进度回调,监听进度
|
|
|
|
|
+ weakSelf(self);
|
|
|
|
|
+ if (_messageModel.isUploadFile) {
|
|
|
|
|
+ _messageModel.uploadPersentChange = ^(NSInteger persent, NSInteger localtime) {
|
|
|
|
|
+ if (localtime == weakself.messageModel.localtime) {
|
|
|
|
|
+ CGFloat progress = persent / 100.0f;
|
|
|
|
|
+ [weakself updateProgress:progress];
|
|
|
|
|
+ if (progress >= 1) {
|
|
|
|
|
+ weakself.messageModel.messageSendStatus = MessageSent;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ case MessageSendFail: {
|
|
|
|
|
+ // 发送失败,显示失败按钮,隐藏进度圆环
|
|
|
|
|
+ [self hideProgressView];
|
|
|
|
|
+ [self showResendButton];
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ case MessageSent:
|
|
|
|
|
+ // 其他状态隐藏进度和失败按钮
|
|
|
|
|
+ [self hideProgressView];
|
|
|
|
|
+ [self hideResendButton];
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
- (void)longPressEvent:(UILongPressGestureRecognizer *)gestureRecognizer {
|
|
- (void)longPressEvent:(UILongPressGestureRecognizer *)gestureRecognizer {
|
|
|
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
|
|
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
|
|
|
NSLog(@"长按事件开始");
|
|
NSLog(@"长按事件开始");
|
|
@@ -901,44 +1065,6 @@ static const CGFloat kMediaCornerRadius = 4.0f;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
- _messageModel.uploadPersentChange = ^(NSInteger index,NSInteger localtime) {
|
|
|
|
|
-
|
|
|
|
|
- if(localtime==weakself.messageModel.localtime){
|
|
|
|
|
- if(index>=100){
|
|
|
|
|
- dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
- if(weakself.jinduLbl){
|
|
|
|
|
- weakself.jinduLbl.alpha = 0;
|
|
|
|
|
- weakself.loadingImg.alpha = 0;
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- else{
|
|
|
|
|
- dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
- if(weakself.jinduLbl){
|
|
|
|
|
- if(weakself.loadingImg.alpha!=1||!weakself.loadingImg.image){
|
|
|
|
|
- NSString *gifPath = [[NSBundle mainBundle] pathForResource:@"load" ofType:@"gif"];
|
|
|
|
|
- NSData *gifData = [NSData dataWithContentsOfFile:gifPath];
|
|
|
|
|
- UIImage *placeholder = [UIImage sd_imageWithGIFData:gifData];
|
|
|
|
|
- weakself.loadingImg.image = placeholder;
|
|
|
|
|
- weakself.loadingImg.alpha = 1;
|
|
|
|
|
- }
|
|
|
|
|
- weakself.jinduLbl.alpha = 1;
|
|
|
|
|
- weakself.jinduLbl.text = [NSString stringWithFormat:@"%ld",(long)index];
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else{
|
|
|
|
|
- dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
- if(weakself.jinduLbl){
|
|
|
|
|
- weakself.jinduLbl.alpha = 0;
|
|
|
|
|
- weakself.loadingImg.alpha = 0;
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
_currentContentView = _videoContentView;
|
|
_currentContentView = _videoContentView;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1150,27 +1276,12 @@ static const CGFloat kMediaCornerRadius = 4.0f;
|
|
|
make.top.mas_equalTo(self.avatarImageView);
|
|
make.top.mas_equalTo(self.avatarImageView);
|
|
|
}];
|
|
}];
|
|
|
|
|
|
|
|
- if (_messageModel.messageType == ChatMessageTypeImage || _messageModel.messageType == ChatMessageTypeVideo) {
|
|
|
|
|
|
|
+ if (_currentContentView) {
|
|
|
[_readStateLbl mas_remakeConstraints:^(MASConstraintMaker *make) {
|
|
[_readStateLbl mas_remakeConstraints:^(MASConstraintMaker *make) {
|
|
|
- make.right.mas_equalTo(self.contentView).offset(-30);
|
|
|
|
|
|
|
+ make.left.mas_equalTo(_currentContentView.mas_right).offset(6);
|
|
|
make.height.mas_equalTo(14);
|
|
make.height.mas_equalTo(14);
|
|
|
- make.top.mas_equalTo(self.currentContentView.mas_bottom).offset(2);
|
|
|
|
|
|
|
+ make.bottom.mas_equalTo(_currentContentView.mas_bottom);
|
|
|
}];
|
|
}];
|
|
|
- }else{
|
|
|
|
|
- if (!_quoteLbl.hidden) {
|
|
|
|
|
- [_readStateLbl mas_remakeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
- make.right.mas_equalTo(self.contentView).offset(-30);
|
|
|
|
|
- make.height.mas_equalTo(14);
|
|
|
|
|
- make.top.mas_equalTo(self.quoteLbl.mas_bottom);
|
|
|
|
|
- }];
|
|
|
|
|
- }else{
|
|
|
|
|
- [_readStateLbl mas_remakeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
- make.right.mas_equalTo(self.contentView).offset(-30);
|
|
|
|
|
- make.height.mas_equalTo(14);
|
|
|
|
|
- make.top.mas_equalTo(self.bubbleImageView.mas_bottom);
|
|
|
|
|
- }];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
[_avatarImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
|
[_avatarImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|