TUIBaseChatViewController_Minimalist.m 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507
  1. //
  2. // TUIBaseChatViewController_Minimalist.m
  3. // UIKit
  4. //
  5. // Created by annidyfeng on 2019/5/21.
  6. // Copyright © 2023 Tencent. All rights reserved.
  7. //
  8. #import "TUIBaseChatViewController_Minimalist.h"
  9. #import <AVFoundation/AVFoundation.h>
  10. #import <AssetsLibrary/AssetsLibrary.h>
  11. #import <MobileCoreServices/MobileCoreServices.h>
  12. #import <Photos/Photos.h>
  13. #import <TIMCommon/NSString+TUIEmoji.h>
  14. #import <TIMCommon/TIMDefine.h>
  15. #import <TIMCommon/TIMInputViewMoreActionProtocol.h>
  16. #import <TIMCommon/TUIBubbleMessageCell_Minimalist.h>
  17. #import <TIMCommon/TUIFloatViewController.h>
  18. #import <TIMCommon/TUIGroupAvatar+Helper.h>
  19. #import <TUICore/NSDictionary+TUISafe.h>
  20. #import <TUICore/TUICore.h>
  21. #import <TUICore/TUILogin.h>
  22. #import <TUICore/TUIThemeManager.h>
  23. #import <TUICore/TUITool.h>
  24. #import <TUICore/NSString+TUIUtil.h>
  25. #import "ReactiveObjC/ReactiveObjC.h"
  26. #import "TUIAIDenoiseSignatureManager.h"
  27. #import "TUIBaseMessageController_Minimalist.h"
  28. #import "TUICameraViewController.h"
  29. #import "TUIChatConfig.h"
  30. #import "TUIChatDataProvider.h"
  31. #import "TUIChatMediaDataProvider.h"
  32. #import "TUIChatModifyMessageHelper.h"
  33. #import "TUICloudCustomDataTypeCenter.h"
  34. #import "TUIFileMessageCellData.h"
  35. #import "TUIImageMessageCellData.h"
  36. #import "TUIJoinGroupMessageCell_Minimalist.h"
  37. #import "TUIMessageController_Minimalist.h"
  38. #import "TUIMessageDataProvider.h"
  39. #import "TUIMessageMultiChooseView_Minimalist.h"
  40. #import "TUIMessageReadViewController_Minimalist.h"
  41. #import "TUIReplyMessageCellData.h"
  42. #import "TUITextMessageCellData.h"
  43. #import "TUIVideoMessageCellData.h"
  44. #import "TUIVoiceMessageCellData.h"
  45. #import "UIAlertController+TUICustomStyle.h"
  46. static UIView *gCustomTopView;
  47. static UIView *gTopExentsionView;
  48. static UIView *gGroupPinTopView;
  49. static CGRect gCustomTopViewRect;
  50. @interface TUIBaseChatViewController_Minimalist () <TUIBaseMessageControllerDelegate_Minimalist,
  51. TUIInputControllerDelegate_Minimalist,
  52. UIImagePickerControllerDelegate,
  53. UIDocumentPickerDelegate,
  54. UINavigationControllerDelegate,
  55. TUIMessageMultiChooseViewDelegate_Minimalist,
  56. TUIChatBaseDataProviderDelegate,
  57. TUINotificationProtocol,
  58. TUIJoinGroupMessageCellDelegate_Minimalist,
  59. V2TIMConversationListener,
  60. TUINavigationControllerDelegate,
  61. V2TIMSDKListener,
  62. TUIChatMediaDataListener,
  63. TIMInputViewMoreActionProtocol>
  64. @property(nonatomic, strong) TUINaviBarIndicatorView *titleView;
  65. @property(nonatomic, strong) TUIMessageMultiChooseView_Minimalist *multiChooseView;
  66. @property(nonatomic, assign) BOOL responseKeyboard;
  67. @property(nonatomic, assign) BOOL isPageAppears;
  68. @property(nonatomic, strong) TUIChatDataProvider *dataProvider;
  69. @property(nonatomic, assign) BOOL firstAppear;
  70. @property(nonatomic, copy) NSString *mainTitle;
  71. @property(nonatomic, strong) UIImageView *backgroudView;
  72. @property(nonatomic, strong) UIImageView *avatarView;
  73. @property(nonatomic, strong) UILabel *mainTitleLabel;
  74. @property(nonatomic, strong) UILabel *subTitleLabel;
  75. @property(nonatomic, strong) TUIChatMediaDataProvider *mediaProvider;
  76. @end
  77. @implementation TUIBaseChatViewController_Minimalist
  78. #pragma mark - Life Cycle
  79. - (instancetype)init {
  80. self = [super init];
  81. if (self) {
  82. [TUIBaseChatViewController_Minimalist createCachePath];
  83. [[TUIAIDenoiseSignatureManager sharedInstance] updateSignature];
  84. [[NSNotificationCenter defaultCenter] addObserver:self
  85. selector:@selector(reloadTopViewsAndMessagePage)
  86. name:TUICore_TUIChatExtension_ChatViewTopArea_ChangedNotification
  87. object:nil];
  88. [TUIChatMediaSendingManager.sharedInstance addCurrentVC:self];
  89. }
  90. return self;
  91. }
  92. - (void)setTitle:(NSString *)title {
  93. self.mainTitle = title;
  94. }
  95. - (void)viewDidLoad {
  96. [super viewDidLoad];
  97. [self setupTopViews];
  98. self.firstAppear = YES;
  99. self.view.backgroundColor = TIMCommonDynamicColor(@"controller_bg_color", @"#FFFFFF");
  100. self.edgesForExtendedLayout = UIRectEdgeNone;
  101. [self configBackgroundView];
  102. [self configNotify];
  103. // setup UI
  104. [self setupNavigator];
  105. if (gCustomTopView) {
  106. [self setupCustomTopView];
  107. }
  108. [self setupMessageController];
  109. [self setupInputMoreMenu];
  110. [self setupInputController];
  111. // data mo_provider
  112. self.dataProvider = [[TUIChatDataProvider alloc] init];
  113. self.dataProvider.delegate = self;
  114. [[V2TIMManager sharedInstance] addIMSDKListener:self];
  115. }
  116. - (void)dealloc {
  117. [TUICore unRegisterEventByObject:self];
  118. }
  119. - (void)willMoveToParentViewController:(UIViewController *)parent {
  120. if (parent == nil) {
  121. [self saveDraft];
  122. }
  123. }
  124. - (void)viewWillAppear:(BOOL)animated {
  125. [super viewWillAppear:animated];
  126. [self configTopViewsViewWillAppear];
  127. }
  128. - (void)configTopViewsViewWillAppear {
  129. if (gCustomTopView.superview != self.view) {
  130. if (CGRectEqualToRect(gCustomTopView.frame, CGRectZero)) {
  131. gCustomTopView.frame = CGRectMake(0, CGRectGetMaxY(gTopExentsionView.frame), gCustomTopViewRect.size.width, gCustomTopViewRect.size.height);
  132. }
  133. [self.view addSubview:gCustomTopView];
  134. }
  135. if (gTopExentsionView.superview != self.view) {
  136. [self.view addSubview:gTopExentsionView];
  137. }
  138. if (gGroupPinTopView.superview != self.view && self.conversationData.groupID.length > 0){
  139. [self.view addSubview:gGroupPinTopView];
  140. }
  141. [self reloadTopViewsAndMessagePage];
  142. }
  143. - (void)setupTopViews {
  144. if (gTopExentsionView) {
  145. [gTopExentsionView removeFromSuperview];
  146. }
  147. else {
  148. gTopExentsionView = [[UIView alloc] init];
  149. gTopExentsionView.clipsToBounds = YES;
  150. }
  151. if (gGroupPinTopView) {
  152. [gGroupPinTopView removeFromSuperview];
  153. }
  154. else {
  155. gGroupPinTopView = [[UIView alloc] init];
  156. gGroupPinTopView.clipsToBounds = YES;
  157. }
  158. if (gTopExentsionView) {
  159. [self setupTopExentsionView];
  160. }
  161. if (gCustomTopView) {
  162. [self setupCustomTopView];
  163. gCustomTopView.frame = CGRectMake(0, CGRectGetMaxY(gTopExentsionView.frame), gCustomTopViewRect.size.width, gCustomTopViewRect.size.height);
  164. }
  165. if (gGroupPinTopView && self.conversationData.groupID.length > 0) {
  166. [self setupGroupPinTopView];
  167. gGroupPinTopView.frame = CGRectMake(0, CGRectGetMaxY(gCustomTopView.frame), gGroupPinTopView.frame.size.width, gGroupPinTopView.frame.size.height);;
  168. }
  169. }
  170. - (void)reloadTopViewsAndMessagePage {
  171. gCustomTopView.frame = CGRectMake(0, CGRectGetMaxY(gTopExentsionView.frame), gCustomTopView.frame.size.width, gCustomTopView.frame.size.height);
  172. if (gGroupPinTopView) {
  173. gGroupPinTopView.frame = CGRectMake(0, CGRectGetMaxY(gCustomTopView.frame), gGroupPinTopView.frame.size.width, gGroupPinTopView.frame.size.height);;
  174. }
  175. CGFloat topMarginByCustomView = [self topMarginByCustomView];
  176. if (_messageController.view.mm_y != topMarginByCustomView) {
  177. CGFloat textViewHeight = TUIChatConfig.defaultConfig.enableMainPageInputBar? TTextView_Height:0;
  178. _messageController.view.frame = CGRectMake(0, topMarginByCustomView, self.view.mm_w,
  179. self.view.mm_h - textViewHeight - Bottom_SafeHeight - topMarginByCustomView);
  180. [self.messageController scrollToBottom:YES];
  181. }
  182. }
  183. - (void)viewDidAppear:(BOOL)animated {
  184. [super viewDidAppear:animated];
  185. self.responseKeyboard = YES;
  186. self.isPageAppears = YES;
  187. if (self.firstAppear) {
  188. [self loadDraft];
  189. self.firstAppear = NO;
  190. }
  191. self.mainTitleLabel.text = [self getMainTitleLabelText];
  192. [self configHeadImageView:self.conversationData];
  193. }
  194. - (void)viewWillDisappear:(BOOL)animated {
  195. [super viewWillDisappear:animated];
  196. self.responseKeyboard = NO;
  197. self.isPageAppears = NO;
  198. [self openMultiChooseBoard:NO];
  199. [self.messageController enableMultiSelectedMode:NO];
  200. }
  201. - (void)viewDidDisappear:(BOOL)animated {
  202. [super viewDidDisappear:animated];
  203. }
  204. - (void)setupNavigator {
  205. TUINavigationController *naviController = (TUINavigationController *)self.navigationController;
  206. if ([naviController isKindOfClass:TUINavigationController.class]) {
  207. naviController.uiNaviDelegate = self;
  208. UIImage *backimg = TIMCommonDynamicImage(@"nav_back_img", TIMCommonImagePath(@"nav_back"));
  209. backimg = [backimg rtl_imageFlippedForRightToLeftLayoutDirection];
  210. naviController.navigationItemBackArrowImage = backimg;
  211. }
  212. UIButton *backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 24, 24)];
  213. [backButton addTarget:self action:@selector(backButtonClick) forControlEvents:UIControlEventTouchUpInside];
  214. UIImage *imgicon = [[TUIImageCache sharedInstance] getResourceFromCache:TUIChatImagePath_Minimalist(@"vc_back")];
  215. imgicon = [imgicon rtl_imageFlippedForRightToLeftLayoutDirection];
  216. [backButton setImage:imgicon forState:UIControlStateNormal];
  217. UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
  218. UIView *infoView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScale390(200), 40)];
  219. UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(rightBarButtonClick)];
  220. [infoView addGestureRecognizer:tap];
  221. UIImageView *avatarView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
  222. avatarView.image = self.conversationData.avatarImage;
  223. avatarView.layer.cornerRadius = avatarView.frame.size.width / 2.0;
  224. avatarView.layer.masksToBounds = YES;
  225. [infoView addSubview:avatarView];
  226. self.avatarView = avatarView;
  227. UILabel *mainTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(avatarView.mm_x + avatarView.mm_w + kScale390(8), 0, kScale390(200), 20)];
  228. mainTitleLabel.font = [UIFont boldSystemFontOfSize:14];
  229. mainTitleLabel.text = [self getMainTitleLabelText];
  230. mainTitleLabel.rtlAlignment = TUITextRTLAlignmentLeading;
  231. [infoView addSubview:mainTitleLabel];
  232. self.mainTitleLabel = mainTitleLabel;
  233. self.subTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(mainTitleLabel.mm_x, 20, mainTitleLabel.mm_w, 20)];
  234. self.subTitleLabel.font = [UIFont systemFontOfSize:12];
  235. self.subTitleLabel.rtlAlignment = TUITextRTLAlignmentLeading;
  236. [self updateSubTitleLabelText];
  237. [infoView addSubview:self.subTitleLabel];
  238. if (isRTL()) {
  239. [avatarView resetFrameToFitRTL];
  240. [mainTitleLabel resetFrameToFitRTL];
  241. [self.subTitleLabel resetFrameToFitRTL];
  242. }
  243. __weak typeof(self) weakSelf = self;
  244. [[RACObserve(_conversationData, otherSideTyping) distinctUntilChanged] subscribeNext:^(id otherSideTyping) {
  245. BOOL otherSideTypingFlag = [otherSideTyping boolValue];
  246. if (!otherSideTypingFlag) {
  247. [weakSelf updateSubTitleLabelText];
  248. }
  249. else {
  250. NSString *typingText = [NSString stringWithFormat:@"%@...", TIMCommonLocalizableString(TUIKitTyping)];
  251. weakSelf.subTitleLabel.text = typingText;
  252. }
  253. }];
  254. UIBarButtonItem *infoViewItem = [[UIBarButtonItem alloc] initWithCustomView:infoView];
  255. self.navigationItem.leftBarButtonItems = @[ backButtonItem, infoViewItem ];
  256. CGSize itemSize = CGSizeMake(30, 24);
  257. NSMutableArray *rightBarButtonList = [NSMutableArray array];
  258. NSMutableDictionary *param = [NSMutableDictionary dictionary];
  259. if (self.conversationData.userID.length > 0) {
  260. param[TUICore_TUIChatExtension_NavigationMoreItem_UserID] = self.conversationData.userID;
  261. } else if (self.conversationData.groupID.length > 0) {
  262. param[TUICore_TUIChatExtension_NavigationMoreItem_GroupID] = self.conversationData.groupID;
  263. }
  264. param[TUICore_TUIChatExtension_NavigationMoreItem_ItemSize] = NSStringFromCGSize(itemSize);
  265. param[TUICore_TUIChatExtension_NavigationMoreItem_FilterVideoCall] = @(!TUIChatConfig.defaultConfig.enableVideoCall);
  266. param[TUICore_TUIChatExtension_NavigationMoreItem_FilterAudioCall] = @(!TUIChatConfig.defaultConfig.enableAudioCall);
  267. NSArray<TUIExtensionInfo *> *extensionList = [TUICore getExtensionList:TUICore_TUIChatExtension_NavigationMoreItem_MinimalistExtensionID param:param];
  268. for (TUIExtensionInfo *info in extensionList) {
  269. if (info.icon && info.onClicked) {
  270. UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, itemSize.width, itemSize.height)];
  271. button.tui_extValueObj = info;
  272. [button addTarget:self action:@selector(rightBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
  273. [button setImage:info.icon forState:UIControlStateNormal];
  274. UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithCustomView:button];
  275. [rightBarButtonList addObject:rightItem];
  276. }
  277. }
  278. if (rightBarButtonList.count > 0) {
  279. self.navigationItem.rightBarButtonItems = rightBarButtonList.reverseObjectEnumerator.allObjects;
  280. }
  281. }
  282. - (NSString *)getMainTitleLabelText {
  283. if (self.conversationData.title.length > 0) {
  284. return self.conversationData.title;
  285. } else if (self.conversationData.groupID.length > 0) {
  286. return self.conversationData.groupID;
  287. } else {
  288. return self.conversationData.userID;
  289. }
  290. }
  291. - (void)updateSubTitleLabelText {
  292. if (![TUIConfig defaultConfig].displayOnlineStatusIcon) {
  293. self.subTitleLabel.text = @"";
  294. return;
  295. }
  296. if (self.conversationData.userID.length > 0) {
  297. [[V2TIMManager sharedInstance] getUserStatus:@[ self.conversationData.userID ]
  298. succ:^(NSArray<V2TIMUserStatus *> *result) {
  299. V2TIMUserStatus *status = result.firstObject;
  300. self.subTitleLabel.text = [self getUserStatus:status];
  301. }
  302. fail:nil];
  303. } else if (self.conversationData.groupID.length > 0) {
  304. [[V2TIMManager sharedInstance] getGroupMemberList:self.conversationData.groupID
  305. filter:V2TIM_GROUP_MEMBER_FILTER_ALL
  306. nextSeq:0
  307. succ:^(uint64_t nextSeq, NSArray<V2TIMGroupMemberFullInfo *> *memberList) {
  308. NSMutableString *title = [NSMutableString string];
  309. int memberCount = 0;
  310. for (V2TIMGroupMemberFullInfo *info in memberList) {
  311. NSString *name = (info.nameCard ?: info.nickName) ?: info.userID;
  312. [title appendString:[NSString stringWithFormat:@"%@,", name]];
  313. if (++memberCount >= 5) {
  314. break;
  315. }
  316. }
  317. if (title.length > 0) {
  318. title = [NSMutableString stringWithString:[title substringToIndex:title.length - 1]];
  319. }
  320. self.subTitleLabel.text = title;
  321. }
  322. fail:nil];
  323. }
  324. }
  325. - (void)onUserStatusChanged:(NSArray<V2TIMUserStatus *> *)userStatusList {
  326. if (!self.conversationData.userID) {
  327. return;
  328. }
  329. for (V2TIMUserStatus *status in userStatusList) {
  330. if ([status.userID isEqualToString:self.conversationData.userID]) {
  331. self.subTitleLabel.text = [self getUserStatus:status];
  332. break;
  333. }
  334. }
  335. }
  336. - (NSString *)getUserStatus:(V2TIMUserStatus *)status {
  337. NSString *title = nil;
  338. switch (status.statusType) {
  339. case V2TIM_USER_STATUS_UNKNOWN: {
  340. title = TIMCommonLocalizableString(TUIKitUserStatusUnknown);
  341. } break;
  342. case V2TIM_USER_STATUS_ONLINE: {
  343. title = TIMCommonLocalizableString(TUIKitUserStatusOnline);
  344. } break;
  345. case V2TIM_USER_STATUS_OFFLINE: {
  346. title = TIMCommonLocalizableString(TUIKitUserStatusOffline);
  347. } break;
  348. case V2TIM_USER_STATUS_UNLOGINED: {
  349. title = TIMCommonLocalizableString(TUIKitUserStatusUnlogined);
  350. } break;
  351. default:
  352. break;
  353. }
  354. return title;
  355. }
  356. - (void)backButtonClick {
  357. [self.messageController readReport];
  358. [self.navigationController popViewControllerAnimated:YES];
  359. }
  360. - (void)rightBarButtonClick:(UIButton *)button {
  361. TUIExtensionInfo *info = button.tui_extValueObj;
  362. if (info == nil || ![info isKindOfClass:TUIExtensionInfo.class] || info.onClicked == nil) {
  363. return;
  364. }
  365. NSMutableDictionary *param = [NSMutableDictionary dictionary];
  366. if (self.conversationData.userID.length > 0) {
  367. param[TUICore_TUIChatExtension_NavigationMoreItem_UserID] = self.conversationData.userID;
  368. } else if (self.conversationData.groupID.length > 0) {
  369. param[TUICore_TUIChatExtension_NavigationMoreItem_GroupID] = self.conversationData.groupID;
  370. }
  371. if (self.navigationController) {
  372. param[TUICore_TUIChatExtension_NavigationMoreItem_PushVC] = self.navigationController;
  373. }
  374. info.onClicked(param);
  375. }
  376. - (void)setupMessageController {
  377. TUIMessageController_Minimalist *vc = [[TUIMessageController_Minimalist alloc] init];
  378. vc.hightlightKeyword = self.highlightKeyword;
  379. vc.locateMessage = self.locateMessage;
  380. vc.isMsgNeedReadReceipt = self.conversationData.msgNeedReadReceipt && [TUIChatConfig defaultConfig].msgNeedReadReceipt;
  381. _messageController = vc;
  382. _messageController.delegate = self;
  383. [_messageController setConversation:self.conversationData];
  384. CGFloat textViewHeight = TUIChatConfig.defaultConfig.enableMainPageInputBar? TTextView_Height:0;
  385. _messageController.view.frame = CGRectMake(0, [self topMarginByCustomView], self.view.frame.size.width,
  386. self.view.frame.size.height - textViewHeight - Bottom_SafeHeight - [self topMarginByCustomView]);
  387. [self addChildViewController:_messageController];
  388. [self.view addSubview:_messageController.view];
  389. [_messageController didMoveToParentViewController:self];
  390. }
  391. - (void)setupTopExentsionView {
  392. if (gTopExentsionView.superview != self.view) {
  393. [self.view addSubview:gTopExentsionView];
  394. }
  395. gTopExentsionView.frame = CGRectMake(0, 0, self.view.frame.size.width, 0);
  396. NSMutableDictionary *param = [NSMutableDictionary dictionary];
  397. if (self.conversationData.userID.length > 0) {
  398. param[TUICore_TUIChatExtension_ChatViewTopArea_ChatID] = self.conversationData.userID;
  399. param[TUICore_TUIChatExtension_ChatViewTopArea_IsGroup] = @"0";
  400. } else if (self.conversationData.groupID.length > 0) {
  401. param[TUICore_TUIChatExtension_ChatViewTopArea_IsGroup] = @"1";
  402. param[TUICore_TUIChatExtension_ChatViewTopArea_ChatID] = self.conversationData.groupID;
  403. }
  404. [TUICore raiseExtension:TUICore_TUIChatExtension_ChatViewTopArea_MinimalistExtensionID parentView:gTopExentsionView param:param];
  405. }
  406. - (void)setupGroupPinTopView {
  407. if (gGroupPinTopView.superview != self.view) {
  408. [self.view addSubview:gGroupPinTopView];
  409. }
  410. gGroupPinTopView.backgroundColor = [UIColor clearColor];
  411. gGroupPinTopView.frame = CGRectMake(0, 0, self.view.frame.size.width, 0);
  412. }
  413. - (void)setupCustomTopView {
  414. if (gCustomTopView.superview != self.view) {
  415. [self.view addSubview:gCustomTopView];
  416. }
  417. }
  418. - (void)setupInputController {
  419. _inputController = [[TUIInputController_Minimalist alloc] init];
  420. _inputController.delegate = self;
  421. _inputController.view.frame =
  422. CGRectMake(0, self.view.frame.size.height - TTextView_Height - Bottom_SafeHeight, self.view.frame.size.width, TTextView_Height + Bottom_SafeHeight);
  423. _inputController.view.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
  424. [self addChildViewController:_inputController];
  425. [self.view addSubview:_inputController.view];
  426. _inputController.view.hidden = !TUIChatConfig.defaultConfig.enableMainPageInputBar;
  427. }
  428. - (void)setupInputMoreMenu {
  429. id<TUIChatInputBarConfigDataSource> dataSource = [TUIChatConfig defaultConfig].inputBarDataSource;
  430. if (dataSource && [dataSource respondsToSelector:@selector(inputBarShouldHideItemsInMoreMenuOfModel:)]) {
  431. TUIChatInputBarMoreMenuItem tag = [dataSource inputBarShouldHideItemsInMoreMenuOfModel:self.conversationData];
  432. self.conversationData.enableFile = !(tag & TUIChatInputBarMoreMenuItem_File);
  433. self.conversationData.enableAlbum = !(tag & TUIChatInputBarMoreMenuItem_Album);
  434. self.conversationData.enableTakePhoto = !(tag & TUIChatInputBarMoreMenuItem_TakePhoto);
  435. self.conversationData.enableRecordVideo = !(tag & TUIChatInputBarMoreMenuItem_RecordVideo);
  436. self.conversationData.enableWelcomeCustomMessage = !(tag & TUIChatInputBarMoreMenuItem_CustomMessage);
  437. }
  438. if (dataSource && [dataSource respondsToSelector:@selector(inputBarShouldAddNewItemsToMoreListOfModel:)]) {
  439. NSArray *items = [dataSource inputBarShouldAddNewItemsToMoreListOfModel:self.conversationData];
  440. if ([items isKindOfClass:NSArray.class]) {
  441. self.conversationData.customizedNewItemsInMoreMenu = items;
  442. }
  443. }
  444. }
  445. - (void)configHeadImageView:(TUIChatConversationModel *)convData {
  446. /**
  447. * Setup default avatar
  448. */
  449. if (convData.groupID.length > 0) {
  450. /**
  451. * If it is a group, change the group default avatar to the last used avatar
  452. */
  453. convData.avatarImage = [TUIGroupAvatar getNormalGroupCacheAvatar:convData.groupID groupType:convData.groupType];
  454. }
  455. @weakify(self);
  456. [[RACObserve(convData, faceUrl) distinctUntilChanged] subscribeNext:^(NSString *faceUrl) {
  457. @strongify(self);
  458. NSString *groupID = convData.groupID ?: @"";
  459. NSString *pFaceUrl = convData.faceUrl ?: @"";
  460. NSString *groupType = convData.groupType ?: @"";
  461. UIImage *originAvatarImage = nil;
  462. if (convData.groupID.length > 0) {
  463. originAvatarImage = convData.avatarImage ?: DefaultGroupAvatarImageByGroupType(groupType);
  464. } else {
  465. originAvatarImage = convData.avatarImage ?: DefaultAvatarImage;
  466. }
  467. NSDictionary *param = @{
  468. @"groupID" : groupID,
  469. @"faceUrl" : pFaceUrl,
  470. @"groupType" : groupType,
  471. @"originAvatarImage" : originAvatarImage,
  472. };
  473. [TUIGroupAvatar configAvatarByParam:param targetView:self.avatarView];
  474. }];
  475. }
  476. - (void)configBackgroundView {
  477. self.backgroudView = [[UIImageView alloc] init];
  478. self.backgroudView.backgroundColor =
  479. TUIChatConfig.defaultConfig.backgroudColor ? TUIChatConfig.defaultConfig.backgroudColor : TUIChatDynamicColor(@"chat_controller_bg_color", @"#FFFFFF");
  480. NSString *conversationID = [self getConversationID];
  481. NSString *imgUrl = [self getBackgroundImageUrlByConversationID:conversationID];
  482. if (TUIChatConfig.defaultConfig.backgroudImage) {
  483. self.backgroudView.backgroundColor = UIColor.clearColor;
  484. self.backgroudView.image = TUIChatConfig.defaultConfig.backgroudImage;
  485. } else if (IS_NOT_EMPTY_NSSTRING(imgUrl)) {
  486. [self.backgroudView sd_setImageWithURL:[NSURL URLWithString:imgUrl] placeholderImage:nil];
  487. }
  488. CGFloat textViewHeight = TUIChatConfig.defaultConfig.enableMainPageInputBar? TTextView_Height:0;
  489. self.backgroudView.frame =
  490. CGRectMake(0, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height - textViewHeight - Bottom_SafeHeight);
  491. [self.view insertSubview:self.backgroudView atIndex:0];
  492. }
  493. - (void)configNotify {
  494. [[V2TIMManager sharedInstance] addConversationListener:self];
  495. [TUICore registerEvent:TUICore_TUIConversationNotify subKey:TUICore_TUIConversationNotify_ClearConversationUIHistorySubKey object:self];
  496. [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(onFriendInfoChanged:) name:@"FriendInfoChangedNotification" object:nil];
  497. [TUICore registerEvent:TUICore_TUIContactNotify subKey:TUICore_TUIContactNotify_UpdateConversationBackgroundImageSubKey object:self];
  498. }
  499. #pragma mark - Public Methods
  500. - (void)sendMessage:(V2TIMMessage *)message {
  501. [self.messageController sendMessage:message];
  502. }
  503. - (void)sendMessage:(V2TIMMessage *)message placeHolderCellData:(TUIMessageCellData *)placeHolderCellData {
  504. [self.messageController sendMessage:message placeHolderCellData:placeHolderCellData];
  505. }
  506. - (void)saveDraft {
  507. NSString *content = [self.inputController.inputBar.inputTextView.textStorage tui_getPlainString];
  508. TUIReplyPreviewData *previewData = nil;
  509. if (self.inputController.referenceData) {
  510. previewData = self.inputController.referenceData;
  511. } else if (self.inputController.replyData) {
  512. previewData = self.inputController.replyData;
  513. }
  514. if (previewData) {
  515. NSDictionary *dict = @{
  516. @"content" : content ?: @"",
  517. @"messageReply" : @{
  518. @"messageID" : previewData.msgID ?: @"",
  519. @"messageAbstract" : [previewData.msgAbstract ?: @"" getInternationalStringWithfaceContent],
  520. @"messageSender" : previewData.sender ?: @"",
  521. @"messageType" : @(previewData.type),
  522. @"messageTime" :
  523. @(previewData.originMessage.timestamp ? [previewData.originMessage.timestamp timeIntervalSince1970] : 0), // Compatible for web
  524. @"messageSequence" : @(previewData.originMessage.seq), // Compatible for web
  525. @"version" : @(kDraftMessageReplyVersion),
  526. },
  527. };
  528. NSMutableDictionary *mudic = [NSMutableDictionary dictionaryWithDictionary:dict];
  529. if (IS_NOT_EMPTY_NSSTRING(previewData.messageRootID)) {
  530. [mudic setObject:previewData.messageRootID forKey:@"messageRootID"];
  531. }
  532. NSError *error = nil;
  533. NSData *data = [NSJSONSerialization dataWithJSONObject:mudic options:0 error:&error];
  534. if (error == nil) {
  535. content = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  536. }
  537. }
  538. [TUIChatDataProvider saveDraftWithConversationID:self.conversationData.conversationID Text:content];
  539. }
  540. - (void)loadDraft {
  541. NSString *draft = self.conversationData.draftText;
  542. if (draft.length == 0) {
  543. return;
  544. }
  545. NSError *error = nil;
  546. NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:[draft dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];
  547. if (error || jsonDict == nil) {
  548. NSMutableAttributedString *formatEmojiString = [draft getAdvancedFormatEmojiStringWithFont:kTUIInputNoramlFont
  549. textColor:kTUIInputNormalTextColor
  550. emojiLocations:nil];
  551. [self.inputController.inputBar addDraftToInputBar:formatEmojiString];
  552. return;
  553. }
  554. /**
  555. * Display draft
  556. */
  557. NSString *draftContent = [jsonDict.allKeys containsObject:@"content"] ? jsonDict[@"content"] : @"";
  558. NSMutableAttributedString *formatEmojiString = [draftContent getAdvancedFormatEmojiStringWithFont:kTUIInputNoramlFont
  559. textColor:kTUIInputNormalTextColor
  560. emojiLocations:nil];
  561. [self.inputController.inputBar addDraftToInputBar:formatEmojiString];
  562. NSString *messageRootID = [jsonDict.allKeys containsObject:@"messageRootID"] ? jsonDict[@"messageRootID"] : @"";
  563. /**
  564. * Display message reply preview bar
  565. */
  566. if ([jsonDict isKindOfClass:NSDictionary.class] && [jsonDict.allKeys containsObject:@"messageReply"]) {
  567. NSDictionary *reply = jsonDict[@"messageReply"];
  568. if ([reply isKindOfClass:NSDictionary.class] && [reply.allKeys containsObject:@"messageID"] && [reply.allKeys containsObject:@"messageAbstract"] &&
  569. [reply.allKeys containsObject:@"messageSender"] && [reply.allKeys containsObject:@"messageType"] && [reply.allKeys containsObject:@"version"]) {
  570. NSInteger version = [reply[@"version"] integerValue];
  571. if (version <= kDraftMessageReplyVersion) {
  572. if (IS_NOT_EMPTY_NSSTRING(messageRootID)) {
  573. TUIReplyPreviewData *replyData = [[TUIReplyPreviewData alloc] init];
  574. replyData.msgID = reply[@"messageID"];
  575. replyData.msgAbstract = reply[@"messageAbstract"];
  576. replyData.sender = reply[@"messageSender"];
  577. replyData.type = [reply[@"messageType"] integerValue];
  578. replyData.messageRootID = messageRootID;
  579. [self.inputController showReplyPreview:replyData];
  580. } else {
  581. TUIReferencePreviewData *replyData = [[TUIReferencePreviewData alloc] init];
  582. replyData.msgID = reply[@"messageID"];
  583. replyData.msgAbstract = reply[@"messageAbstract"];
  584. replyData.sender = reply[@"messageSender"];
  585. replyData.type = [reply[@"messageType"] integerValue];
  586. [self.inputController showReferencePreview:replyData];
  587. }
  588. }
  589. }
  590. }
  591. }
  592. + (void)setCustomTopView:(UIView *)view {
  593. gCustomTopView = view;
  594. gCustomTopViewRect = view.frame;
  595. gCustomTopView.clipsToBounds = YES;
  596. }
  597. + (UIView *)customTopView {
  598. return gCustomTopView;
  599. }
  600. + (UIView *)groupPinTopView {
  601. return gGroupPinTopView;
  602. }
  603. + (UIView *)topAreaBottomView {
  604. if (gGroupPinTopView) {
  605. return gGroupPinTopView;
  606. }
  607. if (gCustomTopView) {
  608. return gCustomTopView;
  609. }
  610. if (gTopExentsionView) {
  611. return gTopExentsionView;
  612. }
  613. return nil;
  614. }
  615. #pragma mark - Getters & Setters
  616. - (void)setConversationData:(TUIChatConversationModel *)conversationData {
  617. _conversationData = conversationData;
  618. if (!IS_NOT_EMPTY_NSSTRING(_conversationData.title) || !IS_NOT_EMPTY_NSSTRING(conversationData.faceUrl)) {
  619. [self checkTitle:YES];
  620. }
  621. }
  622. - (CGFloat)topMarginByCustomView {
  623. CGFloat gCutomTopViewH = gCustomTopView && gCustomTopView.superview ? gCustomTopView.mm_h : 0 ;
  624. CGFloat gTopExtsionH = gTopExentsionView && gTopExentsionView.superview ? gTopExentsionView.mm_h : 0;
  625. CGFloat gGroupPinTopViewH = gGroupPinTopView && gGroupPinTopView.superview ? gGroupPinTopView.mm_h : 0;
  626. CGFloat height = gCutomTopViewH + gTopExtsionH + gGroupPinTopViewH;
  627. return height;
  628. }
  629. #pragma mark - Event Response
  630. - (void)checkTitle:(BOOL)force {
  631. if (force || self.conversationData.title.length == 0) {
  632. if (self.conversationData.userID.length > 0) {
  633. self.conversationData.title = self.conversationData.userID;
  634. @weakify(self);
  635. [TUIChatDataProvider getFriendInfoWithUserId:self.conversationData.userID
  636. SuccBlock:^(V2TIMFriendInfoResult *_Nonnull friendInfoResult) {
  637. @strongify(self);
  638. if (friendInfoResult.relation & V2TIM_FRIEND_RELATION_TYPE_IN_MY_FRIEND_LIST &&
  639. friendInfoResult.friendInfo.friendRemark.length > 0) {
  640. self.conversationData.title = friendInfoResult.friendInfo.friendRemark;
  641. self.conversationData.faceUrl = friendInfoResult.friendInfo.userFullInfo.faceURL;
  642. } else {
  643. [TUIChatDataProvider
  644. getUserInfoWithUserId:self.conversationData.userID
  645. SuccBlock:^(V2TIMUserFullInfo *_Nonnull userInfo) {
  646. if (userInfo.nickName.length > 0) {
  647. self.conversationData.title = userInfo.nickName;
  648. self.conversationData.faceUrl = userInfo.faceURL;
  649. }
  650. }
  651. failBlock:nil];
  652. }
  653. }
  654. failBlock:nil];
  655. } else if (self.conversationData.groupID.length > 0) {
  656. [TUIChatDataProvider getGroupInfoWithGroupID:self.conversationData.groupID
  657. SuccBlock:^(V2TIMGroupInfoResult *_Nonnull groupResult) {
  658. if (groupResult.info.groupName.length > 0) {
  659. self.conversationData.title = groupResult.info.groupName;
  660. self.conversationData.faceUrl = groupResult.info.faceURL;
  661. self.conversationData.groupType = groupResult.info.groupType;
  662. }
  663. }
  664. failBlock:nil];
  665. }
  666. }
  667. }
  668. - (void)leftBarButtonClick {
  669. [self.navigationController popViewControllerAnimated:YES];
  670. }
  671. - (void)rightBarButtonClick {
  672. //When pushing a new VC, the keyboard needs to be hidden.
  673. [self.inputController reset];
  674. if (_conversationData.userID.length > 0) {
  675. [self getUserOrFriendProfileVCWithUserID:self.conversationData.userID
  676. succBlock:^(UIViewController *_Nonnull vc) {
  677. [self.navigationController pushViewController:vc animated:YES];
  678. }
  679. failBlock:^(int code, NSString *_Nonnull desc) {
  680. [TUITool makeToastError:code msg:desc];
  681. }];
  682. } else {
  683. NSDictionary *param = @{TUICore_TUIContactObjectFactory_GetGroupInfoVC_GroupID : self.conversationData.groupID};
  684. [self.navigationController pushViewController:TUICore_TUIContactObjectFactory_GetGroupInfoVC_Minimalist param:param forResult:nil];
  685. }
  686. }
  687. - (void)getUserOrFriendProfileVCWithUserID:(NSString *)userID succBlock:(void (^)(UIViewController *vc))succ failBlock:(nullable V2TIMFail)fail {
  688. NSDictionary *param = @{
  689. TUICore_TUIContactObjectFactory_GetUserOrFriendProfileVCMethod_UserIDKey: userID ? : @"",
  690. TUICore_TUIContactObjectFactory_GetUserOrFriendProfileVCMethod_SuccKey: succ ? : ^(UIViewController *vc){},
  691. TUICore_TUIContactObjectFactory_GetUserOrFriendProfileVCMethod_FailKey: fail ? : ^(int code, NSString * desc){}
  692. };
  693. [TUICore createObject:TUICore_TUIContactObjectFactory_Minimalist key:TUICore_TUIContactObjectFactory_GetUserOrFriendProfileVCMethod param:param];
  694. }
  695. #pragma mark - TUICore notify
  696. - (void)onNotifyEvent:(NSString *)key subKey:(NSString *)subKey object:(id)anObject param:(NSDictionary *)param {
  697. if ([key isEqualToString:TUICore_TUIConversationNotify] && [subKey isEqualToString:TUICore_TUIConversationNotify_ClearConversationUIHistorySubKey]) {
  698. [self.messageController clearUImsg];
  699. } else if ([key isEqualToString:TUICore_TUIContactNotify] && [subKey isEqualToString:TUICore_TUIContactNotify_UpdateConversationBackgroundImageSubKey]) {
  700. NSString *conversationID = param[TUICore_TUIContactNotify_UpdateConversationBackgroundImageSubKey_ConversationID];
  701. if (IS_NOT_EMPTY_NSSTRING(conversationID)) {
  702. [self updateBackgroundImageUrlByConversationID:conversationID];
  703. }
  704. }
  705. }
  706. - (void)updateBackgroundImageUrlByConversationID:(NSString *)conversationID {
  707. if ([[self getConversationID] isEqualToString:conversationID]) {
  708. self.backgroudView.backgroundColor = UIColor.clearColor;
  709. NSString *imgUrl = [self getBackgroundImageUrlByConversationID:conversationID];
  710. if (IS_NOT_EMPTY_NSSTRING(imgUrl)) {
  711. [self.backgroudView sd_setImageWithURL:[NSURL URLWithString:imgUrl] placeholderImage:nil];
  712. } else {
  713. self.backgroudView.image = nil;
  714. }
  715. }
  716. }
  717. - (NSString *)getBackgroundImageUrlByConversationID:(NSString *)targerConversationID {
  718. if (targerConversationID.length == 0) {
  719. return nil;
  720. }
  721. NSDictionary *dict = [NSUserDefaults.standardUserDefaults objectForKey:@"conversation_backgroundImage_map"];
  722. if (dict == nil) {
  723. dict = @{};
  724. }
  725. NSString *conversationID_UserID = [NSString stringWithFormat:@"%@_%@", targerConversationID, [TUILogin getUserID]];
  726. if (![dict isKindOfClass:NSDictionary.class] || ![dict.allKeys containsObject:conversationID_UserID]) {
  727. return nil;
  728. }
  729. return [dict objectForKey:conversationID_UserID];
  730. }
  731. - (NSString *)getConversationID {
  732. NSString *conversationID = @"";
  733. if (self.conversationData.conversationID.length > 0) {
  734. conversationID = self.conversationData.conversationID;
  735. } else if (self.conversationData.userID.length > 0) {
  736. conversationID = [NSString stringWithFormat:@"c2c_%@", self.conversationData.userID];
  737. } else if (self.conversationData.groupID.length > 0) {
  738. conversationID = [NSString stringWithFormat:@"group_%@", self.conversationData.groupID];
  739. }
  740. return conversationID;
  741. }
  742. #pragma mark - TUIInputControllerDelegate
  743. - (void)inputController:(TUIInputController_Minimalist *)inputController didChangeHeight:(CGFloat)height {
  744. if (!self.responseKeyboard) {
  745. return;
  746. }
  747. [UIView animateWithDuration:0.3
  748. delay:0
  749. options:UIViewAnimationOptionCurveEaseOut
  750. animations:^{
  751. CGRect msgFrame = self.messageController.view.frame;
  752. msgFrame.size.height = self.view.frame.size.height - height - [self topMarginByCustomView];
  753. self.messageController.view.frame = msgFrame;
  754. CGRect inputFrame = self.inputController.view.frame;
  755. inputFrame.origin.y = msgFrame.origin.y + msgFrame.size.height;
  756. inputFrame.size.height = height;
  757. self.inputController.view.frame = inputFrame;
  758. [self.messageController scrollToBottom:NO];
  759. }
  760. completion:nil];
  761. }
  762. - (void)inputController:(TUIInputController_Minimalist *)inputController didSendMessage:(V2TIMMessage *)msg {
  763. [self.messageController sendMessage:msg];
  764. }
  765. - (void)inputControllerDidSelectMoreButton:(TUIInputController_Minimalist *)inputController {
  766. NSArray *items = [self.dataProvider getInputMoreActionItemList:self.conversationData.userID
  767. groupID:self.conversationData.groupID
  768. conversationModel:self.conversationData
  769. pushVC:self.navigationController
  770. actionController:self];
  771. if (items.count) {
  772. UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
  773. [alertVC configItems:items];
  774. [alertVC addAction:[UIAlertAction actionWithTitle:TIMCommonLocalizableString(Cancel) style:UIAlertActionStyleCancel handler:nil]];
  775. [self presentViewController:alertVC animated:YES completion:nil];
  776. }
  777. }
  778. - (void)inputControllerDidSelectCamera:(TUIInputController_Minimalist *)inputController {
  779. [self.mediaProvider takePicture];
  780. }
  781. - (void)inputControllerDidInputAt:(TUIInputController_Minimalist *)inputController {
  782. /**
  783. * Handle to GroupChatVC
  784. */
  785. }
  786. - (void)inputController:(TUIInputController_Minimalist *)inputController didDeleteAt:(NSString *)atText {
  787. /**
  788. * Handle to GroupChatVC
  789. */
  790. }
  791. - (void)inputControllerBeginTyping:(TUIInputController_Minimalist *)inputController {
  792. // for C2CChatVC
  793. }
  794. - (void)inputControllerEndTyping:(TUIInputController_Minimalist *)inputController {
  795. // for C2CChatVC
  796. }
  797. #pragma mark - TUIBaseMessageControllerDelegate
  798. - (void)didTapInMessageController:(TUIBaseMessageController_Minimalist *)controller {
  799. [self.inputController reset];
  800. }
  801. - (BOOL)messageController:(TUIBaseMessageController_Minimalist *)controller willShowMenuInCell:(TUIMessageCell *)cell {
  802. if ([self.inputController.inputBar.inputTextView isFirstResponder]) {
  803. self.inputController.inputBar.inputTextView.overrideNextResponder = cell;
  804. return YES;
  805. }
  806. return NO;
  807. }
  808. - (TUIMessageCellData *)messageController:(TUIBaseMessageController_Minimalist *)controller onNewMessage:(V2TIMMessage *)message {
  809. return nil;
  810. }
  811. - (TUIMessageCell *)messageController:(TUIBaseMessageController_Minimalist *)controller onShowMessageData:(TUIMessageCellData *)data {
  812. return nil;
  813. }
  814. - (void)messageController:(TUIBaseMessageController_Minimalist *)controller willDisplayCell:(TUIMessageCell *)cell withData:(TUIMessageCellData *)cellData {
  815. if ([cell isKindOfClass:[TUIJoinGroupMessageCell_Minimalist class]]) {
  816. TUIJoinGroupMessageCell_Minimalist *joinCell = (TUIJoinGroupMessageCell_Minimalist *)cell;
  817. joinCell.joinGroupDelegate = self;
  818. }
  819. }
  820. - (void)messageController:(TUIBaseMessageController_Minimalist *)controller onSelectMessageAvatar:(TUIMessageCell *)cell {
  821. NSString *userID = nil;
  822. if (cell.messageData.innerMessage.groupID.length > 0) {
  823. userID = cell.messageData.innerMessage.sender;
  824. } else {
  825. if (cell.messageData.isUseMsgReceiverAvatar) {
  826. if (cell.messageData.innerMessage.isSelf) {
  827. userID = cell.messageData.innerMessage.userID;
  828. } else {
  829. userID = V2TIMManager.sharedInstance.getLoginUser;
  830. }
  831. } else {
  832. userID = cell.messageData.innerMessage.sender;
  833. }
  834. }
  835. if (userID == nil) {
  836. return;
  837. }
  838. [self getUserOrFriendProfileVCWithUserID:userID
  839. succBlock:^(UIViewController *vc) {
  840. [self.navigationController pushViewController:vc animated:YES];
  841. }
  842. failBlock:nil];
  843. }
  844. - (void)messageController:(TUIBaseMessageController_Minimalist *)controller onSelectMessageContent:(TUIMessageCell *)cell {
  845. cell.disableDefaultSelectAction = NO;
  846. if (cell.disableDefaultSelectAction) {
  847. return;
  848. }
  849. }
  850. - (void)messageController:(TUIBaseMessageController_Minimalist *)controller onSelectMessageMenu:(NSInteger)menuType withData:(TUIMessageCellData *)data {
  851. [self onSelectMessageMenu:menuType withData:data];
  852. }
  853. - (void)didHideMenuInMessageController:(TUIBaseMessageController_Minimalist *)controller {
  854. self.inputController.inputBar.inputTextView.overrideNextResponder = nil;
  855. }
  856. - (void)messageController:(TUIBaseMessageController_Minimalist *)controller onReEditMessage:(TUIMessageCellData *)data {
  857. V2TIMMessage *message = data.innerMessage;
  858. if (message.elemType == V2TIM_ELEM_TYPE_TEXT) {
  859. NSString *text = message.textElem.text;
  860. self.inputController.inputBar.inputTextView.text = text;
  861. [self.inputController.inputBar.inputTextView becomeFirstResponder];
  862. }
  863. }
  864. - (CGFloat)getTopMarginByCustomView {
  865. return [self topMarginByCustomView];
  866. }
  867. - (void)messageController:(TUIBaseMessageController_Minimalist *)controller onSelectMessageWhenMultiCheckboxAppear:(TUIMessageCellData *)data {
  868. if (_multiChooseView) {
  869. NSArray *uiMsgs = [self.messageController multiSelectedResult:TUIMultiResultOptionAll];
  870. _multiChooseView.selectedCountLabel.text =
  871. [NSString stringWithFormat:@"%lu %@", (unsigned long)uiMsgs.count, TIMCommonLocalizableString(TUIKitSelected)];
  872. }
  873. }
  874. #pragma mark - TUIChatBaseDataProviderDelegate
  875. - (NSString *)dataProvider:(TUIChatBaseDataProvider *)dataProvider mergeForwardTitleWithMyName:(NSString *)name {
  876. return [self forwardTitleWithMyName:name];
  877. }
  878. - (NSString *)dataProvider:(TUIChatBaseDataProvider *)dataProvider mergeForwardMsgAbstactForMessage:(V2TIMMessage *)message {
  879. return @"";
  880. }
  881. - (void)dataProvider:(TUIChatBaseDataProvider *)dataProvider sendMessage:(V2TIMMessage *)message {
  882. [self.messageController sendMessage:message];
  883. }
  884. - (void)onSelectPhotoMoreCellData {
  885. [self.mediaProvider selectPhoto];
  886. }
  887. - (void)onTakePictureMoreCellData {
  888. [self.mediaProvider takePicture];
  889. }
  890. - (void)onTakeVideoMoreCellData {
  891. [self.mediaProvider takeVideo];
  892. }
  893. - (void)onSelectFileMoreCellData {
  894. [self.mediaProvider selectFile];
  895. }
  896. #pragma mark - TUINavigationControllerDelegate
  897. - (void)navigationControllerDidClickLeftButton:(TUINavigationController *)controller {
  898. if (controller.currentShowVC == self) {
  899. [self.messageController readReport];
  900. }
  901. }
  902. - (void)navigationControllerDidSideSlideReturn:(TUINavigationController *)controller fromViewController:(UIViewController *)fromViewController {
  903. if ([fromViewController isEqual:self]) {
  904. [self.messageController readReport];
  905. }
  906. }
  907. #pragma mark - MessageMenu
  908. - (void)onSelectMessageMenu:(NSInteger)menuType withData:(TUIMessageCellData *)data {
  909. if (menuType == 0) {
  910. [self openMultiChooseBoard:YES];
  911. } else if (menuType == 1) {
  912. if (data == nil) {
  913. return;
  914. }
  915. NSMutableArray *uiMsgs = [NSMutableArray arrayWithArray:@[ data ]];
  916. [self prepareForwardMessages:uiMsgs];
  917. }
  918. }
  919. - (void)openMultiChooseBoard:(BOOL)open {
  920. [self.view endEditing:YES];
  921. if (_multiChooseView) {
  922. [_multiChooseView removeFromSuperview];
  923. }
  924. if (open) {
  925. _multiChooseView = [[TUIMessageMultiChooseView_Minimalist alloc] init];
  926. _multiChooseView.frame = UIScreen.mainScreen.bounds;
  927. _multiChooseView.delegate = self;
  928. _multiChooseView.titleLabel.text = self.conversationData.title;
  929. _multiChooseView.selectedCountLabel.text = [NSString stringWithFormat:@"%d %@", 1, TIMCommonLocalizableString(TUIKitSelected)];
  930. if (@available(iOS 12.0, *)) {
  931. if (@available(iOS 13.0, *)) {
  932. // > ios 12
  933. [UIApplication.sharedApplication.keyWindow addSubview:_multiChooseView];
  934. } else {
  935. // ios = 12
  936. UIView *view = self.navigationController.view;
  937. if (view == nil) {
  938. view = self.view;
  939. }
  940. [view addSubview:_multiChooseView];
  941. }
  942. } else {
  943. // < ios 12
  944. [UIApplication.sharedApplication.keyWindow addSubview:_multiChooseView];
  945. }
  946. } else {
  947. [self.messageController enableMultiSelectedMode:NO];
  948. }
  949. }
  950. - (void)messageMultiChooseViewOnCancelClicked:(TUIMessageMultiChooseView_Minimalist *)multiChooseView {
  951. [self openMultiChooseBoard:NO];
  952. [self.messageController enableMultiSelectedMode:NO];
  953. }
  954. - (void)messageMultiChooseViewOnRelayClicked:(TUIMessageMultiChooseView_Minimalist *)multiChooseView {
  955. NSArray *uiMsgs = [self.messageController multiSelectedResult:TUIMultiResultOptionAll];
  956. [self prepareForwardMessages:uiMsgs];
  957. }
  958. - (void)messageMultiChooseViewOnDeleteClicked:(TUIMessageMultiChooseView_Minimalist *)multiChooseView {
  959. NSArray *uiMsgs = [self.messageController multiSelectedResult:TUIMultiResultOptionAll];
  960. if (uiMsgs.count == 0) {
  961. [TUITool makeToast:TIMCommonLocalizableString(TUIKitRelayNoMessageTips)];
  962. return;
  963. }
  964. [self.messageController deleteMessages:uiMsgs];
  965. [self openMultiChooseBoard:NO];
  966. [self.messageController enableMultiSelectedMode:NO];
  967. }
  968. - (void)prepareForwardMessages:(NSArray<TUIMessageCellData *> *)uiMsgs {
  969. if (uiMsgs.count == 0) {
  970. [TUITool makeToast:TIMCommonLocalizableString(TUIKitRelayNoMessageTips)];
  971. return;
  972. }
  973. BOOL hasUnsupportMsg = NO;
  974. for (TUIMessageCellData *data in uiMsgs) {
  975. if (data.status != Msg_Status_Succ) {
  976. hasUnsupportMsg = YES;
  977. break;
  978. }
  979. }
  980. if (hasUnsupportMsg) {
  981. UIAlertController *vc = [UIAlertController alertControllerWithTitle:TIMCommonLocalizableString(TUIKitRelayUnsupportForward)
  982. message:nil
  983. preferredStyle:UIAlertControllerStyleAlert];
  984. [vc tuitheme_addAction:[UIAlertAction actionWithTitle:TIMCommonLocalizableString(Confirm)
  985. style:UIAlertActionStyleDefault
  986. handler:^(UIAlertAction *_Nonnull action){
  987. }]];
  988. [self presentViewController:vc animated:YES completion:nil];
  989. return;
  990. }
  991. __weak typeof(self) weakSelf = self;
  992. UIAlertController *tipsVc = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
  993. // Forward one-by-one
  994. [tipsVc
  995. tuitheme_addAction:[UIAlertAction actionWithTitle:TIMCommonLocalizableString(TUIKitRelayOneByOneForward)
  996. style:UIAlertActionStyleDefault
  997. handler:^(UIAlertAction *_Nonnull action) {
  998. if (uiMsgs.count <= 30) {
  999. [weakSelf selectTarget:NO toForwardMessage:uiMsgs orForwardText:nil];
  1000. return;
  1001. }
  1002. UIAlertController *vc =
  1003. [UIAlertController alertControllerWithTitle:TIMCommonLocalizableString(TUIKitRelayOneByOnyOverLimit)
  1004. message:nil
  1005. preferredStyle:UIAlertControllerStyleAlert];
  1006. [vc tuitheme_addAction:[UIAlertAction actionWithTitle:TIMCommonLocalizableString(Cancel)
  1007. style:UIAlertActionStyleDefault
  1008. handler:nil]];
  1009. [vc tuitheme_addAction:[UIAlertAction actionWithTitle:TIMCommonLocalizableString(TUIKitRelayCombineForwad)
  1010. style:UIAlertActionStyleDefault
  1011. handler:^(UIAlertAction *_Nonnull action) {
  1012. [weakSelf selectTarget:YES
  1013. toForwardMessage:uiMsgs
  1014. orForwardText:nil];
  1015. }]];
  1016. [weakSelf presentViewController:vc animated:YES completion:nil];
  1017. }]];
  1018. // Merge-forward
  1019. [tipsVc tuitheme_addAction:[UIAlertAction actionWithTitle:TIMCommonLocalizableString(TUIKitRelayCombineForwad)
  1020. style:UIAlertActionStyleDefault
  1021. handler:^(UIAlertAction *_Nonnull action) {
  1022. [weakSelf selectTarget:YES toForwardMessage:uiMsgs orForwardText:nil];
  1023. }]];
  1024. [tipsVc tuitheme_addAction:[UIAlertAction actionWithTitle:TIMCommonLocalizableString(Cancel) style:UIAlertActionStyleCancel handler:nil]];
  1025. [self presentViewController:tipsVc animated:YES completion:nil];
  1026. }
  1027. - (void)selectTarget:(BOOL)mergeForward toForwardMessage:(NSArray<TUIMessageCellData *> *)uiMsgs orForwardText:(NSString *)forwardText {
  1028. __weak typeof(self) weakSelf = self;
  1029. UIViewController *vc = (UIViewController *)[TUICore createObject:TUICore_TUIConversationObjectFactory_Minimalist
  1030. key:TUICore_TUIConversationObjectFactory_ConversationSelectVC_Minimalist
  1031. param:nil];
  1032. vc.navigateValueCallback = ^(NSDictionary *param) {
  1033. NSArray<NSDictionary *> *selectList = param[TUICore_TUIConversationObjectFactory_ConversationSelectVC_ResultList];
  1034. NSMutableArray<TUIChatConversationModel *> *targetList = [NSMutableArray arrayWithCapacity:selectList.count];
  1035. for (NSDictionary *selectItem in selectList) {
  1036. TUIChatConversationModel *model = [TUIChatConversationModel new];
  1037. model.title = selectItem[TUICore_TUIConversationObjectFactory_ConversationSelectVC_ResultList_Title];
  1038. model.userID = selectItem[TUICore_TUIConversationObjectFactory_ConversationSelectVC_ResultList_UserID];
  1039. model.groupID = selectItem[TUICore_TUIConversationObjectFactory_ConversationSelectVC_ResultList_GroupID];
  1040. model.conversationID = selectItem[TUICore_TUIConversationObjectFactory_ConversationSelectVC_ResultList_ConversationID];
  1041. [targetList addObject:model];
  1042. }
  1043. if (uiMsgs.count > 0) {
  1044. [weakSelf forwardMessages:uiMsgs toTargets:targetList merge:mergeForward];
  1045. } else if (forwardText.length > 0) {
  1046. [weakSelf forwardText:forwardText toConverations:targetList];
  1047. }
  1048. };
  1049. TUIFloatViewController *floatVC = [[TUIFloatViewController alloc] init];
  1050. [floatVC appendChildViewController:(id)vc topMargin:kScale390(87.5)];
  1051. [floatVC.topGestureView setTitleText:@""
  1052. subTitleText:@""
  1053. leftBtnText:TIMCommonLocalizableString(TUIKitCreateCancel)
  1054. rightBtnText:TIMCommonLocalizableString(MultiSelect)];
  1055. floatVC.topGestureView.subTitleLabel.hidden = YES;
  1056. [self presentViewController:floatVC
  1057. animated:YES
  1058. completion:^{
  1059. [weakSelf openMultiChooseBoard:NO];
  1060. [weakSelf.messageController enableMultiSelectedMode:NO];
  1061. }];
  1062. }
  1063. - (void)forwardMessages:(NSArray<TUIMessageCellData *> *)uiMsgs toTargets:(NSArray<TUIChatConversationModel *> *)targets merge:(BOOL)merge {
  1064. if (uiMsgs.count == 0 || targets.count == 0) {
  1065. return;
  1066. }
  1067. @weakify(self);
  1068. [self.dataProvider getForwardMessageWithCellDatas:uiMsgs
  1069. toTargets:targets
  1070. Merge:merge
  1071. ResultBlock:^(TUIChatConversationModel *_Nonnull targetConversation, NSArray<V2TIMMessage *> *_Nonnull msgs) {
  1072. @strongify(self);
  1073. TUIChatConversationModel *convCellData = targetConversation;
  1074. NSTimeInterval timeInterval = convCellData.groupID.length ? 0.09 : 0.05;
  1075. TUISendMessageAppendParams *appendParams = [[TUISendMessageAppendParams alloc] init];
  1076. appendParams.isSendPushInfo = YES;
  1077. appendParams.isOnlineUserOnly = NO;
  1078. appendParams.priority = V2TIM_PRIORITY_NORMAL;
  1079. /**
  1080. *
  1081. * Forward to currernt chat vc
  1082. */
  1083. if ([convCellData.conversationID isEqualToString:self.conversationData.conversationID]) {
  1084. dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  1085. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  1086. dispatch_async(queue, ^{
  1087. for (V2TIMMessage *imMsg in msgs) {
  1088. dispatch_async(dispatch_get_main_queue(), ^{
  1089. [self.messageController sendMessage:imMsg];
  1090. dispatch_semaphore_signal(semaphore);
  1091. });
  1092. dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  1093. [NSThread sleepForTimeInterval:timeInterval];
  1094. }
  1095. });
  1096. return;
  1097. }
  1098. /**
  1099. * Forward to other chat user
  1100. */
  1101. for (V2TIMMessage *message in msgs) {
  1102. message.needReadReceipt = self.conversationData.msgNeedReadReceipt && [TUIChatConfig defaultConfig].msgNeedReadReceipt;
  1103. [TUIMessageDataProvider sendMessage:message
  1104. toConversation:convCellData
  1105. appendParams:appendParams
  1106. Progress:nil
  1107. SuccBlock:^{
  1108. /**
  1109. * Messages sent to other chats need to broadcast the message sending status, which is convenient to refresh the message status after
  1110. * entering the corresponding chat
  1111. */
  1112. [NSNotificationCenter.defaultCenter postNotificationName:TUIKitNotification_onMessageStatusChanged object:message];
  1113. }
  1114. FailBlock:^(int code, NSString *desc) {
  1115. [NSNotificationCenter.defaultCenter postNotificationName:TUIKitNotification_onMessageStatusChanged object:message];
  1116. }];
  1117. /**
  1118. * The delay here is to ensure the order of the receiving end as much as possible when forwarding in batches one by one
  1119. */
  1120. [NSThread sleepForTimeInterval:timeInterval];
  1121. }
  1122. }
  1123. fail:^(int code, NSString *desc) {
  1124. NSLog(@"%@", desc);
  1125. NSAssert(NO, desc);
  1126. }];
  1127. }
  1128. - (NSString *)forwardTitleWithMyName:(NSString *)nameStr {
  1129. return @"";
  1130. }
  1131. #pragma mark - Message reply
  1132. - (void)messageController:(TUIBaseMessageController_Minimalist *)controller onRelyMessage:(nonnull TUIMessageCellData *)data {
  1133. @weakify(self);
  1134. [self.inputController exitReplyAndReference:^{
  1135. @strongify(self);
  1136. NSString *desc = @"";
  1137. desc = [self replyReferenceMessageDesc:data];
  1138. TUIReplyPreviewData *replyData = [[TUIReplyPreviewData alloc] init];
  1139. replyData.msgID = data.msgID;
  1140. replyData.msgAbstract = desc;
  1141. replyData.sender = data.senderName;
  1142. replyData.type = (NSInteger)data.innerMessage.elemType;
  1143. replyData.originMessage = data.innerMessage;
  1144. NSMutableDictionary *cloudResultDic = [[NSMutableDictionary alloc] initWithCapacity:5];
  1145. if (replyData.originMessage.cloudCustomData) {
  1146. NSDictionary *originDic = [TUITool jsonData2Dictionary:replyData.originMessage.cloudCustomData];
  1147. if (originDic && [originDic isKindOfClass:[NSDictionary class]]) {
  1148. [cloudResultDic addEntriesFromDictionary:originDic];
  1149. }
  1150. }
  1151. NSString *messageParentReply = cloudResultDic[@"messageReply"];
  1152. NSString *messageRootID = [messageParentReply valueForKey:@"messageRootID"];
  1153. if (!IS_NOT_EMPTY_NSSTRING(messageRootID)) {
  1154. /**
  1155. * If the original message does not have messageRootID, you need to make the msgID of the current original message as the root
  1156. */
  1157. if (IS_NOT_EMPTY_NSSTRING(replyData.originMessage.msgID)) {
  1158. messageRootID = replyData.originMessage.msgID;
  1159. }
  1160. }
  1161. replyData.messageRootID = messageRootID;
  1162. [self.inputController showReplyPreview:replyData];
  1163. }];
  1164. }
  1165. - (NSString *)replyReferenceMessageDesc:(TUIMessageCellData *)data {
  1166. NSString *desc = @"";
  1167. if (data.innerMessage.elemType == V2TIM_ELEM_TYPE_FILE) {
  1168. desc = data.innerMessage.fileElem.filename;
  1169. } else if (data.innerMessage.elemType == V2TIM_ELEM_TYPE_MERGER) {
  1170. desc = data.innerMessage.mergerElem.title;
  1171. } else if (data.innerMessage.elemType == V2TIM_ELEM_TYPE_CUSTOM) {
  1172. desc = [TUIMessageDataProvider getDisplayString:data.innerMessage];
  1173. } else if (data.innerMessage.elemType == V2TIM_ELEM_TYPE_TEXT) {
  1174. desc = data.innerMessage.textElem.text;
  1175. }
  1176. return desc;
  1177. }
  1178. #pragma mark - Message quote
  1179. - (void)messageController:(TUIBaseMessageController_Minimalist *)controller onReferenceMessage:(TUIMessageCellData *)data {
  1180. @weakify(self);
  1181. [self.inputController exitReplyAndReference:^{
  1182. @strongify(self);
  1183. NSString *desc = @"";
  1184. desc = [self replyReferenceMessageDesc:data];
  1185. TUIReferencePreviewData *referenceData = [[TUIReferencePreviewData alloc] init];
  1186. referenceData.msgID = data.msgID;
  1187. referenceData.msgAbstract = desc;
  1188. referenceData.sender = data.senderName;
  1189. referenceData.type = (NSInteger)data.innerMessage.elemType;
  1190. referenceData.originMessage = data.innerMessage;
  1191. [self.inputController showReferencePreview:referenceData];
  1192. }];
  1193. }
  1194. #pragma mark - Translation forward
  1195. - (void)messageController:(TUIBaseMessageController_Minimalist *)controller onForwardText:(NSString *)text {
  1196. if (text.length == 0) {
  1197. return;
  1198. }
  1199. [self selectTarget:NO toForwardMessage:nil orForwardText:text];
  1200. }
  1201. - (void)forwardText:(NSString *)text toConverations:(NSArray<TUIChatConversationModel *> *)conversations {
  1202. TUISendMessageAppendParams *appendParams = [[TUISendMessageAppendParams alloc] init];
  1203. appendParams.isSendPushInfo = YES;
  1204. appendParams.isOnlineUserOnly = NO;
  1205. appendParams.priority = V2TIM_PRIORITY_NORMAL;
  1206. for (TUIChatConversationModel *conversation in conversations) {
  1207. V2TIMMessage *message = [[V2TIMManager sharedInstance] createTextMessage:text];
  1208. dispatch_async(dispatch_get_main_queue(), ^{
  1209. if ([conversation.conversationID isEqualToString:self.conversationData.conversationID]) {
  1210. // Send text to myself
  1211. [self.messageController sendMessage:message];
  1212. } else {
  1213. // Send to other conversation
  1214. message.needReadReceipt = self.conversationData.msgNeedReadReceipt && [TUIChatConfig defaultConfig].msgNeedReadReceipt;
  1215. [TUIMessageBaseDataProvider sendMessage:message
  1216. toConversation:conversation
  1217. appendParams:appendParams
  1218. Progress:nil
  1219. SuccBlock:^{
  1220. [NSNotificationCenter.defaultCenter postNotificationName:TUIKitNotification_onMessageStatusChanged object:message];
  1221. }
  1222. FailBlock:^(int code, NSString *desc) {
  1223. [NSNotificationCenter.defaultCenter postNotificationName:TUIKitNotification_onMessageStatusChanged object:message];
  1224. }];
  1225. }
  1226. });
  1227. }
  1228. }
  1229. #pragma mark - Private Methods
  1230. + (void)createCachePath {
  1231. NSFileManager *fileManager = [NSFileManager defaultManager];
  1232. if (![fileManager fileExistsAtPath:TUIKit_Image_Path]) {
  1233. [fileManager createDirectoryAtPath:TUIKit_Image_Path withIntermediateDirectories:YES attributes:nil error:nil];
  1234. }
  1235. if (![fileManager fileExistsAtPath:TUIKit_Video_Path]) {
  1236. [fileManager createDirectoryAtPath:TUIKit_Video_Path withIntermediateDirectories:YES attributes:nil error:nil];
  1237. }
  1238. if (![fileManager fileExistsAtPath:TUIKit_Voice_Path]) {
  1239. [fileManager createDirectoryAtPath:TUIKit_Voice_Path withIntermediateDirectories:YES attributes:nil error:nil];
  1240. }
  1241. if (![fileManager fileExistsAtPath:TUIKit_File_Path]) {
  1242. [fileManager createDirectoryAtPath:TUIKit_File_Path withIntermediateDirectories:YES attributes:nil error:nil];
  1243. }
  1244. if (![fileManager fileExistsAtPath:TUIKit_DB_Path]) {
  1245. [fileManager createDirectoryAtPath:TUIKit_DB_Path withIntermediateDirectories:YES attributes:nil error:nil];
  1246. }
  1247. }
  1248. #pragma mark - TUIJoinGroupMessageCellDelegate
  1249. - (void)didTapOnRestNameLabel:(TUIJoinGroupMessageCell_Minimalist *)cell withIndex:(NSInteger)index {
  1250. NSString *userId = cell.joinData.userIDList[index];
  1251. [self getUserOrFriendProfileVCWithUserID:userId
  1252. succBlock:^(UIViewController *vc) {
  1253. [self.navigationController pushViewController:vc animated:YES];
  1254. }
  1255. failBlock:^(int code, NSString *desc) {
  1256. [TUITool makeToastError:code msg:desc];
  1257. }];
  1258. }
  1259. #pragma mark - V2TIMConversationListener
  1260. - (void)onConversationChanged:(NSArray<V2TIMConversation *> *)conversationList {
  1261. for (V2TIMConversation *conv in conversationList) {
  1262. if ([conv.conversationID isEqualToString:self.conversationData.conversationID]) {
  1263. if (!self.conversationData.otherSideTyping) {
  1264. self.conversationData.title = conv.showName;
  1265. }
  1266. break;
  1267. }
  1268. }
  1269. }
  1270. #pragma mark - FriendInfoChangedNotification
  1271. - (void)onFriendInfoChanged:(NSNotification *)notice {
  1272. [self checkTitle:YES];
  1273. }
  1274. #pragma mark - Media Provider
  1275. - (void)sendPlaceHolderUIMessage:(TUIMessageCellData *)cellData {
  1276. [self.messageController sendPlaceHolderUIMessage:cellData];
  1277. }
  1278. - (TUIChatMediaDataProvider *)mediaProvider {
  1279. if (_mediaProvider == nil) {
  1280. _mediaProvider = [[TUIChatMediaDataProvider alloc] init];
  1281. _mediaProvider.listener = self;
  1282. _mediaProvider.presentViewController = self;
  1283. _mediaProvider.conversationID = _conversationData.conversationID;
  1284. }
  1285. return _mediaProvider;
  1286. }
  1287. - (void)onProvideImage:(NSString *)imageUrl {
  1288. V2TIMMessage *message = [V2TIMManager.sharedInstance createImageMessage:imageUrl];
  1289. [self sendMessage:message];
  1290. }
  1291. - (void)onProvideImageError:(NSString *)errorMessage {
  1292. [TUITool makeToast:errorMessage];
  1293. }
  1294. - (void)onProvidePlaceholderVideoSnapshot:(NSString *)snapshotUrl
  1295. SnapImage:(UIImage *)image
  1296. Completion:(void (^__nullable)(BOOL finished, TUIMessageCellData *placeHolderCellData))completion {
  1297. TUIMessageCellData *videoCellData = [TUIVideoMessageCellData placeholderCellDataWithSnapshotUrl:snapshotUrl thubImage:image];
  1298. [self.messageController sendPlaceHolderUIMessage:videoCellData];
  1299. if (completion) {
  1300. completion(YES,videoCellData);
  1301. }
  1302. }
  1303. - (void)onProvideVideo:(NSString *)videoUrl
  1304. snapshot:(NSString *)snapshotUrl
  1305. duration:(NSInteger)duration
  1306. placeHolderCellData:(TUIMessageCellData *)placeHolderCellData {
  1307. V2TIMMessage *message = [V2TIMManager.sharedInstance createVideoMessage:videoUrl
  1308. type:videoUrl.pathExtension
  1309. duration:(int)duration
  1310. snapshotPath:snapshotUrl];
  1311. [self sendMessage:message placeHolderCellData:placeHolderCellData];
  1312. }
  1313. - (void)onProvideVideoError:(NSString *)errorMessage {
  1314. [TUITool makeToast:errorMessage];
  1315. }
  1316. - (void)onProvideFile:(NSString *)fileUrl filename:(NSString *)filename fileSize:(NSInteger)fileSize {
  1317. V2TIMMessage *message = [V2TIMManager.sharedInstance createFileMessage:fileUrl fileName:filename];
  1318. [self sendMessage:message];
  1319. }
  1320. - (void)onProvideFileError:(NSString *)errorMessage {
  1321. [TUITool makeToast:errorMessage];
  1322. }
  1323. - (NSString *)currentConversationID {
  1324. return self.conversationData.conversationID;
  1325. }
  1326. - (BOOL)isPageAppears {
  1327. return self.responseKeyboard;
  1328. }
  1329. @end