| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- //
- // TUIVideoMessageCell.m
- // UIKit
- //
- // Created by annidyfeng on 2019/5/30.
- // Copyright © 2023 Tencent. All rights reserved.
- //
- #import "TUIVideoMessageCell.h"
- #import <TIMCommon/TIMDefine.h>
- #import "TUICircleLodingView.h"
- #import "TUIMessageProgressManager.h"
- @interface TUIVideoMessageCell () <TUIMessageProgressManagerDelegate>
- @property(nonatomic, strong) UIView *animateHighlightView;
- @property(nonatomic, strong) TUICircleLodingView *animateCircleView;
- @property(nonatomic, strong) UIImageView *downloadImage;
- @end
- @implementation TUIVideoMessageCell
- - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
- self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
- if (self) {
- _thumb = [[UIImageView alloc] init];
- _thumb.layer.cornerRadius = 5.0;
- [_thumb.layer setMasksToBounds:YES];
- _thumb.contentMode = UIViewContentModeScaleAspectFill;
- _thumb.backgroundColor = [UIColor clearColor];
- [self.bubbleView addSubview:_thumb];
- _thumb.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- CGSize playSize = TVideoMessageCell_Play_Size;
- _play = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, playSize.width, playSize.height)];
- _play.contentMode = UIViewContentModeScaleAspectFit;
- _play.image = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath(@"play_normal")];
- _play.hidden = YES;
- [_thumb addSubview:_play];
- _downloadImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, playSize.width, playSize.height)];
- _downloadImage.contentMode = UIViewContentModeScaleAspectFit;
- _downloadImage.image = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath(@"download")];
- _downloadImage.hidden = YES;
- [_thumb addSubview:_downloadImage];
- _duration = [[UILabel alloc] init];
- _duration.textColor = [UIColor whiteColor];
- _duration.font = [UIFont systemFontOfSize:12];
- [_thumb addSubview:_duration];
- _animateCircleView = [[TUICircleLodingView alloc] initWithFrame:CGRectMake(0, 0, kScale390(40), kScale390(40))];
- _animateCircleView.progress = 0;
- [_thumb addSubview:_animateCircleView];
-
- _progress = [[UILabel alloc] init];
- _progress.textColor = [UIColor whiteColor];
- _progress.font = [UIFont systemFontOfSize:15];
- _progress.textAlignment = NSTextAlignmentCenter;
- _progress.layer.cornerRadius = 5.0;
- _progress.hidden = YES;
- _progress.backgroundColor = TVideoMessageCell_Progress_Color;
- [_progress.layer setMasksToBounds:YES];
- [self.container addSubview:_progress];
- _progress.mm_fill();
- _progress.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- [TUIMessageProgressManager.shareManager addDelegate:self];
- }
- return self;
- }
- - (void)fillWithData:(TUIVideoMessageCellData *)data;
- {
- // set data
- [super fillWithData:data];
- self.videoData = data;
- _thumb.image = nil;
-
- BOOL hasRiskContent = self.messageData.innerMessage.hasRiskContent;
- if (hasRiskContent) {
- self.thumb.image = TIMCommonBundleThemeImage(@"", @"icon_security_strike");
- self.securityStrikeView.textLabel.text = TIMCommonLocalizableString(TUIKitMessageTypeSecurityStrikeImage);
- self.duration.text = @"";
- self.play.hidden = YES;
- self.downloadImage.hidden = YES;
- self.indicator.hidden = YES;
- self.animateCircleView.hidden = YES;
- return;
- }
- if (data.thumbImage == nil) {
- [data downloadThumb];
- }
- if (data.isPlaceHolderCellData) {
- //show placeHolder
- _thumb.backgroundColor = [UIColor grayColor];
- _animateCircleView.progress = (data.videoTranscodingProgress *100);
- self.duration.text = @"";
- self.play.hidden = YES;
- self.downloadImage.hidden = YES;
- self.indicator.hidden = YES;
- self.animateCircleView.hidden = NO;
- @weakify(self);
- [[RACObserve(data, videoTranscodingProgress) takeUntil:self.rac_prepareForReuseSignal] subscribeNext:^(NSNumber *x) {
- // The transcoded animation can display up to 30% at maximum,
- // and the upload progress increases from 30% to 100%.
- @strongify(self);
- double progress = [x doubleValue];
- double factor = 0.3;
- double resultProgress = (progress *100) * factor;
- self.animateCircleView.progress = resultProgress;
- }];
- if (data.thumbImage) {
- self.thumb.image = data.thumbImage;
- }
- // tell constraints they need updating
- [self setNeedsUpdateConstraints];
- // update constraints now so we can animate the change
- [self updateConstraintsIfNeeded];
- [self layoutIfNeeded];
- return;
- }
- @weakify(self);
- [[RACObserve(data, thumbImage) takeUntil:self.rac_prepareForReuseSignal] subscribeNext:^(UIImage *thumbImage) {
- @strongify(self);
- if (thumbImage) {
- self.thumb.image = thumbImage;
- }
- }];
- _duration.text = [NSString stringWithFormat:@"%02ld:%02ld", (long)data.videoItem.duration / 60, (long)data.videoItem.duration % 60];
- self.play.hidden = YES;
- self.downloadImage.hidden = YES;
- self.indicator.hidden = YES;
- if (data.direction == MsgDirectionIncoming) {
- [[[RACObserve(data, thumbProgress) takeUntil:self.rac_prepareForReuseSignal] distinctUntilChanged] subscribeNext:^(NSNumber *x) {
- @strongify(self);
- // Cover download progress callback
- int progress = [x intValue];
- self.progress.text = [NSString stringWithFormat:@"%d%%", progress];
- self.progress.hidden = (progress >= 100 || progress == 0);
- self.animateCircleView.progress = progress;
- if (progress >= 100 || progress == 0) {
- // The progress of cover download is called back and the download video icon is displayed when the cover progress is 100.
- if ([data isVideoExist]) {
- self.play.hidden = NO;
- } else {
- self.downloadImage.hidden = NO;
- }
- } else {
- self.play.hidden = YES;
- self.downloadImage.hidden = YES;
- }
- }];
- // Video resource download progress callback
- [[[RACObserve(data, videoProgress) takeUntil:self.rac_prepareForReuseSignal] distinctUntilChanged] subscribeNext:^(NSNumber *x) {
- @strongify(self);
- int progress = [x intValue];
- self.animateCircleView.progress = progress;
- if (progress >= 100 || progress == 0) {
- self.play.hidden = NO;
- self.animateCircleView.hidden = YES;
- } else {
- self.play.hidden = YES;
- self.downloadImage.hidden = YES;
- self.animateCircleView.hidden = NO;
- }
- }];
- } else {
- if ([data isVideoExist]) {
- [[[RACObserve(data, uploadProgress) takeUntil:self.rac_prepareForReuseSignal] distinctUntilChanged] subscribeNext:^(NSNumber *x) {
- @strongify(self);
- int progress = [x intValue];
- if (data.placeHolderCellData.videoTranscodingProgress > 0) {
- progress = MAX(progress, 30);//the upload progress increases from 30% to 100%.
- }
- self.animateCircleView.progress = progress;
- if (progress >= 100 || progress == 0) {
- [self.indicator stopAnimating];
- self.play.hidden = NO;
- self.animateCircleView.hidden = YES;
- } else {
- [self.indicator startAnimating];
- self.play.hidden = YES;
- self.animateCircleView.hidden = NO;
- }
- }];
- } else {
- [[[RACObserve(data, thumbProgress) takeUntil:self.rac_prepareForReuseSignal] distinctUntilChanged] subscribeNext:^(NSNumber *x) {
- @strongify(self);
- // Cover download progress callback
- int progress = [x intValue];
- self.progress.text = [NSString stringWithFormat:@"%d%%", progress];
- self.progress.hidden = (progress >= 100 || progress == 0);
- self.animateCircleView.progress = progress;
- if (progress >= 100 || progress == 0) {
- // The download video icon is displayed when the cover progress reaches 100
- if ([data isVideoExist]) {
- self.play.hidden = NO;
- } else {
- self.downloadImage.hidden = NO;
- }
- } else {
- self.play.hidden = YES;
- self.downloadImage.hidden = YES;
- }
- }];
- // Video resource download progress callback
- [[[RACObserve(data, videoProgress) takeUntil:self.rac_prepareForReuseSignal] distinctUntilChanged] subscribeNext:^(NSNumber *x) {
- @strongify(self);
- int progress = [x intValue];
- self.animateCircleView.progress = progress;
- if (progress >= 100 || progress == 0) {
- self.play.hidden = NO;
- self.animateCircleView.hidden = YES;
- } else {
- self.play.hidden = YES;
- self.downloadImage.hidden = YES;
- self.animateCircleView.hidden = NO;
- }
- }];
- }
- }
- // tell constraints they need updating
- [self setNeedsUpdateConstraints];
- // update constraints now so we can animate the change
- [self updateConstraintsIfNeeded];
- [self layoutIfNeeded];
- }
- + (BOOL)requiresConstraintBasedLayout {
- return YES;
- }
- // this is Apple's recommended place for adding/updating constraints
- - (void)updateConstraints {
- [super updateConstraints];
- if (self.messageData.messageContainerAppendSize.height > 0) {
- CGFloat topMargin = 10;
- CGFloat tagViewTopMargin = 6;
- CGFloat thumbHeight = self.bubbleView.mm_h - topMargin - self.messageData.messageContainerAppendSize.height - tagViewTopMargin;
- CGSize size = [self.class getContentSize:self.messageData];
- [self.thumb mas_remakeConstraints:^(MASConstraintMaker *make) {
- make.height.mas_equalTo(thumbHeight);
- make.width.mas_equalTo(size.width);
- make.centerX.mas_equalTo(self.bubbleView);
- make.top.mas_equalTo(self.container).mas_offset(topMargin);
- }];
- [self.duration mas_remakeConstraints:^(MASConstraintMaker *make) {
- make.trailing.mas_equalTo(self.thumb.mas_trailing).mas_offset(-2);
- make.width.mas_greaterThanOrEqualTo(20);
- make.height.mas_equalTo(20);
- make.bottom.mas_equalTo(self.thumb.mas_bottom);
- }];
- } else {
- [self.thumb mas_remakeConstraints:^(MASConstraintMaker *make) {
- make.top.mas_equalTo(self.bubbleView).mas_offset(self.messageData.cellLayout.bubbleInsets.top);
- make.bottom.mas_equalTo(self.bubbleView).mas_offset(- self.messageData.cellLayout.bubbleInsets.bottom);
- make.leading.mas_equalTo(self.bubbleView).mas_offset(self.messageData.cellLayout.bubbleInsets.left);
- make.trailing.mas_equalTo(self.bubbleView).mas_offset(- self.messageData.cellLayout.bubbleInsets.right);
- }];
- [self.duration mas_remakeConstraints:^(MASConstraintMaker *make) {
- make.trailing.mas_equalTo(self.thumb.mas_trailing).mas_offset(-2);
- make.width.mas_greaterThanOrEqualTo(20);
- make.height.mas_equalTo(20);
- make.bottom.mas_equalTo(self.thumb.mas_bottom);
- }];
- }
-
-
- BOOL hasRiskContent = self.messageData.innerMessage.hasRiskContent;
- if (hasRiskContent ) {
- [self.thumb mas_remakeConstraints:^(MASConstraintMaker *make) {
- make.top.mas_equalTo(self.bubbleView).mas_offset(12);
- make.size.mas_equalTo(CGSizeMake(150, 150));
- make.centerX.mas_equalTo(self.bubbleView);
- }];
-
- [self.securityStrikeView mas_remakeConstraints:^(MASConstraintMaker *make) {
- make.top.mas_equalTo(self.thumb.mas_bottom);
- make.width.mas_equalTo(self.bubbleView);
- if(self.messageData.messageContainerAppendSize.height>0) {
- make.bottom.mas_equalTo(self.container).mas_offset(-self.messageData.messageContainerAppendSize.height);
- }
- else {
- make.bottom.mas_equalTo(self.container).mas_offset(-12);
- }
- }];
- }
- [self.play mas_remakeConstraints:^(MASConstraintMaker *make) {
- make.size.mas_equalTo(TVideoMessageCell_Play_Size);
- make.center.mas_equalTo(self.thumb);
- }];
- [self.downloadImage mas_remakeConstraints:^(MASConstraintMaker *make) {
- make.size.mas_equalTo(TVideoMessageCell_Play_Size);
- make.center.mas_equalTo(self.thumb);
- }];
- [self.animateCircleView mas_remakeConstraints:^(MASConstraintMaker *make) {
- make.center.mas_equalTo(self.thumb);
- make.size.mas_equalTo(CGSizeMake(kScale390(40), kScale390(40)));
- }];
- }
- - (void)layoutSubviews {
- [super layoutSubviews];
- }
- - (void)highlightWhenMatchKeyword:(NSString *)keyword {
- if (keyword) {
- if (self.highlightAnimating) {
- return;
- }
- [self animate:3];
- }
- }
- - (void)animate:(int)times {
- times--;
- if (times < 0) {
- [self.animateHighlightView removeFromSuperview];
- self.highlightAnimating = NO;
- return;
- }
- self.highlightAnimating = YES;
- self.animateHighlightView.frame = self.container.bounds;
- self.animateHighlightView.alpha = 0.1;
- [self.container addSubview:self.animateHighlightView];
- [UIView animateWithDuration:0.25
- animations:^{
- self.animateHighlightView.alpha = 0.5;
- }
- completion:^(BOOL finished) {
- [UIView animateWithDuration:0.25
- animations:^{
- self.animateHighlightView.alpha = 0.1;
- }
- completion:^(BOOL finished) {
- if (!self.videoData.highlightKeyword) {
- [self animate:0];
- return;
- }
- [self animate:times];
- }];
- }];
- }
- - (UIView *)animateHighlightView {
- if (_animateHighlightView == nil) {
- _animateHighlightView = [[UIView alloc] init];
- _animateHighlightView.backgroundColor = [UIColor orangeColor];
- }
- return _animateHighlightView;
- }
- #pragma mark - TUIMessageProgressManagerDelegate
- - (void)onUploadProgress:(NSString *)msgID progress:(NSInteger)progress {
- if (![msgID isEqualToString:self.videoData.msgID]) {
- return;
- }
- if (self.videoData.direction == MsgDirectionOutgoing) {
- self.videoData.uploadProgress = progress;
- }
- }
- #pragma mark - TUIMessageCellProtocol
- + (CGSize)getContentSize:(TUIMessageCellData *)data {
- NSAssert([data isKindOfClass:TUIVideoMessageCellData.class], @"data must be kind of TUIVideoMessageCellData");
- TUIVideoMessageCellData *videoCellData = (TUIVideoMessageCellData *)data;
- CGSize size = CGSizeZero;
- BOOL isDir = NO;
- if (![videoCellData.snapshotPath isEqualToString:@""] && [[NSFileManager defaultManager] fileExistsAtPath:videoCellData.snapshotPath isDirectory:&isDir]) {
- if (!isDir) {
- size = [UIImage imageWithContentsOfFile:videoCellData.snapshotPath].size;
- }
- } else {
- size = videoCellData.snapshotItem.size;
- }
- if (CGSizeEqualToSize(size, CGSizeZero)) {
- return size;
- }
- if (size.height > size.width) {
- size.width = size.width / size.height * TVideoMessageCell_Image_Height_Max;
- size.height = TVideoMessageCell_Image_Height_Max;
- } else {
- size.height = size.height / size.width * TVideoMessageCell_Image_Width_Max;
- size.width = TVideoMessageCell_Image_Width_Max;
- }
- BOOL hasRiskContent = videoCellData.innerMessage.hasRiskContent;
- if (hasRiskContent) {
- CGFloat bubbleTopMargin = 12;
- CGFloat bubbleBottomMargin = 12;
- size.height = MAX(size.height, 150);// width must more than TIMCommonBundleThemeImage(@"", @"icon_security_strike");
- size.width = MAX(size.width, 200);// width must more than TIMCommonLocalizableString(TUIKitMessageTypeSecurityStrike)
- size.height += bubbleTopMargin;
- size.height += kTUISecurityStrikeViewTopLineMargin;
- size.height += kTUISecurityStrikeViewTopLineToBottom;
- size.height += bubbleBottomMargin;
- }
- return size;
- }
- @end
|