YOUPAIBBNIMInputView.m 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. //
  2. // YOUPAIBBNIMInputView.m
  3. // VQU
  4. //
  5. // Created by Elaine on 2021/10/26.
  6. // Copyright © 2021 MS. All rights reserved.
  7. //
  8. #import "YOUPAIBBNIMInputView.h"
  9. #import <AVFoundation/AVFoundation.h>
  10. #import "YOUPAINIMInputMoreContainerView.h"
  11. #import "YOUPAINIMInputEmoticonContainerView.h"
  12. #import "YOUPAINIMInputAudioRecordIndicatorView.h"
  13. #import "UIView+NIM.h"
  14. #import "NIMInputEmoticonDefine.h"
  15. #import "YOUPAINIMInputEmoticonManager.h"
  16. #import "YOUPAIBBNIMInputToolBar.h"
  17. #import "UIImage+NIMKit.h"
  18. #import "NIMGlobalMacro.h"
  19. #import "NIMContactSelectViewController.h"
  20. #import "NIMKit.h"
  21. #import "NIMKitInfoFetchOption.h"
  22. #import "NIMKitKeyboardInfo.h"
  23. @interface YOUPAIBBNIMInputView()<BBNIMInputToolBarDelegate,NIMInputEmoticonProtocol,NIMContactSelectDelegate>
  24. {
  25. UIView *_youpaipemoticonView;
  26. }
  27. //@property (nonatomic, strong) YOUPAINIMInputAudioRecordIndicatorView *youpaipaudioRecordIndicator;
  28. @property (nonatomic, assign) NIMAudioRecordPhase youpaiprecordPhase;
  29. @property (nonatomic, weak) id<NIMSessionConfig> youpaipinputConfig;
  30. @property (nonatomic, weak) id<BBNIMInputDelegate> inputDelegate;
  31. @property (nonatomic, weak) id<NIMInputActionDelegate> actionDelegate;
  32. @property (nonatomic, assign) CGFloat youpaipkeyBoardFrameTop; //键盘的frame的top值,屏幕高度 - 键盘高度,由于有旋转的可能,这个值只有当 键盘弹出时才有意义。
  33. @end
  34. @implementation YOUPAIBBNIMInputView
  35. @synthesize youpaipemoticonContainer = _youpaipemoticonContainer;
  36. @synthesize youpaipmoreContainer = _youpaipmoreContainer;
  37. - (instancetype)initWithFrame:(CGRect)frame
  38. config:(id<NIMSessionConfig>)config
  39. {
  40. self = [super initWithFrame:frame];
  41. if (self)
  42. {
  43. _youpaiprecording = NO;
  44. _youpaiprecordPhase = AudioRecordPhaseEnd;
  45. _youpaipatCache = [[YOUPAINIMInputAtCache alloc] init];
  46. _youpaipinputConfig = config;
  47. self.backgroundColor = LCBkgColor;
  48. }
  49. return self;
  50. }
  51. - (void)didMoveToWindow
  52. {
  53. [self youpaifsetup];
  54. }
  55. - (CGSize)sizeThatFits:(CGSize)size
  56. {
  57. //这里不做.语法 get 操作,会提前初始化组件导致卡顿
  58. CGFloat toolBarHeight = _youpaiptoolBar.nim_height;
  59. CGFloat containerHeight = 0;
  60. switch (self.youpaipstatus)
  61. {
  62. case BBNIMInputStatusEmoticon:
  63. _youpaiptoolBar.youpaipemoticonBtn.selected = YES;
  64. _youpaiptoolBar.youpaiprecordBtn.selected = NO;
  65. containerHeight = _youpaipemoticonContainer.nim_height;
  66. break;
  67. case BBNIMInputStatusMore:
  68. _youpaiptoolBar.youpaipemoticonBtn.selected = NO;
  69. _youpaiptoolBar.youpaiprecordBtn.selected = YES;
  70. containerHeight = _youpaipvoiceViewContainer.nim_height;
  71. break;
  72. default:
  73. {
  74. _youpaiptoolBar.youpaipemoticonBtn.selected = NO;
  75. _youpaiptoolBar.youpaiprecordBtn.selected = NO;
  76. UIEdgeInsets safeArea = UIEdgeInsetsZero;
  77. if (@available(iOS 11.0, *))
  78. {
  79. safeArea = self.superview.safeAreaInsets;
  80. }
  81. //键盘是从最底下弹起的,需要减去安全区域底部的高度
  82. CGFloat keyboardDelta = [NIMKitKeyboardInfo instance].keyboardHeight - safeArea.bottom;
  83. //如果键盘还没有安全区域高,容器的初始值为0;否则则为键盘和安全区域的高度差值,这样可以保证 youpaiptoolBar 始终在键盘上面
  84. containerHeight = keyboardDelta>0 ? keyboardDelta : 0;
  85. }
  86. break;
  87. }
  88. CGFloat height = toolBarHeight + containerHeight;
  89. CGFloat width = self.superview? self.superview.nim_width : self.nim_width;
  90. return CGSizeMake(width, height);
  91. }
  92. - (void)youpaifsetInputDelegate:(id<BBNIMInputDelegate>)delegate
  93. {
  94. _inputDelegate = delegate;
  95. }
  96. - (void)youpaifsetInputActionDelegate:(id<NIMInputActionDelegate>)actionDelegate
  97. {
  98. _actionDelegate = actionDelegate;
  99. }
  100. - (void)youpaifreset
  101. {
  102. self.nim_width = self.superview.nim_width;
  103. [self youpaifrefreshStatus:BBNIMInputStatusText];
  104. [self sizeToFit];
  105. }
  106. - (void)youpaifrefreshStatus:(BBNIMInputStatus)status
  107. {
  108. self.youpaipstatus = status;
  109. [self.youpaiptoolBar youpaifupdate:status];
  110. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  111. self.youpaipvoiceViewContainer.hidden = status != BBNIMInputStatusMore;
  112. self.youpaipemoticonContainer.hidden = status != BBNIMInputStatusEmoticon;
  113. });
  114. }
  115. //- (YOUPAINIMInputAudioRecordIndicatorView *)youpaipaudioRecordIndicator {
  116. // if(!_youpaipaudioRecordIndicator) {
  117. // _youpaipaudioRecordIndicator = [[YOUPAINIMInputAudioRecordIndicatorView alloc] init];
  118. // }
  119. // return _youpaipaudioRecordIndicator;
  120. //}
  121. - (void)setYoupaiprecordPhase:(NIMAudioRecordPhase)youpaiprecordPhase {
  122. NIMAudioRecordPhase prevPhase = _youpaiprecordPhase;
  123. _youpaiprecordPhase = youpaiprecordPhase;
  124. // self.youpaipaudioRecordIndicator.phase = _youpaiprecordPhase;
  125. if(prevPhase == AudioRecordPhaseEnd) {
  126. if(AudioRecordPhaseStart == _youpaiprecordPhase) {
  127. if ([_actionDelegate respondsToSelector:@selector(onStartRecording)]) {
  128. [_actionDelegate onStartRecording];
  129. }
  130. }
  131. } else if (prevPhase == AudioRecordPhaseStart || prevPhase == AudioRecordPhaseRecording) {
  132. if (AudioRecordPhaseEnd == _youpaiprecordPhase) {
  133. if ([_actionDelegate respondsToSelector:@selector(onStopRecording)]) {
  134. [_actionDelegate onStopRecording];
  135. }
  136. }
  137. } else if (prevPhase == AudioRecordPhaseCancelling) {
  138. if(AudioRecordPhaseEnd == _youpaiprecordPhase) {
  139. if ([_actionDelegate respondsToSelector:@selector(onCancelRecording)]) {
  140. [_actionDelegate onCancelRecording];
  141. }
  142. }
  143. }
  144. }
  145. - (void)youpaifsetup
  146. {
  147. if (!_youpaiptoolBar)
  148. {
  149. _youpaiptoolBar = [[YOUPAIBBNIMInputToolBar alloc] initWithFrame:CGRectMake(0, 0, self.nim_width, 0)];
  150. }
  151. [self addSubview:_youpaiptoolBar];
  152. //设置placeholder
  153. NSString *placeholder = [NIMKit sharedKit].config.placeholder;
  154. placeholder = @" 请输入消息…";
  155. [_youpaiptoolBar youpaifsetPlaceHolder:placeholder];
  156. _youpaiptoolBar.backgroundColor = HexColorFromRGB(0x2A2935);
  157. //设置input bar 上的按钮
  158. if ([_youpaipinputConfig respondsToSelector:@selector(inputBarItemTypes)]) {
  159. NSArray *types = [_youpaipinputConfig inputBarItemTypes];
  160. [_youpaiptoolBar setYoupaipinputBarItemTypes:types];
  161. }
  162. _youpaiptoolBar.delegate = self;
  163. [_youpaiptoolBar.youpaiprecordBtn addTarget:self action:@selector(youpaifonTouchRecordBtn:) forControlEvents:UIControlEventTouchUpInside];
  164. [_youpaiptoolBar.youpaipcameraBtn addTarget:self action:@selector(youpaifonTouchCameraBtn:) forControlEvents:UIControlEventTouchUpInside];
  165. [_youpaiptoolBar.youpaipphotoBtn addTarget:self action:@selector(youpaifonTouchPhotoBtn:) forControlEvents:UIControlEventTouchUpInside];
  166. [_youpaiptoolBar.youpaipgiftBtn addTarget:self action:@selector(youpaifonTouchGiftBtn:) forControlEvents:UIControlEventTouchUpInside];
  167. [_youpaiptoolBar.youpaipvideoBtn addTarget:self action:@selector(youpaifonTouchVideoBtn:) forControlEvents:UIControlEventTouchUpInside];
  168. [_youpaiptoolBar.youpaipemoticonBtn addTarget:self action:@selector(youpaifonTouchEmoticonBtn:) forControlEvents:UIControlEventTouchUpInside];
  169. [_youpaiptoolBar.youpaipmoreMediaBtn addTarget:self action:@selector(youpaifonTouchMoreBtn:) forControlEvents:UIControlEventTouchUpInside];
  170. [_youpaiptoolBar.youpaipvoiceBtn addTarget:self action:@selector(youpaifonTouchVoiceBtn:) forControlEvents:UIControlEventTouchUpInside];
  171. _youpaiptoolBar.nim_size = [_youpaiptoolBar sizeThatFits:CGSizeMake(self.nim_width, CGFLOAT_MAX)];
  172. _youpaiptoolBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  173. [_youpaiptoolBar.youpaiprecordButton setTitle:@"按住 说话" forState:UIControlStateNormal];
  174. [_youpaiptoolBar.youpaiprecordButton setTitle:@"松开 结束" forState:UIControlStateSelected];
  175. [_youpaiptoolBar.youpaiprecordButton setHidden:YES];
  176. //设置最大输入字数
  177. NSInteger textInputLength = [NIMKit sharedKit].config.inputMaxLength;
  178. self.youpaipmaxTextLength = textInputLength;
  179. [self youpaifrefreshStatus:BBNIMInputStatusText];
  180. [self sizeToFit];
  181. }
  182. - (void)youpaifcheckMoreContainer
  183. {
  184. if (!_youpaipmoreContainer) {
  185. YOUPAINIMInputMoreContainerView *youpaipmoreContainer = [[YOUPAINIMInputMoreContainerView alloc] initWithFrame:CGRectZero];
  186. youpaipmoreContainer.nim_size = [youpaipmoreContainer sizeThatFits:CGSizeMake(self.nim_width, CGFLOAT_MAX)];
  187. youpaipmoreContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  188. youpaipmoreContainer.hidden = YES;
  189. youpaipmoreContainer.config = _youpaipinputConfig;
  190. youpaipmoreContainer.actionDelegate = self.actionDelegate;
  191. _youpaipmoreContainer = youpaipmoreContainer;
  192. }
  193. //可能是外部主动设置进来的,统一放在这里添加 subview
  194. if (!_youpaipmoreContainer.superview)
  195. {
  196. [self addSubview:_youpaipmoreContainer];
  197. }
  198. }
  199. - (void)setYoupaipmoreContainer:(UIView *)youpaipmoreContainer
  200. {
  201. _youpaipmoreContainer = youpaipmoreContainer;
  202. [self sizeToFit];
  203. }
  204. //- (YOUPAINIMInputVoiceView *)youpaipvoiceViewContainer
  205. //{
  206. // if (!_youpaipvoiceViewContainer) {
  207. // _youpaipvoiceViewContainer = [[YOUPAINIMInputVoiceView alloc] initWithFrame:CGRectMake(0,_youpaiptoolBar.nim_height, self.nim_width,216.0f)];
  208. // _youpaipvoiceViewContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  209. // _youpaipvoiceViewContainer.hidden = YES;
  210. // }
  211. // return _youpaipvoiceViewContainer;
  212. //}
  213. - (void)youpaifcheckVoiceViewContainer{
  214. if (!_youpaipvoiceViewContainer) {
  215. YOUPAINIMInputVoiceView *voiceContainer = [[YOUPAINIMInputVoiceView alloc] initWithFrame:CGRectMake(0,_youpaiptoolBar.nim_height, self.nim_width,216.0f)];
  216. voiceContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  217. voiceContainer.hidden = YES;
  218. _youpaipvoiceViewContainer = voiceContainer;
  219. [_youpaipvoiceViewContainer.recordBt addTarget:self action:@selector(youpaifonTouchRecordBtnDown:) forControlEvents:UIControlEventTouchDown];
  220. [_youpaipvoiceViewContainer.recordBt addTarget:self action:@selector(youpaifonTouchRecordBtnDragInside:) forControlEvents:UIControlEventTouchDragInside];
  221. [_youpaipvoiceViewContainer.recordBt addTarget:self action:@selector(youpaifonTouchRecordBtnDragOutside:) forControlEvents:UIControlEventTouchDragOutside];
  222. [_youpaipvoiceViewContainer.recordBt addTarget:self action:@selector(youpaifonTouchRecordBtnUpInside:) forControlEvents:UIControlEventTouchUpInside];
  223. [_youpaipvoiceViewContainer.recordBt addTarget:self action:@selector(youpaifonTouchRecordBtnUpOutside:) forControlEvents:UIControlEventTouchUpOutside];
  224. }
  225. //可能是外部主动设置进来的,统一放在这里添加 subview
  226. if (!_youpaipvoiceViewContainer.superview)
  227. {
  228. [self addSubview:_youpaipvoiceViewContainer];
  229. }
  230. }
  231. - (void)setYoupaipvoiceViewContainer:(YOUPAINIMInputVoiceView *)youpaipvoiceViewContainer
  232. {
  233. _youpaipvoiceViewContainer = youpaipvoiceViewContainer;
  234. [self sizeToFit];
  235. }
  236. - (void)youpaifcheckEmoticonContainer
  237. {
  238. if (!_youpaipemoticonContainer) {
  239. YOUPAINIMInputEmoticonContainerView *youpaipemoticonContainer = [[YOUPAINIMInputEmoticonContainerView alloc] initWithFrame:CGRectZero];
  240. youpaipemoticonContainer.nim_size = [youpaipemoticonContainer sizeThatFits:CGSizeMake(self.nim_width, CGFLOAT_MAX)];
  241. youpaipemoticonContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  242. youpaipemoticonContainer.delegate = self;
  243. youpaipemoticonContainer.hidden = YES;
  244. youpaipemoticonContainer.config = _youpaipinputConfig;
  245. _youpaipemoticonContainer = youpaipemoticonContainer;
  246. }
  247. //可能是外部主动设置进来的,统一放在这里添加 subview
  248. if (!_youpaipemoticonContainer.superview)
  249. {
  250. [self addSubview:_youpaipemoticonContainer];
  251. }
  252. }
  253. - (void)setYoupaipemoticonContainer:(UIView *)youpaipemoticonContainer
  254. {
  255. _youpaipemoticonContainer = youpaipemoticonContainer;
  256. [self sizeToFit];
  257. }
  258. - (void)setYoupaiprecording:(BOOL)youpaiprecording
  259. {
  260. if(youpaiprecording)
  261. {
  262. // self.youpaipaudioRecordIndicator.center = self.superview.center;
  263. // [self.superview addSubview:self.youpaipaudioRecordIndicator];
  264. self.youpaiprecordPhase = AudioRecordPhaseRecording;
  265. }
  266. else
  267. {
  268. // [self.youpaipaudioRecordIndicator removeFromSuperview];
  269. self.youpaiprecordPhase = AudioRecordPhaseEnd;
  270. }
  271. _youpaiprecording = youpaiprecording;
  272. }
  273. #pragma mark - 外部接口
  274. - (void)youpaifsetInputTextPlaceHolder:(NSString*)placeHolder
  275. {
  276. [_youpaiptoolBar youpaifsetPlaceHolder:placeHolder];
  277. }
  278. - (void)youpaifupdateAudioRecordTime:(NSTimeInterval)time {
  279. // self.youpaipaudioRecordIndicator.recordTime = time;
  280. self.youpaipvoiceViewContainer.recordTime = time;
  281. }
  282. - (void)youpaifupdateVoicePower:(float)power {
  283. }
  284. #pragma mark - private methods
  285. - (void)setFrame:(CGRect)frame
  286. {
  287. CGFloat height = self.frame.size.height;
  288. [super setFrame:frame];
  289. if (frame.size.height != height)
  290. {
  291. [self youpaifcallDidChangeHeight];
  292. }
  293. }
  294. - (void)youpaifcallDidChangeHeight
  295. {
  296. if (_inputDelegate && [_inputDelegate respondsToSelector:@selector(didChangeInputHeight:)])
  297. {
  298. if (self.youpaipstatus == BBNIMInputStatusMore || self.youpaipstatus == BBNIMInputStatusEmoticon || self.youpaipstatus == BBNIMInputStatusAudio)
  299. {
  300. //这个时候需要一个动画来模拟键盘
  301. [UIView animateWithDuration:0.25 delay:0 options:7 animations:^{
  302. [_inputDelegate didChangeInputHeight:self.nim_height];
  303. } completion:nil];
  304. }
  305. else
  306. {
  307. [_inputDelegate didChangeInputHeight:self.nim_height];
  308. }
  309. }
  310. }
  311. - (void)layoutSubviews
  312. {
  313. [super layoutSubviews];
  314. //这里不做.语法 get 操作,会提前初始化组件导致卡顿
  315. _youpaipmoreContainer.nim_top = self.youpaiptoolBar.nim_bottom;
  316. _youpaipemoticonContainer.nim_top = self.youpaiptoolBar.nim_bottom;
  317. }
  318. #pragma mark - button actions
  319. - (void)youpaifonTouchVoiceBtn:(id)sender {
  320. // image change
  321. if (self.youpaipstatus!= BBNIMInputStatusAudio) {
  322. if ([self.actionDelegate respondsToSelector:@selector(onTapVoiceBtn:)]) {
  323. [self.actionDelegate onTapVoiceBtn:sender];
  324. }
  325. __weak typeof(self) weakSelf = self;
  326. if ([[AVAudioSession sharedInstance] respondsToSelector:@selector(requestRecordPermission:)]) {
  327. [[AVAudioSession sharedInstance] performSelector:@selector(requestRecordPermission:) withObject:^(BOOL granted) {
  328. if (granted) {
  329. dispatch_async(dispatch_get_main_queue(), ^{
  330. [weakSelf youpaifrefreshStatus:BBNIMInputStatusAudio];
  331. if (weakSelf.youpaiptoolBar.youpaipshowsKeyboard)
  332. {
  333. weakSelf.youpaiptoolBar.youpaipshowsKeyboard = NO;
  334. }
  335. [self sizeToFit];
  336. });
  337. }
  338. else {
  339. dispatch_async(dispatch_get_main_queue(), ^{
  340. [[[UIAlertView alloc] initWithTitle:nil
  341. message:@"没有麦克风权限"
  342. delegate:nil
  343. cancelButtonTitle:@"确定"
  344. otherButtonTitles:nil] show];
  345. });
  346. }
  347. }];
  348. }
  349. }
  350. else
  351. {
  352. if ([self.youpaiptoolBar.youpaipinputBarItemTypes containsObject:@(NIMInputBarItemTypeTextAndRecord)])
  353. {
  354. [self youpaifrefreshStatus:BBNIMInputStatusText];
  355. self.youpaiptoolBar.youpaipshowsKeyboard = YES;
  356. }
  357. }
  358. }
  359. - (IBAction)youpaifonTouchRecordBtnDown:(id)sender {
  360. self.youpaiprecordPhase = AudioRecordPhaseStart;
  361. self.youpaipvoiceViewContainer.titleLabel.text = @"";
  362. [self.youpaipvoiceViewContainer.recordBt setImage:[UIImage imageNamed:@"vqu_images_vqu_images_IM_im_record_ing"] forState:UIControlStateNormal];;
  363. }
  364. - (IBAction)youpaifonTouchRecordBtnUpInside:(id)sender {
  365. // finish Recording
  366. self.youpaiprecordPhase = AudioRecordPhaseEnd;
  367. self.youpaipvoiceViewContainer.titleLabel.text = @"按住说话";
  368. self.youpaipvoiceViewContainer.timeLabel.text = @"";
  369. self.youpaipvoiceViewContainer.titleLabel.textColor = [UIColor whiteColor];
  370. [self.youpaipvoiceViewContainer.recordBt setImage:[UIImage imageNamed:@"vqu_images_vqu_images_IM_im_record_Voice"] forState:UIControlStateNormal];
  371. }
  372. - (IBAction)youpaifonTouchRecordBtnUpOutside:(id)sender {
  373. // cancel Recording
  374. self.youpaiprecordPhase = AudioRecordPhaseEnd;
  375. self.youpaipvoiceViewContainer.titleLabel.text = @"按住说话";
  376. self.youpaipvoiceViewContainer.timeLabel.text = @"";
  377. self.youpaipvoiceViewContainer.titleLabel.textColor = LZFAFAFCColor;
  378. [self.youpaipvoiceViewContainer.recordBt setImage:[UIImage imageNamed:@"vqu_images_vqu_images_IM_im_record_Voice"] forState:UIControlStateNormal];
  379. }
  380. - (IBAction)youpaifonTouchRecordBtnDragInside:(id)sender {
  381. // "手指上滑,取消发送"
  382. self.youpaipvoiceViewContainer.titleLabel.text = @"手指上滑,取消发送";
  383. self.youpaipvoiceViewContainer.titleLabel.textColor = HexColorFromRGB(0x9F9DA5);
  384. self.youpaipvoiceViewContainer.timeLabel.textColor = [UIColor whiteColor];
  385. self.youpaiprecordPhase = AudioRecordPhaseRecording;
  386. [self.youpaipvoiceViewContainer.recordBt setImage:[UIImage imageNamed:@"vqu_images_vqu_images_IM_im_record_ing"] forState:UIControlStateNormal];;
  387. }
  388. - (IBAction)youpaifonTouchRecordBtnDragOutside:(id)sender {
  389. // "松开手指,取消发送"
  390. self.youpaipvoiceViewContainer.titleLabel.text = @"松开手指,取消发送";
  391. self.youpaipvoiceViewContainer.titleLabel.textColor = HexColorFromRGB(0x79262C);
  392. self.youpaipvoiceViewContainer.timeLabel.textColor = HexColorFromRGB(0xD63641);
  393. self.youpaiprecordPhase = AudioRecordPhaseCancelling;
  394. [self.youpaipvoiceViewContainer.recordBt setImage:[UIImage imageNamed:@"vqu_images_vqu_images_IM_im_record_stop"] forState:UIControlStateNormal];;
  395. }
  396. - (void)youpaifonTouchCameraBtn:(UIButton*)btn{
  397. if (self.actionDelegate && [self.actionDelegate respondsToSelector:@selector(onCameraClick)]) {
  398. [self.actionDelegate onCameraClick];
  399. }
  400. }
  401. - (void)youpaifonTouchPhotoBtn:(UIButton*)btn{
  402. if (self.actionDelegate && [self.actionDelegate respondsToSelector:@selector(onPhotoClick)]) {
  403. [self.actionDelegate onPhotoClick];
  404. }
  405. }
  406. - (void)youpaifonTouchGiftBtn:(UIButton*)btn{
  407. if (self.actionDelegate && [self.actionDelegate respondsToSelector:@selector(onGiftClick)]) {
  408. [self.actionDelegate onGiftClick];
  409. }
  410. }
  411. - (void)youpaifonTouchVideoBtn:(UIButton*)btn{
  412. if (self.actionDelegate && [self.actionDelegate respondsToSelector:@selector(onVideoClick)]) {
  413. [self.actionDelegate onVideoClick];
  414. }
  415. }
  416. - (void)youpaifonTouchRecordBtn:(id)sender{
  417. if (self.youpaipstatus != NIMInputStatusMore)
  418. {
  419. // if ([self.actionDelegate respondsToSelector:@selector(onTapMoreBtn:)]) {
  420. // [self.actionDelegate onTapMoreBtn:sender];
  421. // }
  422. [self youpaifcheckVoiceViewContainer];
  423. [self bringSubviewToFront:self.youpaipvoiceViewContainer];
  424. [self.youpaipvoiceViewContainer setHidden:NO];
  425. [self.youpaipemoticonContainer setHidden:YES];
  426. [self youpaifrefreshStatus:BBNIMInputStatusMore];
  427. [self sizeToFit];
  428. if (self.youpaiptoolBar.youpaipshowsKeyboard)
  429. {
  430. self.youpaiptoolBar.youpaipshowsKeyboard = NO;
  431. }
  432. }
  433. else
  434. {
  435. [self youpaifrefreshStatus:BBNIMInputStatusText];
  436. self.youpaiptoolBar.youpaipshowsKeyboard = YES;
  437. }
  438. }
  439. - (void)youpaifonTouchEmoticonBtn:(id)sender
  440. {
  441. if (self.youpaipstatus != BBNIMInputStatusEmoticon) {
  442. if ([self.actionDelegate respondsToSelector:@selector(onTapEmoticonBtn:)]) {
  443. [self.actionDelegate onTapEmoticonBtn:sender];
  444. }
  445. [self youpaifcheckEmoticonContainer];
  446. [self bringSubviewToFront:self.youpaipemoticonContainer];
  447. [self.youpaipemoticonContainer setHidden:NO];
  448. [self.youpaipvoiceViewContainer setHidden:YES];
  449. [self youpaifrefreshStatus:BBNIMInputStatusEmoticon];
  450. [self sizeToFit];
  451. if (self.youpaiptoolBar.youpaipshowsKeyboard)
  452. {
  453. self.youpaiptoolBar.youpaipshowsKeyboard = NO;
  454. }
  455. }
  456. else
  457. {
  458. [self youpaifrefreshStatus:BBNIMInputStatusText];
  459. self.youpaiptoolBar.youpaipshowsKeyboard = YES;
  460. }
  461. }
  462. - (void)youpaifonTouchMoreBtn:(id)sender {
  463. if (self.youpaipstatus != BBNIMInputStatusMore)
  464. {
  465. if ([self.actionDelegate respondsToSelector:@selector(onTapMoreBtn:)]) {
  466. [self.actionDelegate onTapMoreBtn:sender];
  467. }
  468. [self youpaifcheckMoreContainer];
  469. [self bringSubviewToFront:self.youpaipmoreContainer];
  470. [self.youpaipmoreContainer setHidden:NO];
  471. [self.youpaipemoticonContainer setHidden:YES];
  472. [self youpaifrefreshStatus:BBNIMInputStatusMore];
  473. [self sizeToFit];
  474. if (self.youpaiptoolBar.youpaipshowsKeyboard)
  475. {
  476. self.youpaiptoolBar.youpaipshowsKeyboard = NO;
  477. }
  478. }
  479. else
  480. {
  481. [self youpaifrefreshStatus:BBNIMInputStatusText];
  482. self.youpaiptoolBar.youpaipshowsKeyboard = YES;
  483. }
  484. }
  485. - (BOOL)endEditing:(BOOL)force
  486. {
  487. BOOL endEditing = [super endEditing:force];
  488. if (!self.youpaiptoolBar.youpaipshowsKeyboard) {
  489. UIViewAnimationCurve curve = UIViewAnimationCurveEaseInOut;
  490. void(^animations)(void) = ^{
  491. [self youpaifrefreshStatus:BBNIMInputStatusText];
  492. [self sizeToFit];
  493. if (self.inputDelegate && [self.inputDelegate respondsToSelector:@selector(didChangeInputHeight:)]) {
  494. [self.inputDelegate didChangeInputHeight:self.nim_height];
  495. }
  496. };
  497. NSTimeInterval duration = 0.25;
  498. [UIView animateWithDuration:duration delay:0.0f options:(curve << 16 | UIViewAnimationOptionBeginFromCurrentState) animations:animations completion:nil];
  499. }
  500. return endEditing;
  501. }
  502. #pragma mark - NIMInputToolBarDelegate
  503. - (BOOL)textViewShouldBeginEditing
  504. {
  505. [self youpaifrefreshStatus:BBNIMInputStatusText];
  506. return YES;
  507. }
  508. - (BOOL)shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
  509. {
  510. if ([text isEqualToString:@"\n"])
  511. {
  512. [self youpaifdidPressSend:nil];
  513. return NO;
  514. }
  515. if ([text isEqualToString:@""] && range.length == 1 )
  516. {
  517. //非选择删除
  518. return [self youpaifonTextDelete];
  519. }
  520. if ([self shouldCheckAt])
  521. {
  522. // @ 功能
  523. [self checkAt:text];
  524. }
  525. NSString *str = [self.youpaiptoolBar.youpaipcontentText stringByAppendingString:text];
  526. if (str.length > self.youpaipmaxTextLength)
  527. {
  528. return NO;
  529. }
  530. return YES;
  531. }
  532. - (BOOL)shouldCheckAt
  533. {
  534. BOOL youpaipdisable = NO;
  535. if ([self.youpaipinputConfig respondsToSelector:@selector(disableAt)])
  536. {
  537. youpaipdisable = [self.youpaipinputConfig disableAt];
  538. }
  539. return !youpaipdisable;
  540. }
  541. - (void)checkAt:(NSString *)text
  542. {
  543. if ([text isEqualToString:NIMInputAtStartChar]) {
  544. switch (self.session.sessionType) {
  545. case NIMSessionTypeTeam:{
  546. NIMContactTeamMemberSelectConfig *config = [[NIMContactTeamMemberSelectConfig alloc] init];
  547. if ([self.youpaipinputConfig respondsToSelector:@selector(enableRobot)])
  548. {
  549. config.enableRobot = [self.youpaipinputConfig enableRobot];
  550. }
  551. else
  552. {
  553. config.enableRobot = YES;
  554. }
  555. config.needMutiSelected = NO;
  556. config.teamId = self.session.sessionId;
  557. config.filterIds = @[[NIMSDK sharedSDK].loginManager.currentAccount];
  558. NIMContactSelectViewController *vc = [[NIMContactSelectViewController alloc] initWithConfig:config];
  559. vc.delegate = self;
  560. dispatch_async(dispatch_get_main_queue(), ^{
  561. [vc show];
  562. });
  563. }
  564. break;
  565. case NIMSessionTypeP2P:
  566. case NIMSessionTypeChatroom:{
  567. if (([self.youpaipinputConfig respondsToSelector:@selector(enableRobot)] && self.youpaipinputConfig.enableRobot) || [NIMSDK sharedSDK].isUsingDemoAppKey)
  568. {
  569. NIMContactRobotSelectConfig *config = [[NIMContactRobotSelectConfig alloc] init];
  570. config.needMutiSelected = NO;
  571. NIMContactSelectViewController *vc = [[NIMContactSelectViewController alloc] initWithConfig:config];
  572. vc.delegate = self;
  573. dispatch_async(dispatch_get_main_queue(), ^{
  574. [vc show];
  575. });
  576. }
  577. }
  578. break;
  579. default:
  580. break;
  581. }
  582. }
  583. }
  584. - (void)textViewDidChange
  585. {
  586. if (self.actionDelegate && [self.actionDelegate respondsToSelector:@selector(onTextChanged:)])
  587. {
  588. [self.actionDelegate onTextChanged:self];
  589. }
  590. }
  591. - (void)toolBarDidChangeHeight:(CGFloat)height
  592. {
  593. [self sizeToFit];
  594. }
  595. #pragma mark - NIMContactSelectDelegate
  596. - (void)didFinishedSelect:(NSArray *)selectedContacts
  597. {
  598. NSMutableString *str = [[NSMutableString alloc] initWithString:@""];
  599. NIMKitInfoFetchOption *option = [[NIMKitInfoFetchOption alloc] init];
  600. option.session = self.session;
  601. option.forbidaAlias = YES;
  602. for (NSString *uid in selectedContacts) {
  603. NSString *nick = [[NIMKit sharedKit].provider infoByUser:uid option:option].showName;
  604. [str appendString:nick];
  605. [str appendString:NIMInputAtEndChar];
  606. if (![selectedContacts.lastObject isEqualToString:uid]) {
  607. [str appendString:NIMInputAtStartChar];
  608. }
  609. NIMInputAtItem *item = [[NIMInputAtItem alloc] init];
  610. item.uid = uid;
  611. item.name = nick;
  612. [self.youpaipatCache addAtItem:item];
  613. }
  614. [self.youpaiptoolBar youpaifinsertText:str];
  615. }
  616. #pragma mark - InputEmoticonProtocol
  617. - (void)selectedEmoticon:(NSString*)emoticonID catalog:(NSString*)emotCatalogID description:(NSString *)description{
  618. if (!emotCatalogID) { //删除键
  619. [self youpaifonTextDelete];
  620. }else{
  621. if ([emotCatalogID isEqualToString:NIMKit_EmojiCatalog]) {
  622. [self.youpaiptoolBar youpaifinsertText:description];
  623. }else{
  624. //发送贴图消息
  625. if ([self.actionDelegate respondsToSelector:@selector(onSelectChartlet:catalog:)]) {
  626. [self.actionDelegate onSelectChartlet:emoticonID catalog:emotCatalogID];
  627. }
  628. }
  629. }
  630. }
  631. - (void)youpaifdidPressSend:(id)sender{
  632. if ([self.actionDelegate respondsToSelector:@selector(onSendText:atUsers:)] && [self.youpaiptoolBar.youpaipcontentText length] > 0) {
  633. NSString *sendText = self.youpaiptoolBar.youpaipcontentText;
  634. [self.actionDelegate onSendText:sendText atUsers:[self.youpaipatCache youpaifallAtUid:sendText]];
  635. [self.youpaipatCache clean];
  636. self.youpaiptoolBar.youpaipcontentText = @"";
  637. [self.youpaiptoolBar layoutIfNeeded];
  638. }
  639. }
  640. - (BOOL)youpaifonTextDelete
  641. {
  642. NSRange range = [self youpaifdelRangeForEmoticon];
  643. if (range.length == 1)
  644. {
  645. //删的不是表情,可能是@
  646. NIMInputAtItem *item = [self delRangeForAt];
  647. if (item) {
  648. range = item.range;
  649. }
  650. }
  651. if (range.length == 1) {
  652. //自动删除
  653. return YES;
  654. }
  655. [self.youpaiptoolBar youpaifdeleteText:range];
  656. return NO;
  657. }
  658. - (NSRange)youpaifdelRangeForEmoticon
  659. {
  660. NSString *text = self.youpaiptoolBar.youpaipcontentText;
  661. NSRange range = [self youpaifrangeForPrefix:@"[" suffix:@"]"];
  662. NSRange selectedRange = [self.youpaiptoolBar youpaifselectedRange];
  663. if (range.length > 1)
  664. {
  665. NSString *name = [text substringWithRange:range];
  666. NIMInputEmoticon *icon = [[YOUPAINIMInputEmoticonManager sharedManager] emoticonByTag:name];
  667. range = icon? range : NSMakeRange(selectedRange.location - 1, 1);
  668. }
  669. return range;
  670. }
  671. - (NIMInputAtItem *)delRangeForAt
  672. {
  673. NSString *text = self.youpaiptoolBar.youpaipcontentText;
  674. NSRange range = [self youpaifrangeForPrefix:NIMInputAtStartChar suffix:NIMInputAtEndChar];
  675. NSRange selectedRange = [self.youpaiptoolBar youpaifselectedRange];
  676. NIMInputAtItem *item = nil;
  677. if (range.length > 1)
  678. {
  679. NSString *name = [text substringWithRange:range];
  680. NSString *set = [NIMInputAtStartChar stringByAppendingString:NIMInputAtEndChar];
  681. name = [name stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:set]];
  682. item = [self.youpaipatCache item:name];
  683. range = item? range : NSMakeRange(selectedRange.location - 1, 1);
  684. }
  685. item.range = range;
  686. return item;
  687. }
  688. - (NSRange)youpaifrangeForPrefix:(NSString *)prefix suffix:(NSString *)suffix
  689. {
  690. NSString *text = self.youpaiptoolBar.youpaipcontentText;
  691. NSRange range = [self.youpaiptoolBar youpaifselectedRange];
  692. NSString *selectedText = range.length ? [text substringWithRange:range] : text;
  693. NSInteger endLocation = range.location;
  694. if (endLocation <= 0)
  695. {
  696. return NSMakeRange(NSNotFound, 0);
  697. }
  698. NSInteger index = -1;
  699. if ([selectedText hasSuffix:suffix]) {
  700. //往前搜最多20个字符,一般来讲是够了...
  701. NSInteger p = 20;
  702. for (NSInteger i = endLocation; i >= endLocation - p && i-1 >= 0 ; i--)
  703. {
  704. NSRange subRange = NSMakeRange(i - 1, 1);
  705. NSString *subString = [text substringWithRange:subRange];
  706. if ([subString compare:prefix] == NSOrderedSame)
  707. {
  708. index = i - 1;
  709. break;
  710. }
  711. }
  712. }
  713. return index == -1? NSMakeRange(endLocation - 1, 1) : NSMakeRange(index, endLocation - index);
  714. }
  715. @end