TUIVideoCollectionCell.m 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. // Created by Tencent on 2023/06/09.
  2. // Copyright © 2023 Tencent. All rights reserved.
  3. #import "TUIVideoCollectionCell.h"
  4. #import <TIMCommon/TIMDefine.h>
  5. #import "ReactiveObjC/ReactiveObjC.h"
  6. #import "TUICircleLodingView.h"
  7. @import MediaPlayer;
  8. @import AVFoundation;
  9. @import AVKit;
  10. @interface TUIVideoCollectionCellScrollView : UIScrollView <UIScrollViewDelegate>
  11. @property(nonatomic, strong) UIView *videoView;
  12. @property(assign, nonatomic) CGFloat videoViewNormalWidth;
  13. @property(assign, nonatomic) CGFloat videoViewNormalHeight;
  14. - (void)pictureZoomWithScale:(CGFloat)zoomScale;
  15. @end
  16. @implementation TUIVideoCollectionCellScrollView
  17. - (id)initWithFrame:(CGRect)frame {
  18. self = [super initWithFrame:frame];
  19. if (self) {
  20. self.delegate = self;
  21. self.minimumZoomScale = 1.0f;
  22. self.maximumZoomScale = 2.0f;
  23. _videoViewNormalHeight = frame.size.height;
  24. _videoViewNormalWidth = frame.size.width;
  25. self.videoView = [[UIView alloc] initWithFrame:frame];
  26. [self addSubview:self.videoView];
  27. if (@available(iOS 11.0, *)) {
  28. self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
  29. } else {
  30. // Fallback on earlier versions
  31. }
  32. }
  33. return self;
  34. }
  35. - (void)drawRect:(CGRect)rect {
  36. [super drawRect:rect];
  37. }
  38. #pragma mark-- Help Methods
  39. - (void)pictureZoomWithScale:(CGFloat)zoomScale {
  40. CGFloat imageScaleWidth = zoomScale * self.videoViewNormalWidth;
  41. CGFloat imageScaleHeight = zoomScale * self.videoViewNormalHeight;
  42. CGFloat imageX = 0;
  43. CGFloat imageY = 0;
  44. if (imageScaleWidth < self.frame.size.width) {
  45. imageX = floorf((self.frame.size.width - imageScaleWidth) / 2.0);
  46. }
  47. if (imageScaleHeight < self.frame.size.height) {
  48. imageY = floorf((self.frame.size.height - imageScaleHeight) / 2.0);
  49. }
  50. self.videoView.frame = CGRectMake(imageX, imageY, imageScaleWidth, imageScaleHeight);
  51. self.contentSize = CGSizeMake(imageScaleWidth, imageScaleHeight);
  52. }
  53. #pragma mark-- Setter
  54. - (void)setVideoViewNormalWidth:(CGFloat)videoViewNormalWidth {
  55. _videoViewNormalWidth = videoViewNormalWidth;
  56. self.videoView.frame = CGRectMake(0, 0, _videoViewNormalWidth, _videoViewNormalHeight);
  57. self.videoView.center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);
  58. }
  59. - (void)setVideoViewNormalHeight:(CGFloat)videoViewNormalHeight {
  60. _videoViewNormalHeight = videoViewNormalHeight;
  61. self.videoView.frame = CGRectMake(0, 0, _videoViewNormalWidth, _videoViewNormalHeight);
  62. self.videoView.center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);
  63. }
  64. #pragma mark-- UIScrollViewDelegate
  65. // Returns the view control that needs to be zoomed. During zooming
  66. - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
  67. return self.videoView;
  68. }
  69. // BeginZooming
  70. - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {
  71. NSLog(@"BeginZooming");
  72. }
  73. // EndZooming
  74. - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {
  75. NSLog(@"EndZooming");
  76. }
  77. // zoom
  78. - (void)scrollViewDidZoom:(UIScrollView *)scrollView {
  79. CGFloat imageScaleWidth = scrollView.zoomScale * self.videoViewNormalWidth;
  80. CGFloat imageScaleHeight = scrollView.zoomScale * self.videoViewNormalHeight;
  81. CGFloat imageX = 0;
  82. CGFloat imageY = 0;
  83. if (imageScaleWidth < self.frame.size.width) {
  84. imageX = floorf((self.frame.size.width - imageScaleWidth) / 2.0);
  85. }
  86. if (imageScaleHeight < self.frame.size.height) {
  87. imageY = floorf((self.frame.size.height - imageScaleHeight) / 2.0);
  88. }
  89. self.videoView.frame = CGRectMake(imageX, imageY, imageScaleWidth, imageScaleHeight);
  90. }
  91. @end
  92. @interface TUIVideoCollectionCell ()
  93. @property(nonatomic, strong) TUIVideoCollectionCellScrollView *scrollView;
  94. @property(nonatomic, strong) UILabel *duration;
  95. @property(nonatomic, strong) UILabel *playTime;
  96. @property(nonatomic, strong) UISlider *playProcess;
  97. @property(nonatomic, strong) UIButton *mainPlayBtn;
  98. @property(nonatomic, strong) UIButton *mainDownloadBtn;
  99. @property(nonatomic, strong) UIButton *playBtn;
  100. @property(nonatomic, strong) UIButton *closeBtn;
  101. @property(nonatomic, strong) TUICircleLodingView *animateCircleView;
  102. @property(nonatomic, strong) AVPlayer *player;
  103. @property(nonatomic, strong) AVPlayerLayer *playerLayer;
  104. @property(nonatomic, strong) NSString *videoPath;
  105. @property(nonatomic, strong) NSURL *videoUrl;
  106. @property(nonatomic, assign) BOOL isPlay;
  107. @property(nonatomic, assign) BOOL isSaveVideo;
  108. @property(nonatomic, strong) TUIVideoMessageCellData *videoData;
  109. @end
  110. @implementation TUIVideoCollectionCell
  111. - (id)initWithFrame:(CGRect)frame {
  112. self = [super initWithFrame:frame];
  113. if (self) {
  114. [self setupViews];
  115. [self setupRotaionNotifications];
  116. }
  117. return self;
  118. }
  119. - (void)setupRotaionNotifications {
  120. if (@available(iOS 16.0, *)) {
  121. [[NSNotificationCenter defaultCenter] addObserver:self
  122. selector:@selector(onDeviceOrientationChange:)
  123. name:TUIMessageMediaViewDeviceOrientationChangeNotification
  124. object:nil];
  125. } else {
  126. [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
  127. [[NSNotificationCenter defaultCenter] addObserver:self
  128. selector:@selector(onDeviceOrientationChange:)
  129. name:UIDeviceOrientationDidChangeNotification
  130. object:nil];
  131. }
  132. }
  133. - (void)setupViews {
  134. self.scrollView = [[TUIVideoCollectionCellScrollView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)];
  135. [self addSubview:self.scrollView];
  136. self.imageView = [[UIImageView alloc] init];
  137. self.imageView.layer.cornerRadius = 5.0;
  138. [self.imageView.layer setMasksToBounds:YES];
  139. self.imageView.contentMode = UIViewContentModeScaleAspectFit;
  140. self.imageView.backgroundColor = [UIColor clearColor];
  141. [self.scrollView.videoView addSubview:self.imageView];
  142. self.imageView.mm_fill();
  143. self.imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  144. self.mainPlayBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  145. self.mainPlayBtn.contentMode = UIViewContentModeScaleToFill;
  146. [self.mainPlayBtn setImage:TUIChatCommonBundleImage(@"video_play_big") forState:UIControlStateNormal];
  147. [self.mainPlayBtn addTarget:self action:@selector(onPlayBtnClick) forControlEvents:UIControlEventTouchUpInside];
  148. [self addSubview:self.mainPlayBtn];
  149. self.mainDownloadBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  150. self.mainDownloadBtn.contentMode = UIViewContentModeScaleToFill;
  151. [self.mainDownloadBtn setImage:[[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath(@"download")] forState:UIControlStateNormal];
  152. self.mainDownloadBtn.hidden = YES;
  153. [self.mainDownloadBtn addTarget:self action:@selector(mainDownloadBtnClick) forControlEvents:UIControlEventTouchUpInside];
  154. [self addSubview:self.mainDownloadBtn];
  155. self.animateCircleView = [[TUICircleLodingView alloc] initWithFrame:CGRectMake(0, 0, kScale390(40), kScale390(40))];
  156. self.animateCircleView.progress = 0;
  157. self.animateCircleView.hidden = YES;
  158. [self addSubview:_animateCircleView];
  159. self.playBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  160. self.playBtn.contentMode = UIViewContentModeScaleToFill;
  161. [self.playBtn setImage:TUIChatCommonBundleImage(@"video_play") forState:UIControlStateNormal];
  162. [self.playBtn addTarget:self action:@selector(onPlayBtnClick) forControlEvents:UIControlEventTouchUpInside];
  163. [self addSubview:self.playBtn];
  164. self.closeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  165. self.closeBtn.contentMode = UIViewContentModeScaleToFill;
  166. [self.closeBtn setImage:TUIChatCommonBundleImage(@"video_close") forState:UIControlStateNormal];
  167. [self.closeBtn addTarget:self action:@selector(onCloseBtnClick) forControlEvents:UIControlEventTouchUpInside];
  168. [self addSubview:self.closeBtn];
  169. self.downloadBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  170. self.downloadBtn.contentMode = UIViewContentModeScaleToFill;
  171. [self.downloadBtn setImage:TUIChatCommonBundleImage(@"download") forState:UIControlStateNormal];
  172. [self.downloadBtn addTarget:self action:@selector(onDownloadBtnClick) forControlEvents:UIControlEventTouchUpInside];
  173. [self addSubview:self.downloadBtn];
  174. self.playTime = [[UILabel alloc] init];
  175. self.playTime.textColor = [UIColor whiteColor];
  176. self.playTime.font = [UIFont systemFontOfSize:12];
  177. self.playTime.text = @"00:00";
  178. [self addSubview:self.playTime];
  179. self.duration = [[UILabel alloc] init];
  180. self.duration.textColor = [UIColor whiteColor];
  181. self.duration.font = [UIFont systemFontOfSize:12];
  182. self.duration.text = @"00:00";
  183. [self addSubview:self.duration];
  184. self.playProcess = [[UISlider alloc] init];
  185. self.playProcess.minimumValue = 0;
  186. self.playProcess.maximumValue = 1;
  187. self.playProcess.minimumTrackTintColor = [UIColor whiteColor];
  188. [self.playProcess addTarget:self action:@selector(onSliderValueChangedBegin:) forControlEvents:UIControlEventTouchDown];
  189. [self.playProcess addTarget:self action:@selector(onSliderValueChanged:) forControlEvents:UIControlEventTouchUpInside];
  190. [self addSubview:self.playProcess];
  191. }
  192. - (void)fillWithData:(TUIVideoMessageCellData *)data;
  193. {
  194. [super fillWithData:data];
  195. self.videoData = data;
  196. self.isSaveVideo = NO;
  197. BOOL hasRiskContent = data.innerMessage.hasRiskContent;
  198. if (hasRiskContent) {
  199. self.imageView.image = TIMCommonBundleThemeImage(@"", @"icon_security_strike");
  200. for (UIView *subview in self.subviews) {
  201. if (subview != self.scrollView && subview != self.closeBtn){
  202. subview.hidden = YES;
  203. }
  204. }
  205. return;
  206. }
  207. CGFloat duration = data.videoItem.duration;
  208. self.duration.text = [NSString stringWithFormat:@"%.2d:%.2d", (int)duration / 60, (int)duration % 60];
  209. self.imageView.image = nil;
  210. if (data.thumbImage == nil) {
  211. [data downloadThumb];
  212. }
  213. @weakify(self);
  214. [[RACObserve(data, thumbImage) takeUntil:self.rac_prepareForReuseSignal] subscribeNext:^(UIImage *thumbImage) {
  215. @strongify(self);
  216. if (thumbImage) {
  217. self.imageView.image = thumbImage;
  218. }
  219. }];
  220. if (![self.videoData isVideoExist]) {
  221. self.mainDownloadBtn.hidden = NO;
  222. self.mainPlayBtn.hidden = YES;
  223. self.animateCircleView.hidden = YES;
  224. } else {
  225. /**
  226. *
  227. * Downloaded videos can be played directly using local video files
  228. */
  229. self.videoPath = self.videoData.videoPath;
  230. if (self.videoPath) {
  231. [self addPlayer:[NSURL fileURLWithPath:self.videoPath]];
  232. }
  233. }
  234. [[[RACObserve(self.videoData, videoProgress) takeUntil:self.rac_prepareForReuseSignal] distinctUntilChanged] subscribeNext:^(id _Nullable x) {
  235. @strongify(self);
  236. int progress = [x intValue];
  237. if (progress == 100) {
  238. self.animateCircleView.progress = 99;
  239. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  240. self.animateCircleView.progress = 100;
  241. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  242. self.animateCircleView.progress = 0;
  243. self.mainDownloadBtn.hidden = YES;
  244. self.animateCircleView.hidden = YES;
  245. self.mainPlayBtn.hidden = NO;
  246. });
  247. });
  248. } else if (progress > 1 && progress < 100) {
  249. self.animateCircleView.progress = progress;
  250. self.mainDownloadBtn.hidden = YES;
  251. self.animateCircleView.hidden = NO;
  252. } else {
  253. self.animateCircleView.progress = progress;
  254. }
  255. }];
  256. [[[RACObserve(self.videoData, videoPath) filter:^BOOL(NSString *path) {
  257. return [path length] > 0;
  258. }] take:1] subscribeNext:^(NSString *path) {
  259. @strongify(self);
  260. self.videoPath = path;
  261. if (self.isSaveVideo) {
  262. [self saveVideo];
  263. }
  264. self.animateCircleView.hidden = YES;
  265. [self addPlayer:[NSURL fileURLWithPath:self.videoPath]];
  266. }];
  267. }
  268. - (void)layoutSubviews {
  269. [super layoutSubviews];
  270. [self.mainDownloadBtn sizeToFit];
  271. self.mainDownloadBtn.mm_width(65).mm_height(65).mm__centerX(self.mm_w / 2).mm__centerY(self.mm_h / 2);
  272. self.mainDownloadBtn.layer.cornerRadius = (self.mainDownloadBtn.mm_h * 0.5);
  273. self.animateCircleView.tui_mm_center();
  274. self.mainPlayBtn.mm_width(65).mm_height(65).mm__centerX(self.mm_w / 2).mm__centerY(self.mm_h / 2);
  275. self.closeBtn.mm_width(31).mm_height(31).mm_left(16).mm_bottom(47);
  276. self.downloadBtn.mm_width(31).mm_height(31).mm_right(16).mm_bottom(48);
  277. self.playBtn.mm_width(30).mm_height(30).mm_left(32).mm_bottom(108);
  278. self.playTime.mm_width(40).mm_height(21).mm_left(self.playBtn.mm_maxX + 12).mm__centerY(self.playBtn.mm_centerY);
  279. self.duration.mm_width(40).mm_height(21).mm_right(15).mm__centerY(self.playBtn.mm_centerY);
  280. self.playProcess.mm_sizeToFit()
  281. .mm_left(self.playTime.mm_maxX + 10)
  282. .mm_flexToRight(self.duration.mm_r + self.duration.mm_w + 10)
  283. .mm__centerY(self.playBtn.mm_centerY);
  284. self.scrollView.mm_width(self.mm_w).mm_height(self.mm_h).mm__centerX(self.mm_w / 2).mm__centerY(self.mm_h / 2);
  285. self.scrollView.videoViewNormalWidth = self.mm_w;
  286. self.scrollView.videoViewNormalHeight = self.mm_h;
  287. self.playerLayer.frame = self.scrollView.bounds;
  288. [self.scrollView.videoView.layer layoutIfNeeded];
  289. }
  290. - (void)addPlayer:(NSURL *)url {
  291. self.videoUrl = url;
  292. if (!self.player) {
  293. self.player = [AVPlayer playerWithURL:self.videoUrl];
  294. self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
  295. self.playerLayer.frame = self.scrollView.videoView.bounds;
  296. [self.scrollView.videoView.layer insertSublayer:self.playerLayer atIndex:0];
  297. @weakify(self);
  298. [self.player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.05, 30)
  299. queue:NULL
  300. usingBlock:^(CMTime time) {
  301. @strongify(self);
  302. CGFloat curTime = CMTimeGetSeconds(self.player.currentItem.currentTime);
  303. CGFloat duration = CMTimeGetSeconds(self.player.currentItem.duration);
  304. CGFloat progress = curTime / duration;
  305. [self.playProcess setValue:progress];
  306. self.playTime.text = [NSString stringWithFormat:@"%.2d:%.2d", (int)curTime / 60, (int)curTime % 60];
  307. }];
  308. [self addPlayerItemObserver];
  309. } else {
  310. [self removePlayerItemObserver];
  311. AVPlayerItem *item = [AVPlayerItem playerItemWithURL:self.videoUrl];
  312. [self.player replaceCurrentItemWithPlayerItem:item];
  313. [self addPlayerItemObserver];
  314. }
  315. }
  316. - (void)addPlayerItemObserver {
  317. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onVideoPlayEnd) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
  318. }
  319. - (void)removePlayerItemObserver {
  320. [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
  321. }
  322. - (void)stopVideoPlayAndSave {
  323. [self stopPlay];
  324. self.isSaveVideo = NO;
  325. [TUITool hideToast];
  326. }
  327. #pragma player event
  328. - (void)onPlayBtnClick {
  329. if (![self.videoData isVideoExist]) {
  330. [self.videoData downloadVideo];
  331. } else {
  332. if (self.isPlay) {
  333. [self stopPlay];
  334. } else {
  335. [self play];
  336. }
  337. }
  338. }
  339. - (void)onCloseBtnClick {
  340. [self stopPlay];
  341. if (self.delegate && [self.delegate respondsToSelector:@selector(onCloseMedia:)]) {
  342. [self.delegate onCloseMedia:self];
  343. }
  344. }
  345. - (void)onVideoPlayEnd {
  346. if (1 == self.playProcess.value) {
  347. [self.player seekToTime:CMTimeMakeWithSeconds(0, 30)];
  348. [self stopPlay];
  349. }
  350. }
  351. - (void)onSliderValueChangedBegin:(id)sender {
  352. [self.player pause];
  353. }
  354. - (void)onSliderValueChanged:(id)sender {
  355. UISlider *slider = (UISlider *)sender;
  356. CGFloat curTime = CMTimeGetSeconds(self.player.currentItem.duration) * slider.value;
  357. [self.player seekToTime:CMTimeMakeWithSeconds(curTime, 30)];
  358. [self play];
  359. }
  360. - (void)play {
  361. self.isPlay = YES;
  362. [self.player play];
  363. self.imageView.hidden = YES;
  364. self.mainPlayBtn.hidden = YES;
  365. [self.playBtn setImage:TUIChatCommonBundleImage(@"video_pause") forState:UIControlStateNormal];
  366. }
  367. - (void)stopPlay {
  368. BOOL hasRiskContent = self.videoData.innerMessage.hasRiskContent;
  369. self.isPlay = NO;
  370. [self.player pause];
  371. self.imageView.hidden = NO;
  372. if (!hasRiskContent) {
  373. self.mainPlayBtn.hidden = NO;
  374. }
  375. [self.playBtn setImage:TUIChatCommonBundleImage(@"video_play") forState:UIControlStateNormal];
  376. }
  377. - (void)mainDownloadBtnClick {
  378. if (![self.videoData isVideoExist]) {
  379. [self.videoData downloadVideo];
  380. }
  381. }
  382. #pragma video save
  383. - (void)onDownloadBtnClick {
  384. if (![self.videoData isVideoExist]) {
  385. self.isSaveVideo = YES;
  386. [TUITool makeToast:TIMCommonLocalizableString(TUIKitVideoDownloading) duration:CGFLOAT_MAX];
  387. } else {
  388. [self saveVideo];
  389. }
  390. }
  391. - (void)saveVideo {
  392. [TUITool hideToast];
  393. [[PHPhotoLibrary sharedPhotoLibrary]
  394. performChanges:^{
  395. PHAssetChangeRequest *request = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:[NSURL fileURLWithPath:self.videoPath]];
  396. request.creationDate = [NSDate date];
  397. }
  398. completionHandler:^(BOOL success, NSError *_Nullable error) {
  399. dispatch_async(dispatch_get_main_queue(), ^{
  400. if (success) {
  401. [TUITool makeToast:TIMCommonLocalizableString(TUIKitVideoSavedSuccess) duration:1];
  402. } else {
  403. [TUITool makeToastError:-1 msg:TIMCommonLocalizableString(TUIKitVideoSavedFailed)];
  404. }
  405. });
  406. }];
  407. }
  408. - (void)onDeviceOrientationChange:(NSNotification *)noti {
  409. UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
  410. [self reloadAllView];
  411. }
  412. - (void)reloadAllView {
  413. if (self.player) {
  414. [self stopPlay];
  415. self.player = nil;
  416. }
  417. if (self.playerLayer) {
  418. [self.playerLayer removeFromSuperlayer];
  419. self.playerLayer = nil;
  420. }
  421. for (UIView *subview in self.scrollView.subviews) {
  422. if (subview) {
  423. [subview removeFromSuperview];
  424. }
  425. }
  426. for (UIView *subview in self.subviews) {
  427. if (subview) {
  428. [subview removeFromSuperview];
  429. }
  430. }
  431. [self setupViews];
  432. if (self.videoData) {
  433. [self fillWithData:self.videoData];
  434. }
  435. }
  436. #pragma mark - TUIMessageProgressManagerDelegate
  437. - (void)onUploadProgress:(NSString *)msgID progress:(NSInteger)progress {
  438. if (![msgID isEqualToString:self.videoData.msgID]) {
  439. return;
  440. }
  441. if (self.videoData.direction == MsgDirectionOutgoing) {
  442. self.videoData.uploadProgress = progress;
  443. }
  444. }
  445. #pragma mark - V2TIMAdvancedMsgListener
  446. - (void)onRecvMessageModified:(V2TIMMessage *)msg {
  447. V2TIMMessage *imMsg = msg;
  448. if (imMsg == nil || ![imMsg isKindOfClass:V2TIMMessage.class]) {
  449. return;
  450. }
  451. if ([self.videoData.innerMessage.msgID isEqualToString:imMsg.msgID]) {
  452. BOOL hasRiskContent = msg.hasRiskContent;
  453. if (hasRiskContent) {
  454. self.videoData.innerMessage = imMsg;
  455. [self showRiskAlert];
  456. }
  457. }
  458. }
  459. - (void)showRiskAlert {
  460. if (self.player) {
  461. [self stopPlay];
  462. }
  463. UIAlertController *ac = [UIAlertController alertControllerWithTitle:nil
  464. message:TIMCommonLocalizableString(TUIKitVideoCheckRisk)
  465. preferredStyle:UIAlertControllerStyleAlert];
  466. __weak typeof(self) weakSelf = self;
  467. [ac tuitheme_addAction:[UIAlertAction actionWithTitle:TIMCommonLocalizableString(TUIKitVideoCheckRiskCancel)
  468. style:UIAlertActionStyleCancel
  469. handler:^(UIAlertAction *_Nonnull action) {
  470. __strong typeof(weakSelf) strongSelf = weakSelf;
  471. [strongSelf reloadAllView];
  472. }]];
  473. [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:ac animated:YES completion:nil];
  474. }
  475. @end