TUIChatDataProvider.m 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. // Created by Tencent on 2023/06/09.
  2. // Copyright © 2023 Tencent. All rights reserved.
  3. @import ImSDK_Plus;
  4. #import <objc/runtime.h>
  5. #import <TUICore/NSDictionary+TUISafe.h>
  6. #import <TUICore/TUICore.h>
  7. #import <TUICore/TUIThemeManager.h>
  8. #import "UIAlertController+TUICustomStyle.h"
  9. #import "TUIChatConfig.h"
  10. #import "TUIChatDataProvider.h"
  11. #import "TUIMessageDataProvider.h"
  12. #import "TUIVideoMessageCellData.h"
  13. #import "TUIChatConversationModel.h"
  14. #import <TIMCommon/TIMCommonMediator.h>
  15. #import <TIMCommon/TUIEmojiMeditorProtocol.h>
  16. #define Input_SendBtn_Key @"Input_SendBtn_Key"
  17. #define Input_SendBtn_Title @"Input_SendBtn_Title"
  18. #define Input_SendBtn_ImageName @"Input_SendBtn_ImageName"
  19. @interface TUISplitEmojiData : NSObject
  20. @property (nonatomic, assign) NSInteger start;
  21. @property (nonatomic, assign) NSInteger end;
  22. @end
  23. @implementation TUISplitEmojiData
  24. @end
  25. @interface TUIChatDataProvider ()
  26. @property(nonatomic, strong) TUIInputMoreCellData *welcomeInputMoreMenu;
  27. @property(nonatomic, strong) NSMutableArray<TUIInputMoreCellData *> *customInputMoreMenus;
  28. @property(nonatomic, strong) NSArray<TUIInputMoreCellData *> *builtInInputMoreMenus;
  29. @property(nonatomic, strong) NSArray<TUICustomActionSheetItem *> *customInputMoreActionItemList;
  30. @property(nonatomic, strong) NSMutableArray<TUICustomActionSheetItem *> *builtInInputMoreActionItemList;
  31. @end
  32. @implementation TUIChatDataProvider
  33. - (instancetype)init {
  34. if (self = [super init]) {
  35. [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(onChangeLanguage) name:TUIChangeLanguageNotification object:nil];
  36. }
  37. return self;
  38. }
  39. #pragma mark - Public
  40. // For Classic Edition.
  41. - (NSMutableArray<TUIInputMoreCellData *> *)getMoreMenuCellDataArray:(NSString *)groupID
  42. userID:(NSString *)userID
  43. conversationModel:(TUIChatConversationModel *)conversationModel
  44. actionController:(id<TIMInputViewMoreActionProtocol>)actionController {
  45. self.builtInInputMoreMenus = [self createBuiltInInputMoreMenusWithConversationModel:conversationModel];
  46. NSMutableArray *moreMenus = [NSMutableArray array];
  47. [moreMenus addObjectsFromArray:self.builtInInputMoreMenus];
  48. BOOL isNeedWelcomeCustomMessage = [TUIChatConfig defaultConfig].enableWelcomeCustomMessage && conversationModel.enableWelcomeCustomMessage;
  49. if (isNeedWelcomeCustomMessage) {
  50. if (![self.customInputMoreMenus containsObject:self.welcomeInputMoreMenu]) {
  51. [self.customInputMoreMenus addObject:self.welcomeInputMoreMenu];
  52. }
  53. }
  54. [moreMenus addObjectsFromArray:self.customInputMoreMenus];
  55. // Extension items
  56. BOOL isNeedVideoCall = [TUIChatConfig defaultConfig].enableVideoCall && conversationModel.enableVideoCall;
  57. BOOL isNeedAudioCall = [TUIChatConfig defaultConfig].enableAudioCall && conversationModel.enableAudioCall;
  58. BOOL isNeedRoom = [TUIChatConfig defaultConfig].showRoomButton && conversationModel.enableRoom;
  59. BOOL isNeedPoll = [TUIChatConfig defaultConfig].showPollButton && conversationModel.enablePoll;
  60. BOOL isNeedGroupNote = [TUIChatConfig defaultConfig].showGroupNoteButton && conversationModel.enableGroupNote;
  61. NSMutableDictionary *extensionParam = [NSMutableDictionary dictionary];
  62. if (userID.length > 0) {
  63. extensionParam[TUICore_TUIChatExtension_InputViewMoreItem_UserID] = userID;
  64. } else if (groupID.length > 0) {
  65. extensionParam[TUICore_TUIChatExtension_InputViewMoreItem_GroupID] = groupID;
  66. }
  67. extensionParam[TUICore_TUIChatExtension_InputViewMoreItem_FilterVideoCall] = @(!isNeedVideoCall);
  68. extensionParam[TUICore_TUIChatExtension_InputViewMoreItem_FilterAudioCall] = @(!isNeedAudioCall);
  69. extensionParam[TUICore_TUIChatExtension_InputViewMoreItem_FilterRoom] = @(!isNeedRoom);
  70. extensionParam[TUICore_TUIChatExtension_InputViewMoreItem_FilterPoll] = @(!isNeedPoll);
  71. extensionParam[TUICore_TUIChatExtension_InputViewMoreItem_FilterGroupNote] = @(!isNeedGroupNote);
  72. extensionParam[TUICore_TUIChatExtension_InputViewMoreItem_ActionVC] = actionController;
  73. NSArray *extensionList = [TUICore getExtensionList:TUICore_TUIChatExtension_InputViewMoreItem_ClassicExtensionID param:extensionParam];
  74. for (TUIExtensionInfo *info in extensionList) {
  75. NSAssert(info.icon && info.text && info.onClicked, @"extension for input view is invalid, check icon/text/onclick");
  76. if (info.icon && info.text && info.onClicked) {
  77. TUIInputMoreCellData *data = [[TUIInputMoreCellData alloc] init];
  78. data.priority = info.weight;
  79. data.image = info.icon;
  80. data.title = info.text;
  81. data.onClicked = info.onClicked;
  82. [moreMenus addObject:data];
  83. }
  84. }
  85. // Customized items
  86. if (conversationModel.customizedNewItemsInMoreMenu.count > 0) {
  87. [moreMenus addObjectsFromArray:conversationModel.customizedNewItemsInMoreMenu];
  88. }
  89. // Sort with priority
  90. NSArray *sortedMenus = [moreMenus sortedArrayUsingComparator:^NSComparisonResult(TUIInputMoreCellData *obj1, TUIInputMoreCellData *obj2) {
  91. return obj1.priority > obj2.priority ? NSOrderedAscending : NSOrderedDescending;
  92. }];
  93. return [NSMutableArray arrayWithArray:sortedMenus];
  94. }
  95. // For Minimalist Edition.
  96. - (NSArray<TUICustomActionSheetItem *> *)getInputMoreActionItemList:(NSString *)userID
  97. groupID:(NSString *)groupID
  98. conversationModel:(TUIChatConversationModel *)conversationModel
  99. pushVC:(UINavigationController *)pushVC
  100. actionController:(id<TIMInputViewMoreActionProtocol>)actionController {
  101. NSMutableArray *result = [NSMutableArray array];
  102. [result addObjectsFromArray:[self createBuiltInInputMoreActionItemList:conversationModel]];
  103. [result addObjectsFromArray:[self createCustomInputMoreActionItemList:conversationModel]];
  104. // Extension items
  105. NSMutableArray<TUICustomActionSheetItem *> *items = [NSMutableArray array];
  106. NSMutableDictionary *param = [NSMutableDictionary dictionary];
  107. if (userID.length > 0) {
  108. param[TUICore_TUIChatExtension_InputViewMoreItem_UserID] = userID;
  109. } else if (groupID.length > 0) {
  110. param[TUICore_TUIChatExtension_InputViewMoreItem_GroupID] = groupID;
  111. }
  112. param[TUICore_TUIChatExtension_InputViewMoreItem_FilterVideoCall] = @(!TUIChatConfig.defaultConfig.enableVideoCall);
  113. param[TUICore_TUIChatExtension_InputViewMoreItem_FilterAudioCall] = @(!TUIChatConfig.defaultConfig.enableAudioCall);
  114. if (pushVC) {
  115. param[TUICore_TUIChatExtension_InputViewMoreItem_PushVC] = pushVC;
  116. }
  117. param[TUICore_TUIChatExtension_InputViewMoreItem_ActionVC] = actionController;
  118. NSArray *extensionList = [TUICore getExtensionList:TUICore_TUIChatExtension_InputViewMoreItem_MinimalistExtensionID param:param];
  119. for (TUIExtensionInfo *info in extensionList) {
  120. if (info.icon && info.text && info.onClicked) {
  121. TUICustomActionSheetItem *item = [[TUICustomActionSheetItem alloc] initWithTitle:info.text
  122. leftMark:info.icon
  123. withActionHandler:^(UIAlertAction *_Nonnull action) {
  124. info.onClicked(param);
  125. }];
  126. item.priority = info.weight;
  127. [items addObject:item];
  128. }
  129. }
  130. if (items.count > 0) {
  131. [result addObjectsFromArray:items];
  132. }
  133. // Sort with priority
  134. NSArray *sorted = [result sortedArrayUsingComparator:^NSComparisonResult(TUICustomActionSheetItem *obj1, TUICustomActionSheetItem *obj2) {
  135. return obj1.priority > obj2.priority ? NSOrderedAscending : NSOrderedDescending;
  136. }];
  137. return sorted;
  138. }
  139. #pragma mark - Private
  140. - (void)onChangeLanguage {
  141. self.customInputMoreActionItemList = nil;
  142. self.builtInInputMoreActionItemList = nil;
  143. }
  144. #pragma mark -- Classic
  145. - (NSArray<TUIInputMoreCellData *> *)createBuiltInInputMoreMenusWithConversationModel:(TUIChatConversationModel *)conversationModel {
  146. BOOL isNeedRecordVideo = [TUIChatConfig defaultConfig].showRecordVideoButton && conversationModel.enableRecordVideo;
  147. BOOL isNeedTakePhoto = [TUIChatConfig defaultConfig].showTakePhotoButton && conversationModel.enableTakePhoto;
  148. BOOL isNeedAlbum = [TUIChatConfig defaultConfig].showAlbumButton && conversationModel.enableAlbum;
  149. BOOL isNeedFile = [TUIChatConfig defaultConfig].showFileButton && conversationModel.enableFile;
  150. __weak typeof(self) weakSelf = self;
  151. TUIInputMoreCellData *albumData = [[TUIInputMoreCellData alloc] init];
  152. albumData.priority = 1000;
  153. albumData.title = TIMCommonLocalizableString(TUIKitMorePhoto);
  154. albumData.image = TUIChatBundleThemeImage(@"chat_more_picture_img", @"more_picture_2");
  155. albumData.onClicked = ^(NSDictionary *actionParam) {
  156. if ([weakSelf.delegate respondsToSelector:@selector(onSelectPhotoMoreCellData)]) {
  157. [weakSelf.delegate onSelectPhotoMoreCellData];
  158. }
  159. };
  160. TUIInputMoreCellData *takePictureData = [[TUIInputMoreCellData alloc] init];
  161. takePictureData.priority = 900;
  162. takePictureData.title = TIMCommonLocalizableString(TUIKitMoreCamera);
  163. takePictureData.image = TUIChatBundleThemeImage(@"chat_more_camera_img", @"more_camera_2");
  164. takePictureData.onClicked = ^(NSDictionary *actionParam) {
  165. if ([weakSelf.delegate respondsToSelector:@selector(onTakePictureMoreCellData)]) {
  166. [weakSelf.delegate onTakePictureMoreCellData];
  167. }
  168. };
  169. TUIInputMoreCellData *videoData = [[TUIInputMoreCellData alloc] init];
  170. videoData.priority = 800;
  171. videoData.title = TIMCommonLocalizableString(TUIKitMoreVideo);
  172. videoData.image = TUIChatBundleThemeImage(@"chat_more_video_img", @"more_video_2");
  173. videoData.onClicked = ^(NSDictionary *actionParam) {
  174. if ([weakSelf.delegate respondsToSelector:@selector(onTakeVideoMoreCellData)]) {
  175. [weakSelf.delegate onTakeVideoMoreCellData];
  176. }
  177. };
  178. TUIInputMoreCellData *fileData = [[TUIInputMoreCellData alloc] init];
  179. fileData.priority = 700;
  180. fileData.title = TIMCommonLocalizableString(TUIKitMoreFile);
  181. fileData.image = TUIChatBundleThemeImage(@"chat_more_file_img", @"more_file");
  182. fileData.onClicked = ^(NSDictionary *actionParam) {
  183. if ([weakSelf.delegate respondsToSelector:@selector(onSelectFileMoreCellData)]) {
  184. [weakSelf.delegate onSelectFileMoreCellData];
  185. }
  186. };
  187. NSMutableArray *formatArray = [NSMutableArray array];
  188. if (isNeedAlbum) {
  189. [formatArray addObject:albumData];
  190. }
  191. if (isNeedTakePhoto) {
  192. [formatArray addObject:takePictureData];
  193. }
  194. if (isNeedRecordVideo) {
  195. [formatArray addObject:videoData];
  196. }
  197. if (isNeedFile) {
  198. [formatArray addObject:fileData];
  199. }
  200. _builtInInputMoreMenus = [NSArray arrayWithArray:formatArray];
  201. return _builtInInputMoreMenus;
  202. }
  203. #pragma mark -- Minimalist
  204. - (NSArray<TUICustomActionSheetItem *> *)createBuiltInInputMoreActionItemList:(TUIChatConversationModel *)model {
  205. if (_builtInInputMoreActionItemList == nil) {
  206. self.builtInInputMoreActionItemList = [NSMutableArray array];
  207. BOOL showTakePhoto = [TUIChatConfig defaultConfig].showTakePhotoButton && model.enableTakePhoto;
  208. BOOL showAlbum = [TUIChatConfig defaultConfig].showAlbumButton && model.enableAlbum;
  209. BOOL showRecordVideo = [TUIChatConfig defaultConfig].showRecordVideoButton && model.enableRecordVideo;
  210. BOOL showFile = [TUIChatConfig defaultConfig].showFileButton && model.enableFile;
  211. __weak typeof(self) weakSelf = self;
  212. if (showAlbum) {
  213. TUICustomActionSheetItem *album =
  214. [[TUICustomActionSheetItem alloc] initWithTitle:TIMCommonLocalizableString(TUIKitMorePhoto)
  215. leftMark:[UIImage imageNamed:TUIChatImagePath_Minimalist(@"icon_more_photo")]
  216. withActionHandler:^(UIAlertAction *_Nonnull action) {
  217. if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(onSelectPhotoMoreCellData)]) {
  218. [weakSelf.delegate onSelectPhotoMoreCellData];
  219. }
  220. }];
  221. album.priority = 1000;
  222. [self.builtInInputMoreActionItemList addObject:album];
  223. }
  224. if (showTakePhoto) {
  225. TUICustomActionSheetItem *takePhoto =
  226. [[TUICustomActionSheetItem alloc] initWithTitle:TIMCommonLocalizableString(TUIKitMoreCamera)
  227. leftMark:[UIImage imageNamed:TUIChatImagePath_Minimalist(@"icon_more_camera")]
  228. withActionHandler:^(UIAlertAction *_Nonnull action) {
  229. if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(onTakePictureMoreCellData)]) {
  230. [weakSelf.delegate onTakePictureMoreCellData];
  231. }
  232. }];
  233. takePhoto.priority = 900;
  234. [self.builtInInputMoreActionItemList addObject:takePhoto];
  235. }
  236. if (showRecordVideo) {
  237. TUICustomActionSheetItem *recordVideo =
  238. [[TUICustomActionSheetItem alloc] initWithTitle:TIMCommonLocalizableString(TUIKitMoreVideo)
  239. leftMark:[UIImage imageNamed:TUIChatImagePath_Minimalist(@"icon_more_video")]
  240. withActionHandler:^(UIAlertAction *_Nonnull action) {
  241. if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(onTakeVideoMoreCellData)]) {
  242. [weakSelf.delegate onTakeVideoMoreCellData];
  243. }
  244. }];
  245. recordVideo.priority = 800;
  246. [self.builtInInputMoreActionItemList addObject:recordVideo];
  247. }
  248. if (showFile) {
  249. TUICustomActionSheetItem *file =
  250. [[TUICustomActionSheetItem alloc] initWithTitle:TIMCommonLocalizableString(TUIKitMoreFile)
  251. leftMark:[UIImage imageNamed:TUIChatImagePath_Minimalist(@"icon_more_document")]
  252. withActionHandler:^(UIAlertAction *_Nonnull action) {
  253. if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(onSelectFileMoreCellData)]) {
  254. [weakSelf.delegate onSelectFileMoreCellData];
  255. }
  256. }];
  257. file.priority = 700;
  258. [self.builtInInputMoreActionItemList addObject:file];
  259. }
  260. }
  261. return self.builtInInputMoreActionItemList;
  262. }
  263. - (NSArray<TUICustomActionSheetItem *> *)createCustomInputMoreActionItemList:(TUIChatConversationModel *)model {
  264. if (_customInputMoreActionItemList == nil) {
  265. NSMutableArray *arrayM = [NSMutableArray array];
  266. BOOL showCustom = [TUIChatConfig defaultConfig].enableWelcomeCustomMessage && model.enableWelcomeCustomMessage;
  267. if (showCustom) {
  268. __weak typeof(self) weakSelf = self;
  269. TUICustomActionSheetItem *link =
  270. [[TUICustomActionSheetItem alloc] initWithTitle:TIMCommonLocalizableString(TUIKitMoreLink)
  271. leftMark:[UIImage imageNamed:TUIChatImagePath_Minimalist(@"icon_more_custom")]
  272. withActionHandler:^(UIAlertAction *_Nonnull action) {
  273. link.priority = 100;
  274. NSString *text = TIMCommonLocalizableString(TUIKitWelcome);
  275. NSString *link = TUITencentCloudHomePageEN;
  276. NSString *language = [TUIGlobalization tk_localizableLanguageKey];
  277. if ([language tui_containsString:@"zh-"]) {
  278. link = TUITencentCloudHomePageCN;
  279. }
  280. NSError *error = nil;
  281. NSDictionary *param = @{BussinessID : BussinessID_TextLink, @"text" : text, @"link" : link};
  282. NSData *data = [NSJSONSerialization dataWithJSONObject:param options:0 error:&error];
  283. if (error) {
  284. NSLog(@"[%@] Post Json Error", [self class]);
  285. return;
  286. }
  287. V2TIMMessage *message = [TUIMessageDataProvider getCustomMessageWithJsonData:data desc:text extension:text];
  288. if ([weakSelf.delegate respondsToSelector:@selector(dataProvider:sendMessage:)]) {
  289. [weakSelf.delegate dataProvider:weakSelf sendMessage:message];
  290. }
  291. }];
  292. [arrayM addObject:link];
  293. }
  294. if (model.customizedNewItemsInMoreMenu.count > 0) {
  295. [arrayM addObjectsFromArray:model.customizedNewItemsInMoreMenu];
  296. }
  297. _customInputMoreActionItemList = [NSArray arrayWithArray:arrayM];
  298. }
  299. return _customInputMoreActionItemList;
  300. }
  301. #pragma mark -- Override
  302. - (NSString *)abstractDisplayWithMessage:(V2TIMMessage *)msg {
  303. NSString *desc = @"";
  304. if (msg.nickName.length > 0) {
  305. desc = msg.nickName;
  306. } else if (msg.sender.length > 0) {
  307. desc = msg.sender;
  308. }
  309. NSString *display = [self.delegate dataProvider:self mergeForwardMsgAbstactForMessage:msg];
  310. if (display.length == 0) {
  311. display = [self.class parseAbstractDisplayWStringFromMessageElement:msg];
  312. }
  313. NSString * splitStr = @":";
  314. splitStr = @"\u202C:";
  315. NSString *nameFormat = [desc stringByAppendingFormat:@"%@", splitStr];
  316. return [self.class alignEmojiStringWithUserName:nameFormat
  317. text:display];
  318. }
  319. + (nullable NSString *)parseAbstractDisplayWStringFromMessageElement:(V2TIMMessage *)message {
  320. NSString *str = nil;
  321. if (message.elemType == V2TIM_ELEM_TYPE_TEXT) {
  322. NSString *content = message.textElem.text;
  323. str = content;
  324. }
  325. else {
  326. str = [TUIMessageDataProvider getDisplayString:message];
  327. }
  328. return str;
  329. }
  330. + (NSString *)alignEmojiStringWithUserName:(NSString *)userName text:(NSString *)text {
  331. NSArray *textList = [self.class splitEmojiText:text];
  332. NSInteger forwardMsgLength = 98;
  333. NSMutableString *sb = [NSMutableString string];
  334. [sb appendString:userName];
  335. NSInteger length = userName.length;
  336. for (NSString *textItem in textList) {
  337. BOOL isFaceChar = [self.class isFaceStrKey:textItem];
  338. if (isFaceChar) {
  339. if (length + textItem.length < forwardMsgLength) {
  340. [sb appendString:textItem];
  341. length += textItem.length;
  342. } else {
  343. [sb appendString:@"..."];
  344. break;
  345. }
  346. } else {
  347. if (length + textItem.length < forwardMsgLength) {
  348. [sb appendString:textItem];
  349. length += textItem.length;
  350. } else {
  351. [sb appendString:textItem];
  352. break;
  353. }
  354. }
  355. }
  356. return sb;
  357. }
  358. + (BOOL)isFaceStrKey:(NSString*) strkey {
  359. id<TUIEmojiMeditorProtocol> service = [[TIMCommonMediator share] getObject:@protocol(TUIEmojiMeditorProtocol)];
  360. NSArray <TUIFaceGroup *> * groups = service.getFaceGroup;
  361. if ([groups.firstObject.facesMap objectForKey:strkey] != nil) {
  362. return YES;
  363. } else {
  364. return NO;
  365. }
  366. }
  367. + (NSArray<NSString *> *)splitEmojiText:(NSString *)text {
  368. NSString *regex = @"\\[(\\S+?)\\]";
  369. NSRegularExpression *regexExp = [NSRegularExpression regularExpressionWithPattern:regex options:0 error:nil];
  370. NSArray<NSTextCheckingResult *> *matches = [regexExp matchesInString:text options:0 range:NSMakeRange(0, text.length)];
  371. NSMutableArray<TUISplitEmojiData *> *emojiDataList = [NSMutableArray array];
  372. NSInteger lastMentionIndex = -1;
  373. for (NSTextCheckingResult *match in matches) {
  374. NSString *emojiKey = [text substringWithRange:match.range];
  375. NSInteger start;
  376. if (lastMentionIndex != -1) {
  377. start = [text rangeOfString:emojiKey options:0 range:NSMakeRange(lastMentionIndex, text.length - lastMentionIndex)].location;
  378. } else {
  379. start = [text rangeOfString:emojiKey].location;
  380. }
  381. NSInteger end = start + emojiKey.length;
  382. lastMentionIndex = end;
  383. if (![self.class isFaceStrKey:emojiKey]) {
  384. continue;
  385. }
  386. TUISplitEmojiData *emojiData = [[TUISplitEmojiData alloc] init];
  387. emojiData.start = start;
  388. emojiData.end = end;
  389. [emojiDataList addObject:emojiData];
  390. }
  391. NSMutableArray<NSString *> *stringList = [NSMutableArray array];
  392. NSInteger offset = 0;
  393. for (TUISplitEmojiData *emojiData in emojiDataList) {
  394. NSInteger start = emojiData.start - offset;
  395. NSInteger end = emojiData.end - offset;
  396. NSString *startStr = [text substringToIndex:start];
  397. NSString *middleStr = [text substringWithRange:NSMakeRange(start, end - start)];
  398. text = [text substringFromIndex:end];
  399. if (startStr.length > 0) {
  400. [stringList addObject:startStr];
  401. }
  402. [stringList addObject:middleStr];
  403. offset += startStr.length + middleStr.length;
  404. }
  405. if (text.length > 0) {
  406. [stringList addObject:text];
  407. }
  408. return stringList;
  409. }
  410. #pragma mark - Getter
  411. - (TUIInputMoreCellData *)welcomeInputMoreMenu {
  412. if (!_welcomeInputMoreMenu) {
  413. __weak typeof(self) weakSelf = self;
  414. _welcomeInputMoreMenu = [[TUIInputMoreCellData alloc] init];
  415. _welcomeInputMoreMenu.priority = 0;
  416. _welcomeInputMoreMenu.title = TIMCommonLocalizableString(TUIKitMoreLink);
  417. _welcomeInputMoreMenu.image = TUIChatBundleThemeImage(@"chat_more_link_img", @"chat_more_link_img");
  418. _welcomeInputMoreMenu.onClicked = ^(NSDictionary *actionParam) {
  419. NSString *text = TIMCommonLocalizableString(TUIKitWelcome);
  420. NSString *link = TUITencentCloudHomePageEN;
  421. NSString *language = [TUIGlobalization tk_localizableLanguageKey];
  422. if ([language tui_containsString:@"zh-"]) {
  423. link = TUITencentCloudHomePageCN;
  424. }
  425. NSError *error = nil;
  426. NSDictionary *param = @{BussinessID : BussinessID_TextLink, @"text" : text, @"link" : link};
  427. NSData *data = [NSJSONSerialization dataWithJSONObject:param options:0 error:&error];
  428. if (error) {
  429. NSLog(@"[%@] Post Json Error", [weakSelf class]);
  430. return;
  431. }
  432. V2TIMMessage *message = [TUIMessageDataProvider getCustomMessageWithJsonData:data desc:text extension:text];
  433. if ([weakSelf.delegate respondsToSelector:@selector(dataProvider:sendMessage:)]) {
  434. [weakSelf.delegate dataProvider:weakSelf sendMessage:message];
  435. }
  436. };
  437. }
  438. return _welcomeInputMoreMenu;
  439. }
  440. - (NSMutableArray<TUIInputMoreCellData *> *)customInputMoreMenus {
  441. if (!_customInputMoreMenus) {
  442. _customInputMoreMenus = [NSMutableArray array];
  443. }
  444. return _customInputMoreMenus;
  445. }
  446. - (NSArray<TUIInputMoreCellData *> *)builtInInputMoreMenus {
  447. if (_builtInInputMoreMenus == nil) {
  448. return [self createBuiltInInputMoreMenusWithConversationModel:nil];
  449. }
  450. return _builtInInputMoreMenus;
  451. }
  452. @end