TXClassroomViewController.m 82 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183
  1. //
  2. // TXClassroomViewController.m
  3. // TeacherDaya
  4. //
  5. // Created by 王智 on 2023/4/14.
  6. // Copyright © 2023 DayaMusic. All rights reserved.
  7. //
  8. #import "TXClassroomViewController.h"
  9. #import "TXClassTitleView.h"
  10. #import "TXClassroomVideoListView.h"
  11. #import "TXClassroomMainContainer.h"
  12. #import "TXClassRoomAlertView.h"
  13. #import "LoginHelper.h"
  14. #import "TXRTCService.h"
  15. // 成员列表
  16. #import "ClassMemberListView.h"
  17. // 聊天列表
  18. #import "TXChatAreaView.h"
  19. #import "Classroom.h"
  20. #import "ClassroomService.h"
  21. #import "AppDelegate.h"
  22. #import "KSWhiteboardControl.h"
  23. #import <UIDevice+TFDevice.h>
  24. #import "LocalRenderManager.h"
  25. #import <NSDate+Transform.h>
  26. #import "WhiteboardListView.h"
  27. #import "NewTXMetronomeAlertView.h"
  28. #import "KSTipsView.h"
  29. // 时间渲染
  30. #import "ClassroomTimerManager.h"
  31. //// 宫格视图
  32. #import "TXFullVideoView.h"
  33. #import "VideoMaskView.h"
  34. #import "TXTeachToolView.h"
  35. #import "AccompanyProgressView.h"
  36. #import "CustomNavViewController.h"
  37. #import "KSCloseCourseView.h"
  38. #import "KSImageDisplayView.h"
  39. #import <LLPhotoBrowser.h>
  40. #import "KSMediaManager.h"
  41. #import <UIImage+ResizeImage.h>
  42. #import "AccompanyView.h"
  43. #import "TXLiteAVSDK_Professional/TXLiteAVSDK.h"
  44. #import "KSRemoteUserManager.h"
  45. #import "TXQuitChooseView.h"
  46. #import "TXDanMuView.h"
  47. #import "TXTimeView.h"
  48. #import "CoursewareAlertView.h"
  49. #import "TXIMLinsenter.h"
  50. #define MAXBIGPHOTONUMBER (3)
  51. #define MAXPHOTONUMBER (3)
  52. #define COLUMNNUMBER (3)
  53. #define KBUTTON_LEFTSPACE (16)
  54. #define TitleViewHeight (66)
  55. #define PersonListViewWidth (280)
  56. #define WhiteboardListWidth (140+33)
  57. #define TTimeLableWidth (180)
  58. #define TTimeLableHeight (20)
  59. // 需添加TRTC 回调
  60. @interface TXClassroomViewController ()<UIGestureRecognizerDelegate,TXClassTitleViewDelegate,KSWhiteboardControlDelegate,ClassroomDelegate,TXClassroomMainContainerDelegate,TXClassVideoListViewDelegate,ClassMemberListViewDelegate,WhiteboardListViewDelegate,ClassroomTimerManagerDelegate,TXFullVideoViewDelegate,TeachToolViewDelegate,LLPhotoBrowserDelegate,TRTCCloudDelegate, TXRTCServiceDelegate>
  61. @property (nonatomic, strong) KSMediaManager *mediaManager;
  62. @property (nonatomic, strong) NSMutableArray *imageArray; // 图片数组
  63. @property (nonatomic, strong) NSMutableArray *imageAsset; // 图片 asset
  64. @property (nonatomic, strong) TXClassTitleView *titleView;
  65. @property (nonatomic, strong) TXClassroomMainContainer *containerView;
  66. @property (nonatomic, strong) TXClassroomVideoListView *videoListView;
  67. @property (nonatomic, strong) ClassMemberListView *memberListView;
  68. @property (nonatomic, strong) KSWhiteboardControl *wBoardCtrl;
  69. // 聊天的area
  70. @property (nonatomic, strong) TXChatAreaView *chatAreaView;
  71. @property (nonatomic, strong) WhiteboardListView *whiteboardListView;
  72. @property (nonatomic, strong) UILabel *networkLabel;
  73. @property (nonatomic, assign) BOOL cancleAlert;
  74. @property (nonatomic, assign) BOOL isQuitRoom; // 是否正在退出房间
  75. @property (nonatomic, assign) BOOL hasShowAlert;
  76. @property (nonatomic, assign) BOOL isChat;
  77. @property (nonatomic, strong) NewTXMetronomeAlertView *controlView;
  78. @property (nonatomic, strong) KSTipsView *tipsView;
  79. @property (nonatomic, strong) ClassroomTimerManager *timeManager;
  80. @property (nonatomic, strong) TXFullVideoView *squareView; // 宫格视频
  81. @property (nonatomic, assign) BOOL squareOn; // 是否开启宫格模式
  82. @property (nonatomic, strong) VideoMaskView *maskView;
  83. @property (nonatomic, strong) NSString *fileUrl;
  84. @property (nonatomic, strong) TXTeachToolView *toolView;
  85. @property (nonatomic, strong) AccompanyProgressView *progressView;
  86. @property (nonatomic, strong) KSCloseCourseView *closeCourseAlert;
  87. @property (nonatomic, strong) TXClassRoomAlertView *alertView;
  88. @property (nonatomic, strong) AccompanyView *accompanyView;
  89. @property (nonatomic, strong) NSString *songName; // 当前选择的曲目名称
  90. @property (nonatomic, strong) NSString *songId; // 当前选择的曲目id
  91. @property (nonatomic, strong) NSString *songUrl; // 当前播放的url
  92. @property (nonatomic, assign) BOOL isAccompany; // 当前选择的是否为伴奏
  93. @property (nonatomic, assign) NSInteger soundVolume; // 伴奏音量
  94. @property (nonatomic, strong) CoursewareAlertView *coursewareView;
  95. @property (nonatomic, strong) TRTCCloud *engine;
  96. /** 节拍类型 */
  97. @property (nonatomic, assign) KSMetronomeType type;
  98. /** 播放速率,范围40~240 */
  99. @property (nonatomic, assign) int rate;
  100. // 播放节拍器音量
  101. @property (nonatomic, assign) NSInteger volome;
  102. // 是否隐藏了列表
  103. @property (nonatomic, assign) BOOL videoListHidden;
  104. @property (nonatomic, strong) TXDanMuView *danView;
  105. @property (nonatomic, strong) TXTimeView *timeView;
  106. @property (nonatomic, strong) UIButton *showButton;
  107. // 返回白板按钮
  108. @property (nonatomic, strong) UIButton *backWhiteButton;
  109. @end
  110. @implementation TXClassroomViewController
  111. - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
  112. [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
  113. [coordinator animateAlongsideTransition:nil completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
  114. if (size.width > size.height) {
  115. [TRTC_MANAGER refreshGSMode];
  116. }
  117. }];
  118. }
  119. -(BOOL)prefersHomeIndicatorAutoHidden {
  120. return YES;
  121. }
  122. - (void)changeOrientation:(BOOL)isLandScape {
  123. if (isLandScape) {
  124. // 切换到横屏
  125. if (IS_IPAD) {
  126. self.zh_statusBarHidden = YES;
  127. }
  128. AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
  129. delegate.allowAutoRotate = YES;
  130. [UIDevice switchNewOrientation:UIInterfaceOrientationLandscapeRight inController:self];
  131. }
  132. else {
  133. // 切换到竖屏
  134. AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
  135. delegate.allowAutoRotate = NO;
  136. @weakObj(self);
  137. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  138. @strongObj(self);
  139. if (IS_IPAD) {
  140. self.zh_statusBarHidden = NO;
  141. }
  142. [UIDevice switchNewOrientation:UIInterfaceOrientationPortrait inController:self];
  143. });
  144. }
  145. }
  146. - (void)viewWillAppear:(BOOL)animated {
  147. [super viewWillAppear:animated];
  148. // 切换到横屏
  149. [[UIApplication sharedApplication] setIdleTimerDisabled:YES];
  150. _isPushChooseView = NO;
  151. if (_isPushChooseView) {
  152. NSLog(@"-----");
  153. }
  154. [IQKeyboardManager sharedManager].enableAutoToolbar = NO;
  155. }
  156. - (void)viewWillDisappear:(BOOL)animated {
  157. [super viewWillDisappear:animated];
  158. // 竖屏
  159. [[UIApplication sharedApplication] setIdleTimerDisabled:NO];
  160. if (_isPushChooseView == NO) {
  161. [self hideAlertView];
  162. [self judgeShowAlert];
  163. }
  164. [IQKeyboardManager sharedManager].enableAutoToolbar = YES;
  165. }
  166. - (void)hideAlertView {
  167. if (self.alertView && self.alertView.isShow) {
  168. [self.alertView dismissAlertView];
  169. }
  170. [self.memberListView hiddenAlert];
  171. if (_accompanyView && _accompanyView.isShow) {
  172. [_accompanyView dismissAlertView];
  173. }
  174. if (self.controlView && self.controlView.isShow) {
  175. [self.controlView dismissAlertView];
  176. }
  177. }
  178. - (void)judgeShowAlert {
  179. if (self.cancleAlert || self.hasShowAlert) {
  180. return;
  181. }
  182. if (![NSString isEmptyString:self.classEndTime]) {
  183. NSDateFormatter *dateFormatter = [NSObject getDateformatter];
  184. [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  185. NSDate *endDate = [dateFormatter dateFromString:self.classEndTime];
  186. NSDate *currentDate = [NSDate date];
  187. NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:endDate];
  188. if (timeInterval >= 0) { // 课程结束弹出评价
  189. self.hasShowAlert = YES;
  190. [[NSNotificationCenter defaultCenter] postNotificationName:@"showEvaluateAlert" object:self.courseId];
  191. }
  192. }
  193. }
  194. - (void)configBeatConfig {
  195. self.type = KSMetronomeType4V4;
  196. self.volome = 100;
  197. self.rate = 90;
  198. }
  199. - (void)configDefaultSoundVolume {
  200. self.soundVolume = 100;
  201. }
  202. - (void)viewDidAppear:(BOOL)animated {
  203. [super viewDidAppear:animated];
  204. // 切换到横屏
  205. [self changeOrientation:YES];
  206. }
  207. - (void)joinChatRoom {
  208. if (TXIM_LINSENTER.loginIMSuccess == NO) {
  209. NSString *imToken = UserDefault(IM_TOKEN);
  210. [TXIM_LINSENTER TXIMLoginWithUserId:UserDefault(IM_USERID) sig:imToken callback:^(BOOL isSuccess, NSString * _Nullable msg) {
  211. [self liveConversationJoin];
  212. }];
  213. }
  214. else {
  215. [self liveConversationJoin];
  216. }
  217. }
  218. - (void)liveConversationJoin {
  219. NSString *roomId = [ClassroomService sharedService].currentRoom.roomId;
  220. [[V2TIMManager sharedInstance] joinGroup:roomId msg:nil succ:^{
  221. } fail:^(int code, NSString *desc) {
  222. [self showErrorTips];
  223. }];
  224. }
  225. - (void)showErrorTips {
  226. [self.tipsView showTipsMessage:@"加入聊天群失败" inView:self.view];
  227. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  228. [[LoginHelper sharedInstance] logout];
  229. });
  230. }
  231. - (void)viewDidLoad {
  232. [super viewDidLoad];
  233. // Do any additional setup after loading the view.
  234. self.ks_prefersNavigationBarHidden = YES;
  235. [self joinChatRoom];
  236. self.view.backgroundColor = [UIColor whiteColor];
  237. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(leaveRoomAction) name:@"classroomLogout" object:nil];
  238. [self configBeatConfig]; // 设置默认节拍器数据
  239. [self configDefaultSoundVolume]; // 设置默认伴奏音量
  240. [self configClassroomDefault];
  241. UITapGestureRecognizer *tapGes = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGesture:)];
  242. [self.view addGestureRecognizer:tapGes];
  243. tapGes.delegate = self;
  244. [self showRoleHud];
  245. [TRTC_MANAGER useSpeaker:YES];
  246. self.isQuitRoom = NO;
  247. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backgroundQuitRoomAction) name:@"backgroundQuit" object:nil];
  248. }
  249. - (void)configClassroomDefault {
  250. [self addSubviews];
  251. [self bindDelegates];
  252. [self publishStream];
  253. [self renderMainContainerView];
  254. self.timeManager.isDisplay = YES;
  255. }
  256. - (void)backgroundQuitRoomAction {
  257. self.isQuitRoom = YES;
  258. [[LoginHelper sharedInstance] logout];
  259. self.cancleAlert = YES;
  260. }
  261. #pragma mark ----- 账号异地登陆
  262. - (void)leaveRoomAction {
  263. [LOADING_MANAGER MBShowAUTOHidingInWindow:@"该账号在其他设备上登录"];
  264. @weakObj(self);
  265. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  266. @strongObj(self);
  267. self.isQuitRoom = YES;
  268. [[LoginHelper sharedInstance] logout];
  269. self.cancleAlert = YES;
  270. [TRTC_MANAGER leaveRoom:^(NSInteger code) {
  271. }];
  272. [self hideAlertView];
  273. });
  274. }
  275. - (void)tapGesture: (UITapGestureRecognizer *)tapGesture {
  276. if (self.titleView.isDisplay) {
  277. self.titleView.isDisplay = NO;
  278. self.timeManager.isDisplay = NO;
  279. }
  280. else {
  281. self.titleView.isDisplay = YES;
  282. self.timeManager.isDisplay = YES;
  283. }
  284. [self hidePersonListView];
  285. [self hideChatAreaView];
  286. [self.danView resetInputStatus];
  287. }
  288. - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
  289. if ([touch.view isDescendantOfView:self.memberListView] || [touch.view isDescendantOfView:self.chatAreaView] || [touch.view isDescendantOfView:self.videoListView] || [touch.view isDescendantOfView:self.whiteboardListView]
  290. || [touch.view isDescendantOfView:self.squareView] || [touch.view isDescendantOfView:self.maskView] || [touch.view isDescendantOfView:self.toolView] || [touch.view isDescendantOfView:self.closeCourseAlert] || [touch.view isDescendantOfView:self.danView] || [touch.view isDescendantOfView:self.titleView]) {
  291. [self.danView resetInputStatus];
  292. return NO;
  293. }
  294. return YES;
  295. }
  296. - (void)showRoleHud {
  297. Role role = [ClassroomService sharedService].currentRoom.currentMember.role;
  298. if(role == RoleAudience) {
  299. [self.tipsView showTipsMessage:@"你当前身份是旁听人,其他人看/听不见你" inView:self.view];
  300. [self performSelector:@selector(showOnlyYouHUD) withObject:nil afterDelay:5.0f];
  301. } else{
  302. [self showOnlyYouHUD];
  303. }
  304. }
  305. - (void)showOnlyYouHUD {
  306. if ([ClassroomService sharedService].currentRoom.memberList.count == 1) {
  307. [self.tipsView showTipsMessage:@"当前课堂只有你一人,你可以等待或离开" inView:self.view];
  308. }
  309. }
  310. #pragma mark ------ ClassTitleViewDelegate
  311. - (void)classTitleView:(UIButton *)button didTapAtTag:(ClassTitleViewActionTag)tag {
  312. [self.chatAreaView resetInputStatus];
  313. [self.danView resetInputStatus];
  314. ClassRoomTitleButton *tagButton = [self.titleView viewWithTag:tag+1000];
  315. switch (tag) {
  316. case ClassTitleViewActionTagSwitchCamera:
  317. {
  318. [TRTC_MANAGER switchCamera];
  319. }
  320. break;
  321. case ClassTitleViewActionTagMic:
  322. {
  323. if (tagButton.isSelected == NO) { // 关闭
  324. [[ClassroomService sharedService] enableDevice:NO songId:@"" withType:DeviceTypeMicrophone];
  325. }
  326. else { // 打开
  327. [[ClassroomService sharedService] enableDevice:YES songId:@"" withType:DeviceTypeMicrophone];
  328. }
  329. }
  330. break;
  331. case ClassTitleViewActionTagCamera:
  332. {
  333. if (tagButton.isSelected == NO) {
  334. [[ClassroomService sharedService] enableDevice:NO songId:@"" withType:DeviceTypeCamera];
  335. }
  336. else {
  337. [[ClassroomService sharedService] enableDevice:YES songId:@"" withType:DeviceTypeCamera];
  338. }
  339. }
  340. break;
  341. case ClassTitleViewActionTagMute:
  342. {
  343. tagButton.isSelected = !tagButton.isSelected;
  344. [TRTC_MANAGER useSpeaker:!tagButton.isSelected];
  345. }
  346. break;
  347. case ClassTitleViewActionTagSquare: // 宫格模式
  348. {
  349. if (![NSString isEmptyString:[ClassroomService sharedService].currentRoom.shareUserId]) {
  350. // 当前
  351. [self.tipsView showTipsMessage:@"当前有学生演示中" inView:self.view];
  352. return;
  353. }
  354. self.squareOn = YES;
  355. [self.squareView showInView:self.view];
  356. [self.squareView showVideoList];
  357. }
  358. break;
  359. case ClassTitleViewActionTagDan: // 弹幕开关
  360. {
  361. BOOL isWhiteBoard = [ClassroomService sharedService].currentRoom.currentDisplayType == DisplayWhiteboard;
  362. if (tagButton.isSelected == YES && isWhiteBoard) { // 如果白板
  363. [self.tipsView showTipsMessage:@"白板模式下不可开启弹幕" inView:self.view];
  364. return;
  365. }
  366. tagButton.isSelected = !tagButton.isSelected;
  367. if (tagButton.isSelected) { // 关闭弹幕
  368. [self hideDanChatView];
  369. }
  370. else { // 开启弹幕
  371. [self showDanChatView];
  372. }
  373. }
  374. break;
  375. case ClassTitleViewActionTagChat:
  376. {
  377. tagButton.isSelected = !tagButton.isSelected;
  378. tagButton.isSelected ? [self showChatAreaView] : [self hideChatAreaView];
  379. self.isChat = tagButton.isSelected;
  380. }
  381. break;
  382. case ClassTitleViewActionTagMember:
  383. {
  384. tagButton.isSelected = !tagButton.isSelected;
  385. tagButton.isSelected ? [self showPersonListView] : [self hidePersonListView];
  386. }
  387. break;
  388. case ClassTitleViewActionTagHangup:
  389. {
  390. [self showQuitAlert];
  391. }
  392. default:
  393. break;
  394. }
  395. }
  396. - (void)quitViewAction:(QUITCLASSTYPE)type {
  397. if (type == QUITCLASSTYPE_CLOSE) {
  398. [self showCouseCloseAlert];
  399. }
  400. else {
  401. [self showQuitAlert];
  402. }
  403. }
  404. - (void)showQuitAlert {
  405. MJWeakSelf;
  406. self.alertView = [TXClassRoomAlertView shareInstance];
  407. [self.alertView configWithTitle:@"提示" desc:@"确认退出课堂吗?" leftTitle:@"取消" rightTitle:@"退出" cancel:^{
  408. } confirm:^{
  409. weakSelf.isQuitRoom = YES;
  410. [LOADING_MANAGER showCustomLoading:@"加载中..."];
  411. [[LoginHelper sharedInstance] logout];
  412. }];
  413. }
  414. #pragma mark ---- 节拍器控制
  415. - (void)showNodeControlView {
  416. [self hidePersonListView];
  417. self.controlView = [NewTXMetronomeAlertView shareInstance];
  418. [self.controlView configRate:self.rate volume:self.volome beatType:self.type];
  419. self.controlView.isPlayBeat = [ClassroomService sharedService].currentRoom.isPlayBeat;
  420. MJWeakSelf;
  421. [self.controlView showAlertSureCallback:^(int rate, KSMetronomeType type, NSInteger volume) {
  422. weakSelf.type = type;
  423. weakSelf.rate = rate;
  424. weakSelf.volome = volume;
  425. }];
  426. [self.controlView metronomeClickAction:^(BOOL enable) {
  427. [weakSelf metronomeAction:enable];
  428. }];
  429. }
  430. - (void)metronomeAction:(BOOL)enable {
  431. MJWeakSelf;
  432. // 播放节拍器
  433. if (enable == YES) {
  434. [ClassroomService sharedService].currentRoom.isPlayBeat = YES;
  435. if (![NSString isEmptyString:[ClassroomService sharedService].currentRoom.shareUserId]) {
  436. NSString *userId = [ClassroomService sharedService].currentRoom.shareUserId;
  437. [weakSelf operationStudentPlayNode:userId];
  438. }
  439. else {
  440. [weakSelf operationStudentPlayNode:@""];
  441. }
  442. if ([ClassroomService sharedService].currentRoom.isPlaySong) {
  443. [ClassroomService sharedService].currentRoom.isPlaySong = NO;
  444. DeviceType type = self.isAccompany ? DeviceTypeAccompany : DeviceTypeMusicScore;
  445. [[ClassroomService sharedService] enableMutilMemberDevice:NO type:type songId:weakSelf.songId soundVolume:weakSelf.soundVolume forUser:@""];
  446. weakSelf.accompanyView.isPlaying = NO;
  447. }
  448. }
  449. else {
  450. NSDictionary *parm = @{@"enable": @(NO),
  451. @"rate" : @(0),
  452. @"customType" : @(0),
  453. @"playVolume" : @(0),
  454. @"userId" : @"",
  455. };
  456. [[ClassroomService sharedService] enablePlayMessage:NO content:[parm mj_JSONString] userId:@""];
  457. [ClassroomService sharedService].currentRoom.isPlayBeat = NO;
  458. [weakSelf unplayBeatNodeRefreshStream]; // 刷新音频流播放
  459. }
  460. }
  461. - (void)operationStudentPlayNode:(NSString *)userId {
  462. NSDictionary *parm = @{@"enable": @(YES),
  463. @"rate" : @(self.rate),
  464. @"customType" : @(self.type),
  465. @"playVolume" : @(self.volome),
  466. @"userId" : userId,
  467. };
  468. [[ClassroomService sharedService] enablePlayMessage:YES content:[parm mj_JSONString] userId:userId];
  469. // 默认显示第一个学生的视频 单个操作不再次刷新主屏
  470. if (self.videoListView.videoDataSource.count >= 1 && [NSString isEmptyString:userId]) {
  471. for (RoomMember *member in self.videoListView.videoDataSource) {
  472. if (member.role == RoleStudent) {
  473. [self videoListView:nil didTap:member];
  474. break;
  475. }
  476. }
  477. }
  478. else if (![NSString isEmptyString:userId]) {
  479. [ClassroomService sharedService].currentRoom.currentPlayUserId = userId;
  480. [TRTC_MANAGER unPlayRemoteStudentAudioStreamExcept:userId];
  481. }
  482. }
  483. - (void)playNodeAction:(BOOL)enable userId:(NSString *)userId rate:(int)rate beatType:(BeatType)type {
  484. NSLog(@"playNodeAction userId:%@ enable:%@ beatType:%@ rate:%@",userId,@(enable),@(type), @(rate));
  485. // 刷新当前学生的节拍器状态
  486. if ([NSString isEmptyString:userId]) { // 全员
  487. for (RoomMember *member in [ClassroomService sharedService].currentRoom.memberList) {
  488. member.enable = enable;
  489. }
  490. }
  491. else { // 部分操作
  492. NSArray *userIdArray = [userId componentsSeparatedByString:@","];
  493. for (NSString *subUserId in userIdArray) {
  494. for (RoomMember *member in [ClassroomService sharedService].currentRoom.memberList) {
  495. if ([member.userId isEqualToString:subUserId]) {
  496. member.enable = enable;
  497. }
  498. }
  499. }
  500. }
  501. [self.containerView refreshToolView];
  502. }
  503. #pragma mark - ClassroomDelegate
  504. - (void)roomDidLeave {
  505. NSLog(@"roomDidLeave");
  506. // 关闭白板连接
  507. [self.wBoardCtrl.wbView.sdk setCommonCallbackDelegate:nil];
  508. [self.wBoardCtrl.wbView.room disconnect:^{
  509. }];
  510. [TRTC_MANAGER leaveRoom:^(NSInteger code) {
  511. }];
  512. [self dismissClassroom];
  513. }
  514. - (void)dismissClassroom {
  515. [LOADING_MANAGER removeCustomLoading];
  516. [ClassroomService sharedService].currentRoom = nil;
  517. [self changeOrientation:NO];
  518. [self.timeManager stopDurationTimer];
  519. [self.timeView.timeLabel.layer removeAllAnimations];
  520. [self.navigationController popViewControllerAnimated:YES];
  521. }
  522. - (void)memberDidJoin:(RoomMember *)member {
  523. NSLog(@"memberDidJoin %@",member);
  524. if(member.role == RoleStudent) {
  525. [self.tipsView showTipsMessage:[NSString stringWithFormat:@"学生%@已经进入教室", member.name] inView:self.view];
  526. if (self.squareOn) {
  527. [self.squareView showVideoList];
  528. }
  529. else {
  530. [self.videoListView reloadVideoList];
  531. }
  532. // 如果在播放中
  533. if ([ClassroomService sharedService].currentRoom.isPlayBeat || [ClassroomService sharedService].currentRoom.isPlaySong) {
  534. if ([ClassroomService sharedService].currentRoom.memberList.count > 2) {
  535. [TRTC_MANAGER unPlayRemoteStudentWithId:member.userId];
  536. }
  537. }
  538. }
  539. [self.memberListView reloadPersonList];
  540. }
  541. - (void)memberDidLeave:(RoomMember *)member {
  542. NSLog(@"memberDidLeave %@",member);
  543. if(member.role != RoleAudience) {
  544. if (member.role == RoleStudent) {
  545. [self.tipsView showTipsMessage:[NSString stringWithFormat:@"学生%@已经离开教室", member.name] inView:self.view];
  546. if (self.squareOn && [member.userId isEqualToString:self.squareView.displayUserId]) {
  547. [self dismissMaskViewEvent];
  548. }
  549. // 如果主屏上台学生
  550. if ([ClassroomService sharedService].currentRoom.shareUserId == member.userId) {
  551. [self teachToolView:self.toolView.videoButton.actionButton didTapAtTag:TeachToolTagVideo];
  552. }
  553. else {
  554. if ([ClassroomService sharedService].currentRoom.currentDisplayType == DisplayTypeStudent && [[ClassroomService sharedService].currentRoom.currentDisplayURI isEqualToString:member.userId]) {
  555. [self teachToolView:self.toolView.videoButton.actionButton didTapAtTag:TeachToolTagVideo];
  556. }
  557. }
  558. }
  559. if (self.squareOn) {
  560. [self.squareView showVideoList];
  561. }
  562. else {
  563. [self.videoListView reloadVideoList];
  564. }
  565. }
  566. [self.memberListView reloadPersonList:member tag:ClassPersonListTagRemove];
  567. if ([self.progressView isShow]) {
  568. [self.progressView requestData];
  569. }
  570. }
  571. - (void)memberDidKick:(RoomMember *)member {
  572. NSLog(@"memberDidKick %@",member);
  573. if ([ClassroomService sharedService].currentRoom.currentMember.role == RoleTeacher) {
  574. [self.tipsView showTipsMessage:[NSString stringWithFormat:@"你已将%@移出教室", member.name] inView:self.view];
  575. }
  576. if (self.squareOn) {
  577. [self.squareView showVideoList];
  578. }
  579. else {
  580. [self.videoListView reloadVideoList];
  581. }
  582. [self.memberListView reloadPersonList:member tag:ClassPersonListTagRemove];
  583. if (self.containerView.member.role == member.role) {
  584. [self.containerView cancelRenderView];
  585. }
  586. }
  587. - (void)errorDidOccur:(ErrorCode)code {
  588. NSLog(@"errorDidOccur %@",@(code));
  589. [LOADING_MANAGER removeCustomLoading];
  590. if (code != ErrorCodeSuccess) {
  591. if (code == ErrorCodeOverMaxUserCount) {
  592. [self.tipsView showTipsMessage:@"超过人数限制" inView:self.view];
  593. }else {
  594. [self.tipsView showTipsMessage:@"操作失败,请稍后再试" inView:self.view];
  595. }
  596. }
  597. }
  598. - (void)deviceDidEnable:(BOOL)enable type:(DeviceType)type forUser:(RoomMember *)member operator:(nonnull NSString *)operatorId {
  599. NSLog(@"deviceDidEnable devicetype:%@ enable:%@ memeber:%@",@(type),@(enable),member);
  600. RoomMember *curMember = [ClassroomService sharedService].currentRoom.currentMember;
  601. NSString *hudMessage = @"";
  602. //只有老师和自己才有提示
  603. if (curMember.role == RoleTeacher && ![member.userId isEqualToString:curMember.userId]) {
  604. if (type == DeviceTypeCamera) {
  605. hudMessage = !enable ? [NSString stringWithFormat:NSLocalizedStringFromTable(@"SetCameraClose", @"SealClass", nil),member.name] : [NSString stringWithFormat:NSLocalizedStringFromTable(@"SetCameraOpen", @"SealClass", nil),member.name];
  606. [self refreshVideoView:member];
  607. } else if (type == DeviceTypeMicrophone) {
  608. hudMessage = !enable ? [NSString stringWithFormat:NSLocalizedStringFromTable(@"SetMicorophoneClose", @"SealClass", nil),member.name] : [NSString stringWithFormat:NSLocalizedStringFromTable(@"SetMicorophoneOpen", @"SealClass", nil),member.name];
  609. [self.containerView refreshToolView];
  610. [self.memberListView reloadPersonList:member tag:ClassPersonListTagRefresh];
  611. [self.videoListView updateMicStatus:member.userId volume:40];
  612. }
  613. else if (type == DeviceTypeMusicMode) {
  614. }
  615. else if (type == DeviceTypeHandup) {
  616. if (![curMember.userId isEqualToString:operatorId]) {
  617. hudMessage = !enable ? [NSString stringWithFormat:@"%@已取消举手",member.name] : [NSString stringWithFormat:@"%@已举手",member.name];
  618. }
  619. if (self.squareOn) {
  620. [self.squareView showVideoList];
  621. }
  622. else {
  623. [self.videoListView reloadVideoList];
  624. }
  625. [self.memberListView reloadPersonList:member tag:ClassPersonListTagRefresh];
  626. }
  627. else if (type == DeviceTypeExamSong) { // 伴奏播放
  628. }
  629. else if (type == DeviceTypeAccompany || type == DeviceTypeMusicScore) { // 新伴奏 或原声播放
  630. }
  631. if (![NSString isEmptyString:hudMessage]) {
  632. [self.tipsView showTipsMessage:hudMessage inView:self.view];
  633. }
  634. }else {
  635. if ([curMember.userId isEqualToString:member.userId]) {
  636. if (type == DeviceTypeCamera) { // 摄像头
  637. // 非自己操作才需要做提示
  638. if(![curMember.userId isEqualToString:operatorId]){
  639. hudMessage = !enable ? NSLocalizedStringFromTable(@"YourCameraClosed", @"SealClass", nil) : NSLocalizedStringFromTable(@"CameraOpend", @"SealClass", nil);
  640. [self.tipsView showTipsMessage:hudMessage inView:self.view];
  641. }
  642. [self refreshHardwareStatus];
  643. [TRTC_MANAGER setCameraDisable:!enable];
  644. [self refreshVideoView:member];
  645. return;
  646. } else if (type == DeviceTypeMicrophone) { // 麦克风
  647. // 非自己操作才需要做提示
  648. if(![curMember.userId isEqualToString:operatorId]){
  649. hudMessage = !enable ? NSLocalizedStringFromTable(@"YourMicorophoneClosed", @"SealClass", nil) : NSLocalizedStringFromTable(@"MicorophoneOpend", @"SealClass", nil);
  650. [self.tipsView showTipsMessage:hudMessage inView:self.view];
  651. }
  652. [self refreshHardwareStatus];
  653. [TRTC_MANAGER setMicrophoneDisable:!enable];
  654. [self.videoListView updateMicStatus:member.userId volume:40];
  655. }
  656. else if (type == DeviceTypeMusicMode) {
  657. }
  658. }
  659. }
  660. }
  661. - (void)refreshHardwareStatus {
  662. [self.titleView refreshTitleView];
  663. [self.containerView refreshToolView];
  664. }
  665. // 刷新单个视频显示
  666. - (void)refreshVideoView:(RoomMember *)member {
  667. if (self.squareOn) {
  668. [self.squareView showVideoList];
  669. }
  670. else {
  671. // 刷新单个数据
  672. RoomMember *curMember = [ClassroomService sharedService].currentRoom.currentMember;
  673. if ([member.userId isEqualToString:curMember.userId]) {
  674. if ([ClassroomService sharedService].currentRoom.currentDisplayType != DisplayWhiteboard && [[ClassroomService sharedService].currentRoom.currentDisplayURI isEqualToString:member.userId]) {
  675. [self.wBoardCtrl hideBoard];
  676. [self.containerView containerViewRenderView:member];
  677. }
  678. else {
  679. [self.videoListView updateUserVideo:member.userId];
  680. }
  681. [self.titleView refreshTitleView];
  682. }
  683. else {
  684. if ([ClassroomService sharedService].currentRoom.currentDisplayType != DisplayWhiteboard && [[ClassroomService sharedService].currentRoom.currentDisplayURI isEqualToString:member.userId]) {
  685. [self.wBoardCtrl hideBoard];
  686. [self.containerView containerViewRenderView:member];
  687. }
  688. else {
  689. [self.videoListView updateUserVideo:member.userId];
  690. }
  691. [self.memberListView reloadPersonList:member tag:ClassPersonListTagRefresh];
  692. }
  693. }
  694. [self.containerView refreshToolView];
  695. }
  696. - (void)whiteboardDidDisplay:(NSString *)boardId {
  697. NSLog(@"whiteboardDidDisplay %@ ",boardId);
  698. [self renderMainContainerView];
  699. }
  700. - (void)sharedScreenDidDisplay:(NSString *)userId {
  701. NSLog(@"sharedScreenDidDisplay %@ ",userId);
  702. [self renderMainContainerView];
  703. }
  704. - (void)teacherDidDisplay {
  705. NSLog(@"teacherDidDisplay %@ ",[ClassroomService sharedService].currentRoom.teacher);
  706. [self renderMainContainerView];
  707. }
  708. - (void)studentDidDisplay:(NSString *)studentId {
  709. NSLog(@"studentDidDisplay %@", studentId);
  710. [self renderMainContainerView];
  711. }
  712. - (void)noneDidDisplay {
  713. NSLog(@"noneDidDisplay");
  714. [self renderMainContainerView];
  715. }
  716. #pragma mark ---- whiteboardListDelegate
  717. - (void)whiteboardSharedViewCellTap:(id)recentShared {
  718. if ([recentShared isKindOfClass:[WhiteScene class]]) {
  719. [LocalRenderManager shareInstance].hadRenderMainView = NO;
  720. [TRTC_MANAGER cancleRenderUserVideo:[ClassroomService sharedService].currentRoom.currentDisplayURI];
  721. WhiteScene *whiteBoard = (WhiteScene *)recentShared;
  722. [self displayWhiteboard:whiteBoard.name];
  723. [ClassroomService sharedService].currentRoom.currentDisplayURI = whiteBoard.name;
  724. }
  725. }
  726. #pragma mark ---- TRTC delegate
  727. #pragma mark - private method
  728. - (void)bindDelegates {
  729. [ClassroomService sharedService].classroomDelegate = self;
  730. TRTC_MANAGER.delegate = self;
  731. }
  732. - (void)addSubviews {
  733. [self.view addSubview:self.containerView];
  734. [self.view addSubview:self.timeView];
  735. [self.timeView mas_makeConstraints:^(MASConstraintMaker *make) {
  736. make.right.mas_equalTo(self.containerView.emptyView.mas_right).offset(-20);
  737. make.top.mas_equalTo(self.view.mas_top);
  738. make.height.mas_equalTo(44);
  739. }];
  740. [self.view bringSubviewToFront:self.timeView];
  741. [self.view addSubview:self.backWhiteButton];
  742. [self.view bringSubviewToFront:self.backWhiteButton];
  743. [self.backWhiteButton mas_makeConstraints:^(MASConstraintMaker *make) {
  744. make.width.mas_equalTo(72);
  745. make.height.mas_equalTo(26);
  746. make.top.mas_equalTo(self.view.mas_top).offset(16);
  747. make.right.mas_equalTo(self.timeView.mas_left).offset(-12);
  748. }];
  749. self.backWhiteButton.hidden = YES;
  750. [self.view addSubview:self.titleView];
  751. [self wBoardCtrl];
  752. [self chatAreaView];
  753. [self memberListView];
  754. [self.view addSubview:self.videoListView];
  755. [self.view addSubview:self.toolView];
  756. [self showDanChatView];
  757. CGFloat height = 275;
  758. [self.toolView mas_makeConstraints:^(MASConstraintMaker *make) {
  759. make.right.mas_equalTo(self.containerView.emptyView.mas_right);
  760. make.width.mas_equalTo(82);
  761. make.height.mas_equalTo(height);
  762. make.bottom.mas_equalTo(self.containerView.emptyView.mas_bottom);
  763. }];
  764. [self.toolView hiddenToolViewWithAnimation:NO];
  765. [self.view bringSubviewToFront:self.toolView];
  766. [self.view bringSubviewToFront:self.titleView];
  767. }
  768. - (void)showPersonListView {
  769. [self.view addSubview:self.memberListView];
  770. [self.memberListView reloadPersonList];
  771. }
  772. - (void)showChatAreaView{
  773. [self.view addSubview:self.chatAreaView];
  774. [self.chatAreaView scrollToBottom];
  775. }
  776. - (void)hidePersonListView {
  777. self.titleView.memberBtn.isSelected = NO;
  778. [self.memberListView removeFromSuperview];
  779. }
  780. - (void)hideChatAreaView{
  781. [UIView animateWithDuration:0.2 animations:^{
  782. self.titleView.chatBtn.isSelected = NO;
  783. [self.chatAreaView resetInputStatus];
  784. [self.chatAreaView removeFromSuperview];
  785. }];
  786. }
  787. - (void)showDanChatView {
  788. // 视频页面添加弹幕
  789. [self.containerView.videoView addSubview:self.danView];
  790. [self.containerView.videoView bringSubviewToFront:self.containerView.toolView];
  791. }
  792. - (void)hideDanChatView {
  793. //
  794. [self.danView removeFromSuperview];
  795. }
  796. - (CGRect)mainContainerViewFrame {
  797. CGFloat x = 0;
  798. CGFloat y = 0;
  799. CGFloat width = KLandscapeWidth - x;
  800. CGFloat height = KLandscapeHeight - y;
  801. return CGRectMake(x, y, width, height);
  802. }
  803. - (void)displayWhiteboard:(NSString *)boardId {
  804. CGRect boardFrame = [self getWBoardFrame];
  805. [self.wBoardCtrl loadWBoardWithFrame:boardFrame name:boardId];
  806. for (UIView * view in self.view.subviews) {
  807. if ([view isKindOfClass:[ClassMemberListView class]] || [view isKindOfClass:[TXChatAreaView class]] || [view isKindOfClass:[WhiteboardListView class]]) {
  808. [self.view bringSubviewToFront:view];
  809. }
  810. }
  811. if (self.videoListHidden) {
  812. [self.view bringSubviewToFront:self.showButton];
  813. [self.view bringSubviewToFront:self.toolView];
  814. }
  815. self.toolView.isVideoDisplay = NO;
  816. [self.view bringSubviewToFront:self.timeView];
  817. [self.view bringSubviewToFront:self.backWhiteButton];
  818. [self.view bringSubviewToFront:self.titleView];
  819. }
  820. - (void)refreshWhiteBoardFrame {
  821. [self.wBoardCtrl setWBoardFrame:[self getWBoardFrame]];
  822. }
  823. - (CGRect)getWBoardFrame {
  824. CGRect mainVideoFrame = CGRectZero;
  825. CGFloat width = 0;
  826. CGFloat height = 0;
  827. if (self.videoListHidden) {
  828. width = KLandscapeWidth;
  829. height = KLandscapeHeight;
  830. }
  831. else {
  832. width = KLandscapeWidth -(144 + 20 + 10);
  833. height = KLandscapeHeight;
  834. }
  835. mainVideoFrame.size.width = width;
  836. mainVideoFrame.size.height = height;
  837. mainVideoFrame.origin.x += 0;
  838. mainVideoFrame.origin.y = 0;
  839. return mainVideoFrame;
  840. }
  841. - (void)publishStream {
  842. if ([ClassroomService sharedService].currentRoom.currentMember.role != RoleAudience) {
  843. [TRTC_MANAGER publishStream];
  844. }
  845. }
  846. - (void)renderMainContainerView {
  847. if ([ClassroomService sharedService].currentRoom.currentDisplayType == DisplayTypeStudent) {
  848. // 有打开的屏幕
  849. for (RoomMember *displayMember in [ClassroomService sharedService].currentRoom.memberList) {
  850. if ([displayMember.userId isEqualToString:[ClassroomService sharedService].currentRoom.currentDisplayURI]) {
  851. [self.containerView refreshToolView];
  852. [self.wBoardCtrl hideBoard];
  853. [self.containerView containerViewRenderView:displayMember];
  854. [self.videoListView showTeacherPrompt:NO];
  855. break;
  856. }
  857. }
  858. } else if ([ClassroomService sharedService].currentRoom.currentDisplayType == DisplayTeacher) {
  859. NSLog(@"%@",[ClassroomService sharedService].currentRoom.currentDisplayURI);
  860. [self.wBoardCtrl hideBoard];
  861. [self.containerView containerViewRenderView:[ClassroomService sharedService].currentRoom.teacher];
  862. [self.videoListView showTeacherPrompt:YES];
  863. } else if ([ClassroomService sharedService].currentRoom.currentDisplayType == DisplayWhiteboard) {
  864. [self.containerView cancelRenderView];
  865. [self displayWhiteboard:[ClassroomService sharedService].currentRoom.currentDisplayURI];
  866. [self.videoListView showTeacherPrompt:NO];
  867. } else if (([ClassroomService sharedService].currentRoom.currentDisplayType == DisplaySharedScreen)) {
  868. [self.wBoardCtrl hideBoard];
  869. [TRTC_MANAGER renderRemoteUser:[ClassroomService sharedService].currentRoom.currentDisplayURI inView:self.containerView.videoView];
  870. // 分享视频
  871. [self.videoListView showTeacherPrompt:NO];
  872. } else {
  873. [self.wBoardCtrl hideBoard];
  874. [self.containerView cancelRenderView];
  875. [self.videoListView showTeacherPrompt:NO];
  876. }
  877. }
  878. #pragma mark ----- ClassVideoListViewDelegate
  879. - (void)videoListView:(TXClassroomVideoListView *)view didTap:(RoomMember *)member {
  880. if (![NSString isEmptyString:[ClassroomService sharedService].currentRoom.shareUserId]) {
  881. // 当前
  882. [self.tipsView showTipsMessage:@"当前有学生演示中" inView:self.view];
  883. return;
  884. }
  885. // 如果当前是展示白板
  886. if ([ClassroomService sharedService].currentRoom.currentDisplayType == DisplayWhiteboard) {
  887. [self showWhiteButton];
  888. }
  889. // 将视频投到主屏幕上
  890. NSString *currentDisplayUserId = member.userId;
  891. NSString *lastDisplayUserId = [ClassroomService sharedService].currentRoom.currentDisplayURI;
  892. if([currentDisplayUserId isEqualToString:lastDisplayUserId]) {
  893. [self.videoListView updateUserVideo:lastDisplayUserId];
  894. if(![[ClassroomService sharedService].currentRoom.currentMemberId isEqualToString:member.userId]) {
  895. // 记录当前演奏播放音频的学生
  896. if ([ClassroomService sharedService].currentRoom.isPlayBeat || [ClassroomService sharedService].currentRoom.isPlaySong) {
  897. [ClassroomService sharedService].currentRoom.currentPlayUserId = currentDisplayUserId;
  898. [TRTC_MANAGER unPlayRemoteStudentAudioStreamExcept:member.userId];
  899. }
  900. }
  901. return;
  902. }
  903. DisplayType type = member.role == RoleTeacher ? DisplayTeacher : DisplayTypeStudent;
  904. [ClassroomService sharedService].currentRoom.currentDisplayURI = currentDisplayUserId;
  905. [ClassroomService sharedService].currentRoom.currentDisplayType = type;
  906. [self.videoListView updateUserVideo:member.userId];
  907. if(![[ClassroomService sharedService].currentRoom.currentMemberId isEqualToString:member.userId]) {
  908. // 记录当前演奏播放音频的学生
  909. if ([ClassroomService sharedService].currentRoom.isPlayBeat || [ClassroomService sharedService].currentRoom.isPlaySong) {
  910. [ClassroomService sharedService].currentRoom.currentPlayUserId = currentDisplayUserId;
  911. [TRTC_MANAGER unPlayRemoteStudentAudioStreamExcept:member.userId];
  912. }
  913. }
  914. [self renderMainContainerView];
  915. }
  916. - (void)unplayBeatNodeRefreshStream {
  917. if ([ClassroomService sharedService].currentRoom.isPlayBeat == NO && [ClassroomService sharedService].currentRoom.isPlaySong == NO) { // 关闭节拍器后播放所有学生端声音
  918. [TRTC_MANAGER playAllRemoteStudentAudioStream];
  919. [ClassroomService sharedService].currentRoom.currentPlayUserId = nil;
  920. }
  921. }
  922. - (void)videoListView:(TXClassroomVideoListView *)view didHideView:(BOOL)isHideView {
  923. if (isHideView) { // 隐藏video list
  924. [self hideVideoList];
  925. }
  926. else { // 显示
  927. [self showVideoList];
  928. }
  929. }
  930. - (void)hideVideoList {
  931. self.videoListHidden = YES;
  932. CGRect frame = self.videoListView.frame;
  933. self.videoListView.frame = CGRectMake(KLandscapeWidth, frame.origin.y, frame.size.width, frame.size.height);
  934. [self.containerView changeVideoFrameFull:YES];
  935. [self refreshWhiteBoardFrame];
  936. [self.view addSubview:self.showButton];
  937. [self.view bringSubviewToFront:self.toolView];
  938. }
  939. - (void)showVideoList {
  940. self.videoListHidden = NO;
  941. CGRect frame = self.videoListView.frame;
  942. self.videoListView.frame = CGRectMake(KLandscapeWidth - frame.size.width, frame.origin.y, frame.size.width, frame.size.height);
  943. [self.containerView changeVideoFrameFull:NO];
  944. [self refreshWhiteBoardFrame];
  945. [self.showButton removeFromSuperview];
  946. }
  947. #pragma mark ---- ClassroomTimerManager delegate
  948. - (void)formatTime:(NSString *)timeString {
  949. self.timeView.timeLabel.text = timeString;
  950. }
  951. - (void)timeLabelAddAnimation:(CABasicAnimation *)animation {
  952. self.timeView.timeLabel.textColor = HexRGB(0x2DC7AA);
  953. [self.timeView.timeLabel.layer addAnimation:animation forKey:nil];
  954. }
  955. - (void)hiddenTitleView {
  956. self.titleView.isDisplay = NO;
  957. }
  958. - (void)quitClassroomNotifer {
  959. // 课程结束后15分钟自动退出房间 连堂课不退出(对内)
  960. if (self.isQuitRoom == NO) {
  961. self.isQuitRoom = YES;
  962. // 退出房间
  963. [self.tipsView showTipsMessage:@"课程已结束" inView:self.view];
  964. @weakObj(self);
  965. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  966. @strongObj(self);
  967. // 课程结束退出房间
  968. SealClassLog(@"ClassEnd!");
  969. [LOADING_MANAGER showCustomLoading:@"加载中..."];
  970. [[LoginHelper sharedInstance] logout];
  971. [self.titleView clearUnreadMessage];
  972. });
  973. }
  974. }
  975. #pragma mark --- whiteboard
  976. - (void)didTurnPage:(NSInteger)pageNum {
  977. }
  978. - (void)whiteboardViewDidChangeZoomScale:(float)scale {
  979. }
  980. - (void)needRefreshWhiteboardList {
  981. [self.whiteboardListView reloadDataSource];
  982. }
  983. - (void)needShowTopTitleView:(UIView *)touchView {
  984. if ([touchView isDescendantOfView:self.whiteboardListView]) {
  985. return;
  986. }
  987. self.titleView.isDisplay = YES;
  988. self.timeManager.isDisplay = YES;
  989. [self hidePersonListView];
  990. [self hideChatAreaView];
  991. [self.danView resetInputStatus];
  992. }
  993. // 白板连接状态回调
  994. - (void)connectionWhiteboardStatus:(JOINROOMSTATUS)status {
  995. if (status == JOINROOMSTATUS_FAILED) {
  996. [self.tipsView showTipsMessage:@"白板连接失败,请检查您的网络" inView:self.view];
  997. }
  998. else if (status == JOINROOMSTATUS_PARAMERROR) {
  999. [self.tipsView showTipsMessage:@"获取白板参数错误" inView:self.view];
  1000. }
  1001. }
  1002. #pragma mark ---- mainContainer
  1003. - (void)mainContainerOpertionMember:(RoomMember *)member tapButton:(UIButton *)button didTapAtTag:(MainToolButtonTag)tag {
  1004. RoomMember *curMember = [ClassroomService sharedService].currentRoom.currentMember;
  1005. // 操作自己
  1006. MainToolButton *toolButton = [self.containerView.toolView viewWithTag:tag+1000];
  1007. // 操作自己
  1008. if ([member.userId isEqualToString:curMember.userId]) {
  1009. switch (tag) {
  1010. case MainToolButtonTagMic: // 麦克风
  1011. {
  1012. if (toolButton.isSelected) { // 打开
  1013. [[ClassroomService sharedService] enableDevice:YES songId:@"" withType:DeviceTypeMicrophone];
  1014. }
  1015. else { // 关闭
  1016. [[ClassroomService sharedService] enableDevice:NO songId:@"" withType:DeviceTypeMicrophone];
  1017. }
  1018. }
  1019. break;
  1020. case MainToolButtonTagCamero: // 摄像头
  1021. {
  1022. if (toolButton.isSelected) { // 打开
  1023. [[ClassroomService sharedService] enableDevice:YES songId:@"" withType:DeviceTypeCamera];
  1024. }
  1025. else { // 关闭
  1026. [[ClassroomService sharedService] enableDevice:NO songId:@"" withType:DeviceTypeCamera];
  1027. }
  1028. }
  1029. break;
  1030. case MainToolButtonTagShare: // 老师无此状态操作
  1031. {
  1032. }
  1033. break;
  1034. case MainToolButtonTagPercent:
  1035. {
  1036. // [self showProgressView];
  1037. }
  1038. break;
  1039. default:
  1040. break;
  1041. }
  1042. }
  1043. else { // 操作学生
  1044. switch (tag) {
  1045. case MainToolButtonTagMic:
  1046. {
  1047. if (toolButton.isSelected) { // 打开
  1048. self.alertView = [TXClassRoomAlertView shareInstance];
  1049. [self.alertView configWithTitle:@"提示" desc:@"确认打开学生的麦克风吗?" leftTitle:@"取消" rightTitle:@"确认" cancel:^{
  1050. } confirm:^{
  1051. [[ClassroomService sharedService] enableDevice:YES type:DeviceTypeMicrophone songId:@"" soundVolume:0 forUser:member.userId];
  1052. }];
  1053. }
  1054. else { // 关闭
  1055. self.alertView = [TXClassRoomAlertView shareInstance];
  1056. [self.alertView configWithTitle:@"提示" desc:@"确认关闭学生的麦克风吗?" leftTitle:@"取消" rightTitle:@"确认" cancel:^{
  1057. } confirm:^{
  1058. [[ClassroomService sharedService] enableDevice:NO type:DeviceTypeMicrophone songId:@"" soundVolume:0 forUser:member.userId];
  1059. }];
  1060. }
  1061. }
  1062. break;
  1063. case MainToolButtonTagCamero:
  1064. {
  1065. if (toolButton.isSelected) { // 打开
  1066. self.alertView = [TXClassRoomAlertView shareInstance];
  1067. [self.alertView configWithTitle:@"提示" desc:@"邀请学生打开摄像头吗?" leftTitle:@"取消" rightTitle:@"确认" cancel:^{
  1068. } confirm:^{
  1069. [[ClassroomService sharedService] enableDevice:YES type:DeviceTypeCamera songId:@"" soundVolume:0 forUser:member.userId];
  1070. }];
  1071. }
  1072. else { // 关闭
  1073. self.alertView = [TXClassRoomAlertView shareInstance];
  1074. [self.alertView configWithTitle:@"提示" desc:@"确认关闭学生的摄像头吗?" leftTitle:@"取消" rightTitle:@"确认" cancel:^{
  1075. } confirm:^{
  1076. [[ClassroomService sharedService] enableDevice:NO type:DeviceTypeCamera songId:@"" soundVolume:0 forUser:member.userId];
  1077. }];
  1078. }
  1079. }
  1080. break;
  1081. case MainToolButtonTagShare:
  1082. {
  1083. if (toolButton.isSelected) { // 下台 显示老师
  1084. // 停止伴奏和节拍器
  1085. [self resetPlayBeatAndAccompany];
  1086. // 之前共享的学生切换成小流
  1087. [self exchangePreStudentToTinySteam];
  1088. [self.containerView refreshToolView];
  1089. [ClassroomService sharedService].currentRoom.currentDisplayType = DisplayTeacher;
  1090. [ClassroomService sharedService].currentRoom.currentDisplayURI = [ClassroomService sharedService].currentRoom.currentMember.userId;
  1091. [[ClassroomService sharedService] displayTeacher];
  1092. [self.containerView containerViewRenderView:[ClassroomService sharedService].currentRoom.currentMember];
  1093. [self.videoListView showTeacherPrompt:YES];
  1094. @weakObj(self);
  1095. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  1096. @strongObj(self);
  1097. [self renderMainContainerView];
  1098. });
  1099. }
  1100. else { // 上台共享学生
  1101. // 隐藏返回白板按钮
  1102. [self hideWhiteButton];
  1103. // 停止伴奏和节拍器
  1104. [self resetPlayBeatAndAccompany];
  1105. // 如果之前显示的白板 关闭掉
  1106. self.toolView.isVideoDisplay = YES;
  1107. [self.whiteboardListView removeFromSuperview];
  1108. [ClassroomService sharedService].currentRoom.shareUserId = member.userId;
  1109. [self.containerView refreshToolView];
  1110. [[ClassroomService sharedService] displayStudent:member.userId];
  1111. [self.containerView refreshShareStatus];
  1112. [self.videoListView showTeacherPrompt:NO];
  1113. if (member.handUpOn) {
  1114. [[ClassroomService sharedService] enableDevice:NO type:DeviceTypeHandup songId:@"" soundVolume:0 forUser:member.userId];
  1115. }
  1116. }
  1117. }
  1118. break;
  1119. case MainToolButtonTagPercent:
  1120. {
  1121. // [self showProgressView];
  1122. }
  1123. break;
  1124. default:
  1125. break;
  1126. }
  1127. }
  1128. }
  1129. - (void)resetPlayBeatAndAccompany {
  1130. if ([ClassroomService sharedService].currentRoom.isPlaySong) {
  1131. DeviceType type = self.isAccompany ? DeviceTypeAccompany : DeviceTypeMusicScore;
  1132. [[ClassroomService sharedService] enableMutilMemberDevice:NO type:type songId:self.songId soundVolume:self.soundVolume forUser:@""];
  1133. // 重置伴奏按钮
  1134. self.accompanyView.isPlaying = NO;
  1135. }
  1136. if ([ClassroomService sharedService].currentRoom.isPlayBeat) {
  1137. NSDictionary *parm = @{@"enable": @(NO),
  1138. @"rate" : @(0),
  1139. @"customType" : @(0),
  1140. @"playVolume" : @(0),
  1141. @"userId" : @"",
  1142. };
  1143. [[ClassroomService sharedService] enablePlayMessage:NO content:[parm mj_JSONString] userId:@""];
  1144. [ClassroomService sharedService].currentRoom.isPlayBeat = NO;
  1145. }
  1146. [self unplayBeatNodeRefreshStream]; // 刷新音频流播放
  1147. }
  1148. - (void)changeSongPlayDisplay:(NSString *)userId {
  1149. // 默认显示第一个学生的视频 单个操作不再次刷新主屏
  1150. if (self.videoListView.videoDataSource.count >= 1 && [NSString isEmptyString:userId]) {
  1151. for (RoomMember *member in self.videoListView.videoDataSource) {
  1152. if (member.role == RoleStudent) {
  1153. [self videoListView:nil didTap:member];
  1154. break;
  1155. }
  1156. }
  1157. }
  1158. else if (![NSString isEmptyString:userId]) {
  1159. [ClassroomService sharedService].currentRoom.currentPlayUserId = userId;
  1160. [TRTC_MANAGER unPlayRemoteStudentAudioStreamExcept:userId];
  1161. }
  1162. }
  1163. - (void)showProgressView {
  1164. [self.progressView showView:self.songName songId:self.songId];
  1165. }
  1166. - (void)exchangePreStudentToTinySteam {
  1167. [ClassroomService sharedService].currentRoom.shareUserId = @"";
  1168. }
  1169. #pragma mark ---- TXRTCServiceDelegate
  1170. - (void)didReportNetworkQuality:(TRTCQuality)quality remoteQuality:(NSArray<TRTCQualityInfo *> *)remoteQuality {
  1171. if (quality >= 5) { // 网络质量不佳
  1172. dispatch_async(dispatch_get_main_queue(), ^{
  1173. [self.view addSubview:self.networkLabel];
  1174. [self.view bringSubviewToFront:self.networkLabel];
  1175. self.networkLabel.hidden = NO;
  1176. self.networkLabel.text = @"当前通话连接质量不佳";
  1177. });
  1178. }
  1179. else { // 正常
  1180. dispatch_async(dispatch_get_main_queue(), ^{
  1181. self.networkLabel.hidden = YES;
  1182. self.networkLabel.text = @"";
  1183. [self.networkLabel removeFromSuperview];
  1184. });
  1185. }
  1186. [self showNetworkingStatus:quality remoteQuality:remoteQuality];
  1187. }
  1188. - (void)showNetworkingStatus:(TRTCQuality)quality remoteQuality:(NSArray<TRTCQualityInfo *> *)remoteQuality {
  1189. dispatch_async(dispatch_get_main_queue(), ^{
  1190. // 本地
  1191. NSString *currentUserID = [ClassroomService sharedService].currentRoom.currentMemberId;
  1192. if ([self.containerView.member.userId isEqualToString:currentUserID]) {
  1193. [self.containerView.displayView updateUserQualityNetWorkingStatus:[self getNetStatusWithQuality:quality]];
  1194. }
  1195. [self.videoListView updateUserQuality:currentUserID netWorkingStatus:[self getNetStatusWithQuality:quality]];
  1196. // 更新full
  1197. if (self.squareOn) {
  1198. [self.squareView updateUserQuality:currentUserID netWorkingStatus:[self getNetStatusWithQuality:quality]];
  1199. }
  1200. // 远端
  1201. for (TRTCQualityInfo *info in remoteQuality) {
  1202. NSString *userId = info.userId;
  1203. [self.videoListView updateUserQuality:userId netWorkingStatus:[self getNetStatusWithQuality:info.quality]];
  1204. if ([info.userId isEqualToString:self.containerView.member.userId]) {
  1205. [self.containerView.displayView updateUserQualityNetWorkingStatus:[self getNetStatusWithQuality:info.quality]];
  1206. }
  1207. // 更新full
  1208. if (self.squareOn) {
  1209. [self.squareView updateUserQuality:userId netWorkingStatus:[self getNetStatusWithQuality:info.quality]];
  1210. }
  1211. }
  1212. });
  1213. }
  1214. - (TXNetWorkingStatus)getNetStatusWithQuality:(TRTCQuality)quality {
  1215. TXNetWorkingStatus status = TXNetWorkingStatus_Full;
  1216. if (quality == 1 || quality == 2) {
  1217. status = TXNetWorkingStatus_Full;
  1218. }
  1219. else if (quality == 3) {
  1220. status = TXNetWorkingStatus_Good;
  1221. }
  1222. else if (quality == 4) {
  1223. status = TXNetWorkingStatus_Nomal;
  1224. }
  1225. else if (quality == 5) {
  1226. status = TXNetWorkingStatus_Bad;
  1227. }
  1228. else { //
  1229. status = TXNetWorkingStatus_Poor;
  1230. }
  1231. return status;
  1232. }
  1233. - (void)didReportUserVolume:(NSArray<TRTCVolumeInfo *> *)userVolumes {
  1234. NSString *currentUserID = [ClassroomService sharedService].currentRoom.currentMemberId;
  1235. for (TRTCVolumeInfo *info in userVolumes) {
  1236. NSString *userId = info.userId;
  1237. if ([NSString isEmptyString:userId]) {
  1238. userId = currentUserID;
  1239. }
  1240. [self.videoListView updateMicStatus:userId volume:info.volume];
  1241. // 更新title
  1242. if ([currentUserID isEqualToString:userId]) {
  1243. [self.titleView updateUserVolume:info.volume];
  1244. }
  1245. // 更新container
  1246. if ([self.containerView.member.userId isEqualToString:userId]) {
  1247. [self.containerView updateUserVolume:info.volume];
  1248. }
  1249. // 更新full
  1250. if (self.squareOn) {
  1251. [self.squareView updateMicStatus:userId volume:info.volume];
  1252. }
  1253. }
  1254. }
  1255. #pragma mark ------- 教学工具
  1256. - (TXTeachToolView *)toolView {
  1257. if (!_toolView) {
  1258. _toolView = [[TXTeachToolView alloc] init];
  1259. _toolView.delegate = self;
  1260. }
  1261. return _toolView;
  1262. }
  1263. - (AccompanyProgressView *)progressView {
  1264. if (!_progressView) {
  1265. _progressView = [[AccompanyProgressView alloc] initWithFrame:CGRectMake(0, 0, KLandscapeWidth, KLandscapeHeight)];
  1266. }
  1267. return _progressView;
  1268. }
  1269. - (void)hideDanView {
  1270. [self.titleView closeDanButton];
  1271. [self hideDanChatView];
  1272. }
  1273. - (void)teachToolView:(UIButton *)button didTapAtTag:(TeachToolTag)tag {
  1274. switch (tag) {
  1275. case TeachToolTagWhiteboard:
  1276. {
  1277. // 停止伴奏和节拍器
  1278. [self resetPlayBeatAndAccompany];
  1279. [LOADING_MANAGER showCustomLoading:@"加载中..."];
  1280. @weakObj(self);
  1281. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  1282. @strongObj(self);
  1283. [LOADING_MANAGER removeCustomLoading];
  1284. button.selected = YES;
  1285. self.toolView.isVideoDisplay = NO;
  1286. if ([ClassroomService sharedService].currentRoom.randomNumeric == 0) {
  1287. [self.view addSubview:self.whiteboardListView];
  1288. }
  1289. self.whiteboardListView.isOpen = NO;
  1290. // 之前共享的学生切换成小流
  1291. [self exchangePreStudentToTinySteam];
  1292. [TRTC_MANAGER cancleRenderUserVideo:[ClassroomService sharedService].currentRoom.currentDisplayURI];
  1293. [ClassroomService sharedService].currentRoom.currentDisplayType = DisplayWhiteboard;
  1294. [ClassroomService sharedService].currentRoom.currentDisplayURI = @"whiteboard";
  1295. [[ClassroomService sharedService] displayWhiteboard:@"whiteboard"];
  1296. [self renderMainContainerView];
  1297. [self.videoListView showTeacherPrompt:NO];
  1298. [self.whiteboardListView reloadDataSource];
  1299. // 收起
  1300. [self.toolView hiddenToolViewWithAnimation:YES];
  1301. [self hideDanView];
  1302. });
  1303. }
  1304. break;
  1305. case TeachToolTagVideo:
  1306. {
  1307. [self hideWhiteButton];
  1308. // 停止伴奏和节拍器
  1309. [self resetPlayBeatAndAccompany];
  1310. button.selected = YES;
  1311. self.toolView.isVideoDisplay = YES;
  1312. // 收起
  1313. [self.toolView hiddenToolViewWithAnimation:YES];
  1314. // 之前共享的学生切换成小流
  1315. [self exchangePreStudentToTinySteam];
  1316. [ClassroomService sharedService].currentRoom.currentDisplayType = DisplayTeacher;
  1317. [ClassroomService sharedService].currentRoom.currentDisplayURI = [ClassroomService sharedService].currentRoom.currentMember.userId;
  1318. [[ClassroomService sharedService] displayTeacher];
  1319. [self.containerView containerViewRenderView:[ClassroomService sharedService].currentRoom.currentMember];
  1320. [self.videoListView showTeacherPrompt:YES];
  1321. @weakObj(self);
  1322. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  1323. @strongObj(self);
  1324. [self renderMainContainerView];
  1325. });
  1326. [self.whiteboardListView removeFromSuperview];
  1327. }
  1328. break;
  1329. case TeachToolTagLibrary: // 选择伴奏曲库
  1330. {
  1331. [self.accompanyView showAccompanyView];
  1332. }
  1333. break;
  1334. case TeachToolTagNode:
  1335. {
  1336. [self showNodeControlView];
  1337. }
  1338. break;
  1339. default:
  1340. break;
  1341. }
  1342. }
  1343. #pragma mark - Getters & setters
  1344. - (ClassroomTimerManager *)timeManager {
  1345. if (!_timeManager) {
  1346. _timeManager = [[ClassroomTimerManager alloc] initWithDelegate:self];
  1347. _timeManager.autoClose = [ClassroomService sharedService].currentRoom.autoCloseFlag;
  1348. // 统一15分钟关闭
  1349. _timeManager.autoCloseNetworkRoomTime = [ClassroomService sharedService].currentRoom.autoCloseNetworkRoomTime;
  1350. }
  1351. return _timeManager;
  1352. }
  1353. - (TXTimeView *)timeView {
  1354. if (!_timeView) {
  1355. _timeView = [TXTimeView shareInstance];
  1356. }
  1357. return _timeView;
  1358. }
  1359. - (KSTipsView *)tipsView {
  1360. if (!_tipsView) {
  1361. _tipsView = [[KSTipsView alloc] initWithFrame:CGRectZero];
  1362. }
  1363. return _tipsView;
  1364. }
  1365. - (TXClassTitleView *)titleView {
  1366. if (!_titleView) {
  1367. _titleView = [[TXClassTitleView alloc] initWithFrame:CGRectMake(0, 0, KLandscapeWidth, TitleViewHeight)];
  1368. _titleView.delegate = self;
  1369. }
  1370. return _titleView;
  1371. }
  1372. - (TXClassroomVideoListView *)videoListView {
  1373. if(!_videoListView) {
  1374. CGFloat width = VIDEO_WIDTH + 20 + 10;
  1375. CGFloat height = KLandscapeHeight;
  1376. _videoListView = [[TXClassroomVideoListView alloc] initWithFrame:CGRectMake(KLandscapeWidth - width, 0, width, height)];
  1377. _videoListView.delegate = self;
  1378. }
  1379. return _videoListView;
  1380. }
  1381. - (UIButton *)showButton {
  1382. if (!_showButton) {
  1383. _showButton = [UIButton buttonWithType:UIButtonTypeCustom];
  1384. _showButton.frame = CGRectMake(KLandscapeWidth-30, (KLandscapeHeight-30)/2.0, 30, 30);
  1385. [_showButton setImage:[UIImage imageNamed:@"videoList_show"] forState:UIControlStateNormal];
  1386. [_showButton addTarget:self action:@selector(showVideoList) forControlEvents:UIControlEventTouchUpInside];
  1387. }
  1388. return _showButton;
  1389. }
  1390. - (ClassMemberListView *)memberListView {
  1391. if (!_memberListView) {
  1392. _memberListView = [[ClassMemberListView alloc] initWithFrame:CGRectMake(KLandscapeWidth - PersonListViewWidth, 0, PersonListViewWidth, KLandscapeHeight)];
  1393. _memberListView.delegate = self;
  1394. }
  1395. return _memberListView;
  1396. }
  1397. - (TXClassroomMainContainer *)containerView {
  1398. if (!_containerView) {
  1399. _containerView = [[TXClassroomMainContainer alloc] initWithFrame:[self mainContainerViewFrame]];
  1400. _containerView.delegate = self;
  1401. }
  1402. return _containerView;
  1403. }
  1404. - (TXChatAreaView *)chatAreaView {
  1405. if(!_chatAreaView) {
  1406. _chatAreaView = [[TXChatAreaView alloc] initWithFrame:CGRectMake(KLandscapeWidth- 300,0, 300, KLandscapeHeight) chatGroupId:[ClassroomService sharedService].currentRoom.roomId];
  1407. }
  1408. return _chatAreaView;
  1409. }
  1410. - (KSWhiteboardControl *)wBoardCtrl {
  1411. if (!_wBoardCtrl) {
  1412. CGRect frame = [self getWBoardFrame];
  1413. _wBoardCtrl = [[KSWhiteboardControl alloc] initWithDelegate:self viewFrame:frame];
  1414. NSLog(@"----%@", [ClassroomService sharedService].currentRoom.roomId);
  1415. _wBoardCtrl.randomNumeric = [ClassroomService sharedService].currentRoom.randomNumeric;
  1416. NSString *roomId = [ClassroomService sharedService].currentRoom.roomId;
  1417. if ([roomId containsString:@"S"] || [roomId containsString:@"I"]) {
  1418. roomId = [roomId substringFromIndex:1];
  1419. }
  1420. _wBoardCtrl.roomId = roomId;
  1421. _wBoardCtrl.subjectId = self.subjectId;
  1422. [_wBoardCtrl moveToSuperView:self.view];
  1423. }
  1424. return _wBoardCtrl;
  1425. }
  1426. - (WhiteboardListView *)whiteboardListView {
  1427. if (!_whiteboardListView) {
  1428. _whiteboardListView = [[WhiteboardListView alloc] initWithFrame:CGRectMake(-140+iPhoneXSafeTopMargin, 0, WhiteboardListWidth, KLandscapeHeight)];
  1429. _whiteboardListView.delegate = self;
  1430. _whiteboardListView.whiteboardCtrl = self.wBoardCtrl;
  1431. }
  1432. return _whiteboardListView;
  1433. }
  1434. - (TXFullVideoView *)squareView {
  1435. if (!_squareView) {
  1436. _squareView = [[TXFullVideoView alloc] initWithFrame:CGRectMake(0, 0, KLandscapeWidth, KLandscapeHeight)];
  1437. _squareView.delegate = self;
  1438. }
  1439. return _squareView;
  1440. }
  1441. #pragma mark ----- 宫格模式
  1442. // 点击视频
  1443. - (void)fullVideoListView:(TXFullVideoView *)view didTap:(RoomMember *)member {
  1444. // 放大当前视频
  1445. if([[ClassroomService sharedService].currentRoom.currentMemberId isEqualToString:member.userId]) {
  1446. [TRTC_MANAGER renderLocalUserInView:self.maskView.maskVideoView isCameraEnable:member.cameraEnable];
  1447. }else {
  1448. [TRTC_MANAGER renderRemoteUser:member.userId inView:self.maskView.maskVideoView];
  1449. if ([ClassroomService sharedService].currentRoom.isPlayBeat || [ClassroomService sharedService].currentRoom.isPlaySong) {
  1450. [TRTC_MANAGER unPlayRemoteStudentAudioStreamExcept:member.userId];
  1451. [ClassroomService sharedService].currentRoom.currentPlayUserId = member.userId;
  1452. }
  1453. }
  1454. [self.maskView configUserAvatar:member.headUrl];
  1455. if (member.cameraEnable) {
  1456. self.maskView.closeCameraView.hidden = YES;
  1457. }
  1458. else {
  1459. self.maskView.closeCameraView.hidden = NO;
  1460. }
  1461. [self.view addSubview:self.maskView];
  1462. }
  1463. // 关闭宫格模式
  1464. - (void)cancleFullVideoList {
  1465. self.squareOn = NO;
  1466. [self.squareView removeFromSuperview];
  1467. if ([ClassroomService sharedService].currentRoom.isPlayBeat || [ClassroomService sharedService].currentRoom.isPlaySong) {
  1468. [ClassroomService sharedService].currentRoom.currentPlayUserId = self.squareView.currentPlayUserId;
  1469. NSString *userId = [ClassroomService sharedService].currentRoom.currentPlayUserId;
  1470. [TRTC_MANAGER unPlayRemoteStudentAudioStreamExcept:userId];
  1471. }
  1472. [self renderMainContainerView];
  1473. [self.videoListView reloadVideoList];
  1474. }
  1475. - (VideoMaskView *)maskView {
  1476. if (!_maskView) {
  1477. CGFloat width = (KLandscapeWidth);
  1478. CGRect frame = CGRectMake(0, 0, width, KLandscapeHeight);
  1479. _maskView = [[VideoMaskView alloc] initWithFrame:frame];
  1480. [_maskView addDismisTarget:self action:@selector(dismissMaskViewEvent)];
  1481. }
  1482. return _maskView;
  1483. }
  1484. - (void)dismissMaskViewEvent {
  1485. // 切换成小流
  1486. [self removeMaskViewIfNeed];
  1487. [self.squareView showVideoList];
  1488. self.squareView.displayUserId = @"";
  1489. }
  1490. - (void)removeMaskViewIfNeed {
  1491. [self.maskView removeFromSuperview];
  1492. _maskView = nil;
  1493. }
  1494. #pragma mark --------- 主动关闭教室
  1495. - (void)showCouseCloseAlert {
  1496. // 判断如果课程结束、不能进行此操作
  1497. if (self.timeManager.showCloseTips) {
  1498. [self.tipsView showTipsMessage:@"已结束课程不可使用该功能" inView:self.view];
  1499. return;
  1500. }
  1501. self.closeCourseAlert = [KSCloseCourseView shareInstanceShowInView:self.view];
  1502. self.imageArray = [NSMutableArray array];
  1503. self.imageAsset = [NSMutableArray array];
  1504. [self createImageButtonAndPhotosButton];
  1505. MJWeakSelf;
  1506. [self.closeCourseAlert sureCallback:^(NSString * _Nonnull message) {
  1507. [weakSelf submitCloseMessge:message];
  1508. }];
  1509. [self.closeCourseAlert showAlert];
  1510. }
  1511. /**
  1512. 图片和按钮的布局
  1513. */
  1514. #pragma marl 图片和按钮布局
  1515. - (void)createImageButtonAndPhotosButton {
  1516. for (UIView *subView in self.closeCourseAlert.imageContentView.subviews) {
  1517. [subView removeFromSuperview];
  1518. }
  1519. if (self.imageArray.count == 0) {
  1520. self.closeCourseAlert.hasChooseImage = NO;
  1521. }
  1522. else {
  1523. self.closeCourseAlert.hasChooseImage = YES;
  1524. }
  1525. CGFloat space = 10;
  1526. CGFloat buttonWidth = (COURSEVIEWWIDTH - KBUTTON_LEFTSPACE * 2 - space * 2) / 3.0f;
  1527. CGFloat buttonHeight = 80;
  1528. NSInteger section = self.imageArray.count/3 + 1;
  1529. if (self.imageArray.count==MAXPHOTONUMBER) {
  1530. section = MAXPHOTONUMBER / 3;
  1531. }
  1532. CGFloat currentX = 0;
  1533. CGFloat currentY = 0;
  1534. for (NSInteger i = 0; i < self.imageArray.count; i++) {
  1535. currentX = i % 3 * (buttonWidth + space);
  1536. currentY = i / 3 * (buttonHeight + space);
  1537. UIImage *image = self.imageArray [i];
  1538. CGRect frame = CGRectMake(currentX, currentY, buttonWidth, buttonHeight);
  1539. MJWeakSelf;
  1540. KSImageDisplayView *displayView = [KSImageDisplayView shareInstance];
  1541. displayView.frame = frame;
  1542. displayView.tag = 1000 + i;
  1543. [displayView displayImage:image callback:^(IMAGEACTION action, NSInteger viewIndex) {
  1544. if (action == IMAGEACTION_DISPLAY) {
  1545. [weakSelf displayImageIndex:viewIndex];
  1546. }
  1547. else {
  1548. [weakSelf deleteImage:viewIndex];
  1549. }
  1550. }];
  1551. [self.closeCourseAlert.imageContentView addSubview:displayView];
  1552. }
  1553. currentX = self.imageArray .count % 3 * (buttonWidth + space);
  1554. if (self.imageArray.count != MAXPHOTONUMBER) {
  1555. //计算下一个添加按钮位置
  1556. if (self.imageArray.count % 3 == 0) {
  1557. currentY = (self.imageArray.count+1) / 3 * (buttonHeight + space);
  1558. }
  1559. UIButton *cameraButton = [UIButton buttonWithType:UIButtonTypeCustom];
  1560. cameraButton.frame = CGRectMake(currentX, currentY, buttonWidth, buttonHeight);
  1561. cameraButton.layer.cornerRadius = 5.0f;
  1562. [cameraButton setImage:[UIImage imageNamed:@"common_image_choose"] forState:UIControlStateNormal];
  1563. [cameraButton setBackgroundColor:[UIColor clearColor]];
  1564. [cameraButton addTarget:self action:@selector(addImgAction:) forControlEvents:UIControlEventTouchUpInside];
  1565. [self.closeCourseAlert.imageContentView addSubview:cameraButton];
  1566. }
  1567. }
  1568. - (void)displayImageIndex:(NSInteger)fileIndex {
  1569. self.isPushChooseView = YES;
  1570. // 展示大图
  1571. LLPhotoBrowser *photoBrowser = [[LLPhotoBrowser alloc] initWithImages:self.imageArray currentIndex:fileIndex];
  1572. photoBrowser.delegate = self;
  1573. photoBrowser.modalPresentationStyle = UIModalPresentationFullScreen;
  1574. [self presentViewController:photoBrowser animated:YES completion:nil];
  1575. }
  1576. - (void)deleteImage:(NSInteger)fileIndex {
  1577. [self.imageArray removeObjectAtIndex:fileIndex];
  1578. [self.imageAsset removeObjectAtIndex:fileIndex];
  1579. [self createImageButtonAndPhotosButton];
  1580. }
  1581. #pragma mark 点击+按钮
  1582. - (void)addImgAction:(UIButton *)sender {
  1583. [self.view endEditing:YES];
  1584. UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:IS_IPAD ? UIAlertControllerStyleAlert : UIAlertControllerStyleActionSheet];
  1585. [alertVC addAction:[UIAlertAction actionWithTitle:@"相机拍摄" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  1586. // 调用相机
  1587. self.isPushChooseView = YES;
  1588. [self takePhotos];
  1589. }]];
  1590. [alertVC addAction:[UIAlertAction actionWithTitle:@"从手机相册选择" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  1591. // 调用相册
  1592. self.isPushChooseView = YES;
  1593. [self pushImagePickerController];
  1594. }]];
  1595. [alertVC addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
  1596. }]];
  1597. alertVC.modalPresentationStyle = UIModalPresentationFullScreen;
  1598. [self presentViewController:alertVC animated:true completion:nil];
  1599. }
  1600. - (void)takePhotos {
  1601. // 调用相册
  1602. self.mediaManager = [[KSMediaManager alloc] init];
  1603. self.mediaManager.mediaType = MEDIATYPE_PHOTO;
  1604. self.mediaManager.maxPhotoNumber = MAXPHOTONUMBER;
  1605. self.mediaManager.baseCtrl = self;
  1606. self.mediaManager.imageArray = [self.imageArray mutableCopy];
  1607. self.mediaManager.imageAsset = [self.imageAsset mutableCopy];
  1608. self.mediaManager.needCropImage = NO;
  1609. MJWeakSelf;
  1610. [self.mediaManager noAlertCallback:^(NSString * _Nullable videoUrl, NSMutableArray * _Nullable imageArray, NSMutableArray * _Nullable imageAsset) {
  1611. [weakSelf displayChooseImage:imageArray imageAsset:imageAsset];
  1612. }];
  1613. [self.mediaManager takePhoto];
  1614. }
  1615. - (void)pushImagePickerController {
  1616. // 调用相册
  1617. self.mediaManager = [[KSMediaManager alloc] init];
  1618. self.mediaManager.mediaType = MEDIATYPE_PHOTO;
  1619. self.mediaManager.maxPhotoNumber = MAXPHOTONUMBER;
  1620. self.mediaManager.baseCtrl = self;
  1621. self.mediaManager.imageArray = [self.imageArray mutableCopy];
  1622. self.mediaManager.imageAsset = [self.imageAsset mutableCopy];
  1623. self.mediaManager.needCropImage = NO;
  1624. MJWeakSelf;
  1625. [self.mediaManager noAlertCallback:^(NSString * _Nullable videoUrl, NSMutableArray * _Nullable imageArray, NSMutableArray * _Nullable imageAsset) {
  1626. [weakSelf displayChooseImage:imageArray imageAsset:imageAsset];
  1627. }];
  1628. [self.mediaManager pushImagePickerController];
  1629. }
  1630. - (void)displayChooseImage:(NSMutableArray *)imageArray imageAsset:(NSMutableArray *)imageAsset {
  1631. self.imageArray = [imageArray mutableCopy];
  1632. self.imageAsset = [imageAsset mutableCopy];
  1633. // 重新布局
  1634. [self createImageButtonAndPhotosButton];
  1635. }
  1636. #pragma mark -- LLPhotoBrowserDelegate
  1637. - (void)photoBrowser:(LLPhotoBrowser *)photoBrowser backImages:(NSMutableArray *)images {
  1638. NSMutableArray * backImgArray = [images mutableCopy];
  1639. NSMutableArray *imageArray = [NSMutableArray array];
  1640. NSMutableArray *imageAsset = [NSMutableArray array];
  1641. for (NSInteger i = 0; i < self.imageArray.count; i++) {
  1642. UIImage *imagePic = self.imageArray[i];
  1643. if ([backImgArray containsObject:imagePic]) { // 包含
  1644. [imageArray addObject:imagePic];
  1645. [imageAsset addObject:self.imageAsset[i]];
  1646. }
  1647. }
  1648. self.imageArray = [imageArray mutableCopy];
  1649. self.imageAsset = [imageAsset mutableCopy];
  1650. //布局
  1651. [self createImageButtonAndPhotosButton];
  1652. }
  1653. - (void)submitCloseMessge:(NSString *)message {
  1654. [LOADING_MANAGER showCustomLoading:@"加载中..."];
  1655. // 先上传图片
  1656. NSMutableArray *imageDataArray = [NSMutableArray array];
  1657. for (UIImage *image in self.imageArray) {
  1658. NSData *imgData = [UIImage turnsImaegDataByImage:image];
  1659. [imageDataArray addObject:imgData];
  1660. }
  1661. [UPLOAD_MANAGER configWithfilePath:@"/classroom/"];
  1662. [UPLOAD_MANAGER mutilUploadImage:imageDataArray fileName:@"onlineClassroomImg" successCallback:^(NSMutableArray * _Nonnull fileUrlArray) {
  1663. NSMutableArray *urlArray = [NSMutableArray array];
  1664. for (NSString *url in fileUrlArray) {
  1665. [urlArray addObject:url];
  1666. }
  1667. // 再提交申诉
  1668. NSString *attachments = [urlArray componentsJoinedByString:@","];
  1669. [self feedbackAction:attachments message:message];
  1670. } faliure:^(NSError * _Nullable error, NSString * _Nullable descMessaeg) {
  1671. [LOADING_MANAGER removeCustomLoading];
  1672. if (![NSString isEmptyString:descMessaeg]) {
  1673. [self.tipsView showTipsMessage:descMessaeg inView:self.view];
  1674. }
  1675. }];
  1676. }
  1677. - (void)feedbackAction:(NSString *)attachments message:(NSString *)message {
  1678. }
  1679. - (void)dealloc {
  1680. NSLog(@"----- class room dealloc----");
  1681. [[NSNotificationCenter defaultCenter] removeObserver:self];
  1682. }
  1683. #pragma mark ----- accompany view
  1684. - (AccompanyView *)accompanyView {
  1685. if (!_accompanyView) {
  1686. _accompanyView = [[AccompanyView alloc] initWithFrame:CGRectMake(0, 0, KLandscapeWidth, KLandscapeHeight)];
  1687. _accompanyView.volume = self.soundVolume;
  1688. _accompanyView.hideDownloadStatus = YES;
  1689. MJWeakSelf;
  1690. [_accompanyView accompanyPlayAction:^(ACCOMPANYACTION action, NSString * _Nullable songId, NSString * _Nullable songName, BOOL isAccompany, NSString * _Nullable songUrl) {
  1691. [weakSelf accompanyViewAction:action songId:songId songName:songName isAccompany:isAccompany songUrl:songUrl];
  1692. }];
  1693. }
  1694. return _accompanyView;
  1695. }
  1696. - (void)accompanyViewAction:(ACCOMPANYACTION)action songId:(NSString *)songId songName:(NSString *)songName isAccompany:(BOOL)isAccompany songUrl:(NSString *)songUrl {
  1697. NSLog(@"------------- song id %@", songId);
  1698. self.soundVolume = self.accompanyView.volume;
  1699. NSLog(@"-------sound volume %zd", self.soundVolume);
  1700. if (action == ACCOMPANYACTION_ADDSONG) {
  1701. // 添加伴奏
  1702. [self.coursewareView showView];
  1703. }
  1704. else if (action == ACCOMPANYACTION_STOP) {
  1705. DeviceType type = self.isAccompany ? DeviceTypeAccompany : DeviceTypeMusicScore;
  1706. // 取消记录当前播放曲目
  1707. [[ClassroomService sharedService] enableMutilMemberDevice:NO type:type songId:songId soundVolume:self.soundVolume forUser:@""];
  1708. [ClassroomService sharedService].currentRoom.isPlaySong = NO;
  1709. [self unplayBeatNodeRefreshStream]; // 刷新音频流播放
  1710. }
  1711. else if (action == ACCOMPANYACTION_PLAYSONG) {
  1712. // 如果之前有播放节拍器
  1713. [ClassroomService sharedService].currentRoom.isPlaySong = YES;
  1714. if ([ClassroomService sharedService].currentRoom.isPlayBeat) {
  1715. [ClassroomService sharedService].currentRoom.isPlayBeat = NO;
  1716. NSDictionary *parm = @{@"enable": @(NO),
  1717. @"rate" : @(0),
  1718. @"customType" : @(0),
  1719. @"playVolume" : @(0),
  1720. @"userId" : @"",
  1721. };
  1722. [[ClassroomService sharedService] enablePlayMessage:NO content:[parm mj_JSONString] userId:@""];
  1723. }
  1724. DeviceType type = isAccompany ? DeviceTypeAccompany : DeviceTypeMusicScore;
  1725. // 记录当前播放曲目
  1726. if (![NSString isEmptyString:[ClassroomService sharedService].currentRoom.shareUserId]) {
  1727. NSString *userId = [ClassroomService sharedService].currentRoom.shareUserId;
  1728. [[ClassroomService sharedService] enableMutilMemberDevice:YES type:type songId:songId soundVolume:self.soundVolume forUser:userId];
  1729. [self changeSongPlayDisplay:userId];
  1730. }
  1731. else {
  1732. [[ClassroomService sharedService] enableMutilMemberDevice:YES type:type songId:songId soundVolume:self.soundVolume forUser:@""];
  1733. [self changeSongPlayDisplay:@""];
  1734. }
  1735. [ClassroomService sharedService].currentRoom.isPlaySong = YES;
  1736. // 同步主屏显示
  1737. [self recordSongMessageWithSongId:songId songName:songName isAccompany:isAccompany songUrl:songUrl];
  1738. }
  1739. else if (action == ACCOMPANYACTION_DISPLAY) { // 显示弹窗
  1740. // [self.progressView showView:songName songId:songId];
  1741. }
  1742. else if (action == ACCOMPANYACTION_CHOOSE) { // 选择的伴奏
  1743. [self recordSongMessageWithSongId:songId songName:songName isAccompany:isAccompany songUrl:songUrl];
  1744. }
  1745. else if (action == ACCOMPANYACTION_MODIFY_VOLUME) {
  1746. // TXAudioEffectManager *audioManager = [TRTCCloud sharedInstance].getAudioEffectManager;
  1747. // [audioManager setAllMusicVolume:self.soundVolume];
  1748. }
  1749. }
  1750. - (void)notiferStudentDownload:(NSString *)songId songUrl:(NSString *)songUrl accompanyUrl:(NSString *)accompanyUrl songName:(NSString *)songName {
  1751. [self.coursewareView hideView];
  1752. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  1753. for (RoomMember *member in [ClassroomService sharedService].currentRoom.memberList) {
  1754. if (member.songMessage.count == 0) { // 如果没有选择过曲目
  1755. self.songName = songName;
  1756. self.songId = songId;
  1757. if ([NSString isEmptyString:songUrl]) {
  1758. self.isAccompany = YES;
  1759. self.songUrl = accompanyUrl;
  1760. }
  1761. else {
  1762. self.isAccompany = NO;
  1763. self.songUrl = songUrl;
  1764. }
  1765. member.accompanimentPlayStatus = NO;
  1766. member.downStatus = 0;
  1767. member.playStatus = NO;
  1768. member.url = songUrl;
  1769. member.mp3Url = accompanyUrl;
  1770. member.examSongName = songName;
  1771. member.musicScoreAccompanimentId = songId;
  1772. ClassSongMessage *songModel = [[ClassSongMessage alloc] init];
  1773. songModel.musicScoreAccompanimentId = songId;
  1774. songModel.accompanimentPlayStatus = NO;
  1775. songModel.downStatus = 0;
  1776. songModel.playStatus = NO;
  1777. songModel.url = songUrl;
  1778. songModel.mp3Url = accompanyUrl;
  1779. songModel.examSongName = songName;
  1780. [member.songMessage addObject:songModel];
  1781. }
  1782. else {
  1783. BOOL hasDownloadSong = NO;
  1784. for (ClassSongMessage *songModel in member.songMessage) {
  1785. if ([songModel.musicScoreAccompanimentId isEqualToString:songId]) {
  1786. hasDownloadSong = YES;
  1787. break;
  1788. }
  1789. }
  1790. if (hasDownloadSong == NO) { // 如果没有下载 添加到列表
  1791. ClassSongMessage *songModel = [[ClassSongMessage alloc] init];
  1792. songModel.musicScoreAccompanimentId = songId;
  1793. songModel.accompanimentPlayStatus = NO;
  1794. songModel.downStatus = 0;
  1795. songModel.playStatus = NO;
  1796. songModel.url = songUrl;
  1797. songModel.mp3Url = accompanyUrl;
  1798. songModel.examSongName = songName;
  1799. [member.songMessage addObject:songModel];
  1800. }
  1801. }
  1802. }
  1803. dispatch_main_async_safe(^{
  1804. // 刷新选择窗
  1805. [self.accompanyView refreshView];
  1806. if (![NSString isEmptyString:self.songName]) {
  1807. [self.containerView.toolView showDownloadButtonWithSongName:self.songName isAccompany:self.isAccompany]; // 弹出 当前曲目的下载状态框
  1808. }
  1809. // 通知
  1810. [[ClassroomService sharedService] pushDownloadMusicScoreMsgWithSongId:songId];
  1811. });
  1812. });
  1813. }
  1814. - (void)recordSongMessageWithSongId:(NSString *)songId songName:(NSString *)songName isAccompany:(BOOL)isAccompany songUrl:(NSString *)songUrl {
  1815. self.songId = songId;
  1816. self.songUrl = songUrl;
  1817. self.songName = songName;
  1818. self.isAccompany = isAccompany;
  1819. [self.containerView.toolView showDownloadButtonWithSongName:songName isAccompany:isAccompany]; // 弹出 当前曲目的下载状态框
  1820. }
  1821. #pragma mark ----- 首页弹幕聊天
  1822. - (TXDanMuView *)danView {
  1823. if (!_danView) {
  1824. _danView = [[TXDanMuView alloc] initWithFrame:CGRectMake(38, KLandscapeHeight - 160 - 20, 260, 160) chatGroupId:[ClassroomService sharedService].currentRoom.roomId];
  1825. }
  1826. return _danView;
  1827. }
  1828. - (CoursewareAlertView *)coursewareView {
  1829. if (!_coursewareView) {
  1830. _coursewareView = [CoursewareAlertView shareInstance];
  1831. [_coursewareView configUI];
  1832. MJWeakSelf;
  1833. [_coursewareView chooseCoursewareCallback:^(NSString * _Nonnull url, NSString * _Nonnull musicUrl, NSString * _Nonnull musicName, NSString * _Nonnull songId) {
  1834. [weakSelf notiferStudentDownload:songId songUrl:url accompanyUrl:musicUrl songName:musicName];
  1835. }];
  1836. }
  1837. return _coursewareView;
  1838. }
  1839. - (UIButton *)backWhiteButton {
  1840. if (!_backWhiteButton) {
  1841. _backWhiteButton = [UIButton buttonWithType:UIButtonTypeCustom];
  1842. _backWhiteButton.backgroundColor = HexRGB(0xFE5219);
  1843. [_backWhiteButton setTitle:@"返回白板" forState:UIControlStateNormal];
  1844. [_backWhiteButton.titleLabel setFont:[UIFont systemFontOfSize:14.0f weight:UIFontWeightMedium]];
  1845. _backWhiteButton.layer.cornerRadius = 4;
  1846. [_backWhiteButton addTarget:self action:@selector(backWhiteboardView) forControlEvents:UIControlEventTouchUpInside];
  1847. }
  1848. return _backWhiteButton;
  1849. }
  1850. - (void)backWhiteboardView {
  1851. [self hideDanView];
  1852. [ClassroomService sharedService].currentRoom.currentDisplayType = DisplayWhiteboard;
  1853. [ClassroomService sharedService].currentRoom.currentDisplayURI = @"whiteboard";
  1854. [self renderMainContainerView];
  1855. [self hideWhiteButton];
  1856. }
  1857. - (void)hideWhiteButton {
  1858. self.backWhiteButton.hidden = YES;
  1859. }
  1860. - (void)showWhiteButton {
  1861. self.backWhiteButton.hidden = NO;
  1862. }
  1863. /*
  1864. #pragma mark - Navigation
  1865. // In a storyboard-based application, you will often want to do a little preparation before navigation
  1866. - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
  1867. // Get the new view controller using [segue destinationViewController].
  1868. // Pass the selected object to the new view controller.
  1869. }
  1870. */
  1871. @end