ClassTitleView.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. //
  2. // ClassTitleView.m
  3. // StudentDaya
  4. //
  5. // Created by Kyle on 2020/6/12.
  6. // Copyright © 2020 DayaMusic. All rights reserved.
  7. //
  8. #import "ClassTitleView.h"
  9. #import "ClassroomService.h"
  10. #import "Masonry.h"
  11. #import <AVFoundation/AVFoundation.h>
  12. #import "RTCService.h"
  13. #define TSignalImageViewWidth (24)
  14. #define TTimeLableWidth (70)
  15. #define TTimeLableHeight (14)
  16. #define StateButtonWidth (34)
  17. #define TButtonWidth (24)
  18. #define TButtonSpace (20)
  19. #define THiddenDuration (3)
  20. @interface ClassTitleView ()
  21. //@property (nonatomic, strong) UILabel *timeLable;
  22. @property (nonatomic, strong) NSTimer *timeTimer;
  23. @property (nonatomic, strong) NSMutableArray *buttonArray;
  24. @property (nonatomic, strong) NSArray *buttonImageArray;
  25. @property (nonatomic, strong) NSArray *buttonHighlightedImageArray;
  26. @property (nonatomic, strong) NSArray *buttonCloseImageArray;
  27. @property (nonatomic, assign) NSInteger duration;
  28. @property (nonatomic, assign) NSInteger hiddenDuration;
  29. @property (nonatomic, assign) BOOL isCountDown;
  30. @end
  31. @implementation ClassTitleView
  32. - (instancetype)initWithFrame:(CGRect)frame
  33. {
  34. self = [super initWithFrame:frame];
  35. if (self) {
  36. self.backgroundColor = [HexRGB(0x141414) colorWithAlphaComponent:0.74];
  37. [self.buttonArray addObjectsFromArray:@[self.switchLineBtn,self.switchCameraBtn,self.microphoneBtn,self.cameraBtn,self.hangupBtn]];
  38. [self addSubviews];
  39. self.isCountDown = NO;
  40. self.duration = [ClassroomService sharedService].currentRoom.surplusTime;
  41. [self refreshTitleView];
  42. [self.timeTimer setFireDate:[NSDate distantPast]];
  43. }
  44. return self;
  45. }
  46. - (void)addSubviews {
  47. [self addSubview:self.signalImageView];
  48. // [self addSubview:self.timeLable];
  49. [self addSubview:self.switchLineBtn];
  50. [self addSubview:self.switchCameraBtn];
  51. [self addSubview:self.microphoneBtn];
  52. [self addSubview:self.cameraBtn];
  53. // [self addSubview:self.onShowLabel];
  54. [self addSubview:self.hangupBtn];
  55. CGFloat topOffset = (self.bounds.size.height - TButtonWidth) / 2.0;
  56. [self.signalImageView mas_makeConstraints:^(MASConstraintMaker *make) {
  57. make.left.mas_equalTo(self.mas_left).offset(20);
  58. make.centerY.mas_equalTo(self.mas_centerY);
  59. make.width.mas_equalTo(TSignalImageViewWidth);
  60. make.height.mas_equalTo(TSignalImageViewWidth);
  61. }];
  62. // [self.timeLable mas_makeConstraints:^(MASConstraintMaker *make) {
  63. // make.left.equalTo(self.signalImageView.mas_right).offset(20);
  64. // make.centerY.equalTo(self.mas_centerY);
  65. // make.width.equalTo(@TTimeLableWidth);
  66. // make.height.equalTo(@TTimeLableHeight);
  67. // }];
  68. // 切换线路
  69. [self.switchLineBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  70. make.left.mas_equalTo(self.signalImageView.mas_right).offset(20);
  71. make.width.mas_equalTo(TButtonWidth);
  72. make.height.mas_equalTo(TButtonWidth);
  73. make.top.mas_equalTo(self.mas_top).offset(topOffset);
  74. }];
  75. // 切换摄像头
  76. [self.switchCameraBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  77. make.left.mas_equalTo(self.switchLineBtn.mas_right).offset(TButtonSpace);
  78. make.width.mas_equalTo(TButtonWidth);
  79. make.height.mas_equalTo(TButtonWidth);
  80. make.top.mas_equalTo(self.mas_top).offset(topOffset);
  81. }];
  82. // 麦克风
  83. [self.microphoneBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  84. make.left.mas_equalTo(self.switchCameraBtn.mas_right).offset(TButtonSpace);
  85. make.width.mas_equalTo(TButtonWidth);
  86. make.height.mas_equalTo(TButtonWidth);
  87. make.top.mas_equalTo(self.mas_top).offset(topOffset);
  88. }];
  89. // 摄像头
  90. [self.cameraBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  91. make.left.mas_equalTo(self.microphoneBtn.mas_right).offset(TButtonSpace);
  92. make.width.mas_equalTo(TButtonWidth);
  93. make.height.mas_equalTo(TButtonWidth);
  94. make.top.mas_equalTo(self.mas_top).offset(topOffset);
  95. }];
  96. // 演示label
  97. // [self.onShowLabel mas_makeConstraints:^(MASConstraintMaker *make) {
  98. // make.left.mas_equalTo(self.cameraBtn.mas_right).offset(TButtonSpace * 2);
  99. // make.width.mas_equalTo(120);
  100. // make.height.mas_equalTo(TButtonWidth);
  101. // make.top.mas_equalTo(self.mas_top).offset(topOffset);
  102. // }];
  103. // 退出
  104. [self.hangupBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  105. make.right.mas_equalTo(self.mas_right).offset(-TButtonSpace);
  106. make.width.mas_equalTo(TButtonWidth);
  107. make.height.mas_equalTo(TButtonWidth);
  108. make.top.mas_equalTo(self.mas_top).offset(topOffset);
  109. }];
  110. self.isDisplay = YES;
  111. }
  112. - (void)clearUnreadMessage{
  113. Classroom *currentRoom = [ClassroomService sharedService].currentRoom;
  114. [[RCIMClient sharedRCIMClient] clearMessagesUnreadStatus:ConversationType_GROUP targetId:currentRoom.roomId];
  115. UIButton *button = (UIButton *)[self viewWithTag:ClassTitleViewActionTagChat];
  116. [button setBackgroundImage:[UIImage imageNamed:@"classnews_nomal"] forState:UIControlStateNormal];
  117. [button setBackgroundImage:[UIImage imageNamed:@"classnews_nomal"] forState:UIControlStateHighlighted];
  118. }
  119. - (void)refreshTitleView {
  120. [self setDefaultButtons];
  121. RoomMember *curMember = [ClassroomService sharedService].currentRoom.currentMember;
  122. // 判断显示状态
  123. [self isCameraAvailable:^(bool avilable) {
  124. if (avilable) {
  125. self.cameraBtn.selected = !curMember.cameraEnable;
  126. }else {
  127. self.cameraBtn.selected = YES;
  128. }
  129. }];
  130. [self isMicrophoneAvailable:^(bool avilable) {
  131. if (avilable) {
  132. self.microphoneBtn.selected = !curMember.microphoneEnable;
  133. }else {
  134. self.microphoneBtn.selected = YES;
  135. }
  136. }];
  137. }
  138. - (void)setDuration:(NSInteger)duration {
  139. _duration = duration;
  140. if (_duration < 300 && self.isCountDown == NO) {
  141. self.isCountDown = YES;
  142. // self.timeLable.textColor = HexRGB(0x2DC7AA);
  143. // [self.timeLable.layer addAnimation:[self opacityForeverAnimation:0.5f] forKey:nil];
  144. }
  145. }
  146. - (void)timeFunction:(NSTimer *)timer {
  147. // 隐藏titleView
  148. if (self.isDisplay) {
  149. if (self.hiddenDuration > 0) {
  150. self.hiddenDuration -= 1;
  151. }
  152. else {
  153. self.hiddenDuration = 0;
  154. self.isDisplay = NO;
  155. [self hiddenView];
  156. }
  157. }
  158. // self.timeLable.text = [self formatJoinTime];
  159. if (self.delegate && [self.delegate respondsToSelector:@selector(refreshClassStatus)]) {
  160. [self.delegate refreshClassStatus];
  161. }
  162. }
  163. - (void)stopDurationTimer {
  164. [self.timeTimer setFireDate:[NSDate distantFuture]];
  165. if (self.timeTimer.valid) {
  166. [self.timeTimer invalidate];
  167. self.timeTimer = nil;
  168. }
  169. }
  170. - (void)tapEvent:(UIButton *)btn {
  171. if (btn.tag == ClassTitleViewActionTagMicrophone) {
  172. [self isMicrophoneAvailable:^(bool avilable) {
  173. if (!avilable) {
  174. #pragma clang diagnostic push
  175. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  176. UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:NSLocalizedStringFromTable(@"microphoneAvailable", @"SealClass", nil) delegate:self cancelButtonTitle:NSLocalizedStringFromTable(@"Cancel", @"SealClass", nil) otherButtonTitles:@"设置", nil];
  177. [alertView show];
  178. #pragma clang diagnostic pop
  179. return;
  180. }else {
  181. if(self.delegate && [self.delegate respondsToSelector:@selector(classTitleView:didTapAtTag:)]) {
  182. [self.delegate classTitleView:btn didTapAtTag:btn.tag];
  183. }
  184. }
  185. }];
  186. }
  187. else if (btn.tag == ClassTitleViewActionTagCamera) {
  188. [self isCameraAvailable:^(bool avilable) {
  189. if (!avilable) {
  190. #pragma clang diagnostic push
  191. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  192. UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:NSLocalizedStringFromTable(@"cameraAvailable", @"SealClass", nil) delegate:self cancelButtonTitle:NSLocalizedStringFromTable(@"Cancel", @"SealClass", nil) otherButtonTitles:@"设置", nil];
  193. [alertView show];
  194. #pragma clang diagnostic pop
  195. return;
  196. }else {
  197. if(self.delegate && [self.delegate respondsToSelector:@selector(classTitleView:didTapAtTag:)]) {
  198. [self.delegate classTitleView:btn didTapAtTag:btn.tag];
  199. }
  200. }
  201. }];
  202. }
  203. else {
  204. if (btn.tag == ClassTitleViewActionTagChat) {
  205. [self clearUnreadMessage];
  206. }
  207. if(self.delegate && [self.delegate respondsToSelector:@selector(classTitleView:didTapAtTag:)]) {
  208. [self.delegate classTitleView:btn didTapAtTag:btn.tag];
  209. }
  210. }
  211. }
  212. - (void)setDefaultButtons {
  213. self.buttonImageArray = @[@"line_switch",@"camera_switch", @"userMic_on", @"userCamera_on",@"class_hangUp"];
  214. self.buttonCloseImageArray = @[@"line_switch",@"camera_switch", @"userMic_off", @"userCamera_off", @"class_hangUp"];
  215. for(int i = 0; i < self.buttonArray.count; i++) {
  216. UIButton *button = [self.buttonArray objectAtIndex:i];
  217. button.enabled = YES;
  218. [button setBackgroundImage:[UIImage imageNamed:[self.buttonImageArray objectAtIndex:i]] forState:UIControlStateNormal];
  219. [button setBackgroundImage:[UIImage imageNamed:[self.buttonCloseImageArray objectAtIndex:i]] forState:UIControlStateSelected];
  220. }
  221. }
  222. - (NSString *)formatJoinTime {
  223. if (self.duration <= 0) {
  224. return @"00:00:00";
  225. }
  226. NSInteger durationInteger = self.duration--;
  227. NSInteger durationS = durationInteger % 60;
  228. NSInteger durationM = ((durationInteger - durationS) / 60) % 60;
  229. NSInteger durationH = (durationInteger - durationS - 60 * durationM) / 3600;
  230. NSMutableArray * durationArr = [NSMutableArray new];
  231. [durationArr addObject:[NSString stringWithFormat:@"%02ld", durationH]];
  232. [durationArr addObject:[NSString stringWithFormat:@"%02ld", durationM]];
  233. [durationArr addObject:[NSString stringWithFormat:@"%02ld", durationS]];
  234. return [durationArr componentsJoinedByString:@":"];
  235. }
  236. - (UIImageView *)signalImageView {
  237. if(!_signalImageView) {
  238. _signalImageView = [[UIImageView alloc] init];
  239. _signalImageView.image = [UIImage imageNamed:@"network_status1"];
  240. }
  241. return _signalImageView;
  242. }
  243. //- (UILabel *)timeLable {
  244. // if(!_timeLable) {
  245. // _timeLable = [[UILabel alloc] init];
  246. // _timeLable.font = [UIFont systemFontOfSize:14];
  247. // _timeLable.textColor = [UIColor colorWithHexString:@"FFFFFF" alpha:1];
  248. // }
  249. // return _timeLable;
  250. //}
  251. - (UIButton *)switchLineBtn {
  252. if (!_switchLineBtn) {
  253. _switchLineBtn = [[UIButton alloc] init];
  254. _switchLineBtn.enabled = YES;
  255. _switchLineBtn.tag = ClassTitleViewActionTagSwitchLine;
  256. [_switchLineBtn addTarget:self action:@selector(tapEvent:) forControlEvents:UIControlEventTouchUpInside];
  257. }
  258. return _switchLineBtn;
  259. }
  260. - (UIButton *)switchCameraBtn {
  261. if(!_switchCameraBtn) {
  262. _switchCameraBtn = [[UIButton alloc] init];
  263. _switchCameraBtn.enabled = YES;
  264. _switchCameraBtn.tag = ClassTitleViewActionTagSwitchCamera;
  265. [_switchCameraBtn addTarget:self action:@selector(tapEvent:) forControlEvents:UIControlEventTouchUpInside];
  266. }
  267. return _switchCameraBtn;
  268. }
  269. - (UIButton *)microphoneBtn {
  270. if(!_microphoneBtn) {
  271. _microphoneBtn = [[UIButton alloc] init];
  272. _microphoneBtn.enabled = YES;
  273. _microphoneBtn.tag = ClassTitleViewActionTagMicrophone;
  274. [_microphoneBtn addTarget:self action:@selector(tapEvent:) forControlEvents:UIControlEventTouchUpInside];
  275. }
  276. return _microphoneBtn;
  277. }
  278. - (UIButton *)cameraBtn {
  279. if (!_cameraBtn) {
  280. _cameraBtn = [[UIButton alloc] init];
  281. _cameraBtn.enabled = YES;
  282. _cameraBtn.tag = ClassTitleViewActionTagCamera;
  283. [_cameraBtn addTarget:self action:@selector(tapEvent:) forControlEvents:UIControlEventTouchUpInside];
  284. }
  285. return _cameraBtn;
  286. }
  287. //- (UILabel *)onShowLabel {
  288. // if (!_onShowLabel) {
  289. // _onShowLabel = [[UILabel alloc] init];
  290. // _onShowLabel.textColor = HexRGB(0xf9f9f9);
  291. // _onShowLabel.font = [UIFont systemFontOfSize:14.0f];
  292. // _onShowLabel.text = @"您已进入演示模式";
  293. // }
  294. // return _onShowLabel;
  295. //}
  296. - (UIButton *)hangupBtn {
  297. if(!_hangupBtn) {
  298. _hangupBtn = [[UIButton alloc] init];
  299. _hangupBtn.enabled = YES;
  300. _hangupBtn.tag = ClassTitleViewActionTagHangup;
  301. [_hangupBtn addTarget:self action:@selector(tapEvent:) forControlEvents:UIControlEventTouchUpInside];
  302. }
  303. return _hangupBtn;
  304. }
  305. - (NSMutableArray *)buttonArray {
  306. if (!_buttonArray) {
  307. _buttonArray = [[NSMutableArray alloc] init];
  308. }
  309. return _buttonArray;
  310. }
  311. - (NSTimer *)timeTimer {
  312. if (_timeTimer == nil) {
  313. _timeTimer = [NSTimer scheduledTimerWithTimeInterval:1
  314. target:self
  315. selector:@selector(timeFunction:)
  316. userInfo:nil
  317. repeats:YES];
  318. [[NSRunLoop currentRunLoop] addTimer:_timeTimer forMode:NSRunLoopCommonModes];
  319. }
  320. return _timeTimer;
  321. }
  322. - (void)setNetStatus:(NetWorkingStatus)netStatus {
  323. _netStatus = netStatus;
  324. NSString *displayImg = @"network_status1";
  325. switch (netStatus) {
  326. case NetWorkingStatus_Good:
  327. displayImg = @"network_status1";
  328. break;
  329. case NetWorkingStatus_Well:
  330. displayImg = @"network_status2";
  331. break;
  332. case NetWorkingStatus_Bad:
  333. displayImg = @"network_status3";
  334. break;
  335. case NetWorkingStatus_Poor:
  336. displayImg = @"network_status4";
  337. break;
  338. default:
  339. break;
  340. }
  341. self.signalImageView.image = [UIImage imageNamed:displayImg];
  342. }
  343. #pragma mark ----- 显示和隐藏title
  344. - (void)displayView {
  345. CGRect frame = self.frame;
  346. self.hiddenDuration = THiddenDuration;
  347. if (frame.origin.y == 0) {
  348. return;
  349. }
  350. [UIView animateWithDuration:0.3f animations:^{
  351. CGRect frame = self.frame;
  352. frame.origin.y = 0;
  353. self.frame = frame;
  354. }];
  355. }
  356. - (void)hiddenView {
  357. CGRect frame = self.frame;
  358. if (frame.origin.y < 0) {
  359. return;
  360. }
  361. [UIView animateWithDuration:0.3f animations:^{
  362. CGRect frame = self.frame;
  363. frame.origin.y = -frame.size.height;
  364. self.frame = frame;
  365. }];
  366. }
  367. - (void)setIsDisplay:(BOOL)isDisplay {
  368. _isDisplay = isDisplay;
  369. if (isDisplay) {
  370. [self displayView];
  371. }
  372. }
  373. #pragma mark === 永久闪烁的动画 ======
  374. - (CABasicAnimation *)opacityForeverAnimation:(CGFloat)time {
  375. CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
  376. animation.fromValue = [NSNumber numberWithFloat:1.0f];
  377. animation.toValue = [NSNumber numberWithFloat:0.0f];//这是透明度。
  378. animation.autoreverses = YES;
  379. animation.duration = time;
  380. animation.repeatCount = MAXFLOAT;
  381. animation.removedOnCompletion = NO;
  382. animation.fillMode = kCAFillModeForwards;
  383. animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
  384. return animation;
  385. }
  386. #pragma mark - UIAlertViewDelegate
  387. #pragma clang diagnostic push
  388. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  389. - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
  390. if (buttonIndex == 1) { // 去设置界面,开启相机访问权限
  391. [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
  392. }
  393. }
  394. #pragma clang diagnostic pop
  395. - (void)isCameraAvailable:(void (^)(bool avilable))successBlock {
  396. NSString *mediaType = AVMediaTypeVideo; //读取媒体类型
  397. AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType]; //读取设备授权状态
  398. if (AVAuthorizationStatusAuthorized == authStatus) {
  399. successBlock(YES);
  400. } else if(authStatus == AVAuthorizationStatusNotDetermined) {
  401. [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo
  402. completionHandler:^(BOOL granted) {
  403. dispatch_async(dispatch_get_main_queue(), ^{
  404. if (granted) {
  405. successBlock(YES);
  406. } else {
  407. successBlock(NO);
  408. }
  409. });
  410. }];
  411. }else {
  412. successBlock(NO);
  413. }
  414. }
  415. -(void)isMicrophoneAvailable:(void (^)(bool avilable))successBlock {
  416. AVAudioSessionRecordPermission authStatus = [[AVAudioSession sharedInstance] recordPermission];
  417. if (AVAudioSessionRecordPermissionGranted == authStatus) {
  418. successBlock(YES);
  419. } else if(authStatus == AVAudioSessionRecordPermissionUndetermined){
  420. [[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) {
  421. dispatch_async(dispatch_get_main_queue(), ^{
  422. if (granted) {
  423. successBlock(YES);
  424. } else {
  425. successBlock(NO);
  426. }
  427. });
  428. }];
  429. }else {
  430. successBlock(NO);
  431. }
  432. }
  433. /*
  434. // Only override drawRect: if you perform custom drawing.
  435. // An empty implementation adversely affects performance during animation.
  436. - (void)drawRect:(CGRect)rect {
  437. // Drawing code
  438. }
  439. */
  440. @end