YMIMMessageCollectionView.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. //
  2. // YMIMMessageCollectionView.m
  3. // PCDBank
  4. //
  5. // Created by Gusont on 2021/8/25.
  6. // Copyright © 2021 SLAiELTS. All rights reserved.
  7. //
  8. #import "YMIMMessageCollectionView.h"
  9. #import "YMIMBaseMessageCell.h"
  10. #import "UICollectionView+YMHelper.h"
  11. @interface YMIMMessageCollectionView()<UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UIScrollViewDelegate>
  12. @end
  13. @implementation YMIMMessageCollectionView
  14. - (void)dealloc
  15. {
  16. }
  17. - (instancetype)initWithFrame:(CGRect)frame
  18. {
  19. self = [super initWithFrame:frame];
  20. if (self) {
  21. [self setupMessageCollectionView];
  22. }
  23. return self;
  24. }
  25. - (void)setupMessageCollectionView
  26. {
  27. [self.messageCollectionView mas_makeConstraints:^(MASConstraintMaker *make) {
  28. make.edges.equalTo(self);
  29. }];
  30. [self.messageCollectionView registerCellWithReuseIdentifierClass:YMIMBaseMessageCell.class];
  31. }
  32. - (void)applicationEnterBackground:(id)noti
  33. {
  34. // if ([_iFlySpeechSynthesizer isSpeaking]) {
  35. // [_iFlySpeechSynthesizer pauseSpeaking];
  36. // }
  37. }
  38. - (CGFloat)getBotttomCellMaxY
  39. {
  40. if (self.chatDataManager.count > 0) {
  41. NSIndexPath *idxPath = [NSIndexPath indexPathForItem:self.chatDataManager.count - 1 inSection:0];
  42. UICollectionViewCell *cell = [self.messageCollectionView cellForItemAtIndexPath:idxPath];
  43. CGRect rect = [self.messageCollectionView convertRect:cell.frame toView:self.messageCollectionView];
  44. return CGRectGetMaxY(rect);
  45. }
  46. return 0;
  47. }
  48. - (void)scrollToBottom:(BOOL)animated
  49. {
  50. dispatch_async(dispatch_get_main_queue(), ^{
  51. if (self.chatDataManager.count > 0) {
  52. NSIndexPath *endIndex = [NSIndexPath indexPathForItem:self.chatDataManager.count - 1 inSection:0];
  53. [self.messageCollectionView scrollToItemAtIndexPath:endIndex atScrollPosition:UICollectionViewScrollPositionBottom animated:animated];
  54. }
  55. });
  56. }
  57. ///Q
  58. - (void)appendMessage:(MessageModel *)message
  59. {
  60. MessageModel *lastModel = self.chatDataManager.lastObject;
  61. if ((lastModel && message.sendTime - lastModel.sendTime > 120) || !lastModel) {
  62. message.showTime = YES;
  63. }
  64. [self appendRequestMessage:message];
  65. [self resultsRequestWith:message];
  66. }
  67. ///A
  68. - (void)appendRequestMessage:(MessageModel *)message
  69. {
  70. [self.chatDataManager addObject:message];
  71. dispatch_async(dispatch_get_main_queue(), ^{
  72. [self.messageCollectionView reloadData];
  73. [self scrollToBottom:YES];
  74. });
  75. }
  76. /// 结果请求数据
  77. /// @param message <#message description#>
  78. - (void)resultsRequestWith:(MessageModel *)message
  79. {
  80. NSString *msg = message.sendText;
  81. if (msg.length > 0) {
  82. dispatch_async(dispatch_get_main_queue(), ^{
  83. __block NSMutableArray<SLMessageDetail *> *msgList = [NSMutableArray array];
  84. [self.chatDataManager enumerateObjectsUsingBlock:^(MessageModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  85. SLMessageDetail *detail = [[SLMessageDetail alloc] init];
  86. detail.role = obj.isReceive ? @"assistant" : @"user";
  87. detail.content = obj.sendText;
  88. [msgList addObject:detail];
  89. }];
  90. // NSString *timestamp = [NSString stringWithFormat:@"%.0f",message.sendTime * 1000];
  91. // NSString *newStr = [timestamp stringByAppendingString:SLTimeMD5Sign];
  92. // NSString *newMd5str = [SPEncryption getmd5Str:newStr];
  93. // SLMessageSendModel *sendModel = [[SLMessageSendModel alloc] init];
  94. // sendModel.messages = msgList;
  95. // sendModel.timestamp = timestamp;
  96. // sendModel.sign = newMd5str;
  97. // [[SLHttpCenter SharedInstance] postWithUrl:SLChatApiUrl body:[sendModel mj_JSONData] success:^(id responseObject) {
  98. // NSString *dataStr = [responseObject objectForKey:@"data"];
  99. // NSString *str = [self replaceHasPrefix:@"\n" str:dataStr];
  100. // MessageModel *model = [MessageModel initWithSendText:str isReceive:YES showMike:message.isMike showText:!message.isMike isMike:message.isMike];
  101. // [self appendRequestMessage:model];
  102. // } failure:^(SPRequestError *error) {
  103. //
  104. // }];
  105. [[SLHttpCenter SharedInstance] getWithUrl:@"/api/Chat/SendMessage" parameter:@{@"chatType" : @"0", @"toId" : message.toId ?: @"", @"message" : message.sendText} success:^(id responseObject) {
  106. NSDictionary *dataDict = [responseObject objectForKey:@"data"];
  107. NSString *dataStr = [dataDict objectForKey:@"data"];
  108. NSString *str = [self replaceHasPrefix:@"\n" str:dataStr];
  109. MessageModel *model = [MessageModel initWithSendText:str isReceive:YES showMike:message.isMike showText:!message.isMike isMike:message.isMike];
  110. model.headImg = self.friendModel.head;
  111. [self appendRequestMessage:model];
  112. } failure:^(SPRequestError *error) {
  113. }];
  114. });
  115. }
  116. }
  117. - (NSString *)replaceHasPrefix:(NSString *)fixStr str:(NSString *)str {
  118. if ([str hasPrefix:fixStr]) {
  119. NSString *newStr = [str substringFromIndex:fixStr.length];
  120. return [self replaceHasPrefix:fixStr str:newStr];
  121. }
  122. return str;
  123. }
  124. - (void)setVoiceStatus:(BOOL)voiceStatus
  125. {
  126. _voiceStatus = voiceStatus;
  127. }
  128. #pragma mark - 语音合成
  129. - (void)startSpeakingMessage:(NSString *)responseString
  130. {
  131. }
  132. - (void)insertMessage:(NSArray *)message
  133. {
  134. [self.chatDataManager addObjectsFromArray:message];
  135. [self.messageCollectionView reloadDataNoScroll];
  136. }
  137. - (void)updateMessage:(MessageModel *)message idx:(NSInteger)idx
  138. {
  139. // if ([self.iFlySpeechSynthesizer isSpeaking]) {
  140. // [self.iFlySpeechSynthesizer stopSpeaking];
  141. // }
  142. if (self.chatDataManager.count > 1) {
  143. [self.chatDataManager replaceObjectAtIndex:idx withObject:message];
  144. [self.messageCollectionView reloadData];
  145. }
  146. }
  147. - (void)removeMessage:(MessageModel *)message
  148. {
  149. NSInteger idx = [self.chatDataManager indexOfObject:message];
  150. if (message.showTime && self.chatDataManager.count > idx + 1) {
  151. MessageModel *nextModel = [self.chatDataManager objectAtIndex:idx + 1];
  152. nextModel.showTime = YES;
  153. }
  154. [self.chatDataManager removeObject:message];
  155. [self.messageCollectionView reloadDataNoScroll];
  156. }
  157. - (void)removeAllMessages
  158. {
  159. [self.chatDataManager removeAllObjects];
  160. [self.messageCollectionView reloadData];
  161. }
  162. #pragma mark - UICollectionViewDataSource
  163. - (nonnull __kindof UICollectionViewCell *)collectionView:(nonnull UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath
  164. {
  165. YMIMBaseMessageCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass(YMIMBaseMessageCell.class) forIndexPath:indexPath];
  166. MessageModel *model = [self.chatDataManager objectAtIndex:indexPath.item];
  167. [cell confignBaseMessageContentWith:model];
  168. [cell setCellLayerCornerRadiusWith:model];
  169. WS(weakSelf);
  170. cell.segmentBlock = ^(SLMikeSegmentModel * _Nullable sModel) {
  171. MessageModel *models = [MessageModel initWithSendText:model.sendText isReceive:model.isReceive showMike:model.showMike showText:model.showText isMike:model.isMike showTime:model.showTime sendTime:model.sendTime voicePath:model.voicePath];
  172. switch (sModel.mikeType) {
  173. case SLMikeInputDelete:
  174. {
  175. [weakSelf removeMessage:model];
  176. }
  177. break;
  178. case SLMikeInputLook:
  179. {
  180. models.showText = YES;
  181. [weakSelf updateMessage:models idx:indexPath.item];
  182. }
  183. break;
  184. case SLMikeInputBroadcast:
  185. {
  186. if (weakSelf.broadcastBlock) {
  187. weakSelf.broadcastBlock(models);
  188. }
  189. }
  190. break;
  191. case SLMikeInputHidden:
  192. {
  193. models.showText = NO;
  194. [weakSelf updateMessage:models idx:indexPath.item];
  195. }
  196. break;
  197. default:
  198. break;
  199. }
  200. };
  201. return cell;
  202. }
  203. - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
  204. {
  205. [collectionView.collectionViewLayout invalidateLayout];
  206. return 1;
  207. }
  208. - (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
  209. {
  210. return self.chatDataManager.count;
  211. }
  212. - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
  213. {
  214. }
  215. - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
  216. {
  217. return UIEdgeInsetsMake(0, 0, 0, 0);
  218. }
  219. - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
  220. {
  221. return 0;
  222. }
  223. /**
  224. */
  225. - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
  226. {
  227. return 0;
  228. }
  229. - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
  230. {
  231. if (indexPath.item >= self.chatDataManager.count) {
  232. return;
  233. }
  234. }
  235. #pragma mark - UICollectionViewDelegateFlowLayout
  236. - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
  237. {
  238. MessageModel *model = [self.chatDataManager objectAtIndex:indexPath.item];
  239. //实际send宽度16 + 52 + 10 + 16 英文和中文宽度不一致、ios string包含字符串iOS开发已经被淘汰了吧
  240. //
  241. CGFloat sw = 124;
  242. NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"];
  243. NSRange range = [model.sendText rangeOfCharacterFromSet:set];
  244. if (range.location != NSNotFound) {
  245. sw -= 8;
  246. }
  247. CGSize contentSize =[model.sendText boundingRectWithSize:CGSizeMake(kSCREEN_WIDTH - sw, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:17]} context:nil].size;
  248. // NSLog(@"%f---%f",contentSize.width, contentSize.height);
  249. CGFloat height = 0;
  250. if (model.showMike) {
  251. height += 65;
  252. }
  253. if (model.showText) {
  254. height += contentSize.height + (model.showMike ? 25 : 42);
  255. }
  256. if (model.showTime) {
  257. height += 23;
  258. }
  259. return CGSizeMake(kSCREEN_WIDTH, height);
  260. }
  261. - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
  262. {
  263. }
  264. - (UICollectionView *)messageCollectionView
  265. {
  266. if (!_messageCollectionView) {
  267. UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
  268. layout.minimumLineSpacing = 0.0;
  269. layout.minimumInteritemSpacing = 0.0;
  270. _messageCollectionView = [[UICollectionView alloc] initWithFrame:self.frame collectionViewLayout:layout];
  271. _messageCollectionView.delegate = self;
  272. _messageCollectionView.dataSource = self;
  273. _messageCollectionView.backgroundColor = [UIColor clearColor];
  274. _messageCollectionView.showsVerticalScrollIndicator = NO;
  275. _messageCollectionView.showsHorizontalScrollIndicator = NO;
  276. _messageCollectionView.bounces = NO;
  277. [self addSubview:_messageCollectionView];
  278. }
  279. return _messageCollectionView;
  280. }
  281. - (NSMutableArray<MessageModel *> *)chatDataManager
  282. {
  283. if (!_chatDataManager) {
  284. _chatDataManager = [NSMutableArray array];
  285. }
  286. return _chatDataManager;
  287. }
  288. @end