// // RQExerciseModule.m // SDJK // // Created by 张嵘 on 2021/8/12. // #import "RQExerciseModule.h" /// 刷新TableView NSString * const RQRefreshExerciseTableViewNotification = @"RQRefreshExerciseTableViewNotification"; /// 答题结果 NSString * const RQAnswerResultsNotification = @"RQAnswerResultsNotification"; /// 答题页面更新 NSString * const RQQuestionReloadNotification = @"RQQuestionReloadNotification"; /// 答题结果 key NSString * const RQAnswerResultsKey = @"RQAnswerResultsKey"; /// 练习模式Key NSString * const RQExerciseTypeKey = @"RQExerciseTypeKey"; /// 页面操作类型Key NSString * const RQExerciseDoTypeKey = @"RQExerciseDoTypeKey"; /// 答题页面更新ExerciseModelKey NSString * const RQQuestionReloadExerciseModelKey = @"RQQuestionReloadExerciseModelKey"; /// 收藏成功通知 NSString * const RQAddCollectNotification = @"RQAddCollectNotification"; /// 取消收藏成功通知 NSString * const RQCancelCollectNotification = @"RQCancelCollectNotification"; /// 取消收藏题目Key NSString * const RQCancelCollectExerciseModelKey = @"RQCancelCollectExerciseModelKey"; @interface RQExerciseModule () @property (nonatomic, readwrite, strong) SCLAlertView *alert; @property (nonatomic, readwrite, strong) UITextView *messageTextView; @property (nonatomic, readwrite, strong) SCLButton *rePlayButton; @property (nonatomic, readwrite, strong) SCLButton *closeButton; @property (nonatomic, readwrite, assign) BOOL isShow; @end @implementation RQExerciseModule static id rq_RQExerciseModule = nil; #pragma mark - init + (instancetype)sharedInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ rq_RQExerciseModule = [[self alloc] init]; }); return rq_RQExerciseModule; } - (instancetype)init { if (self = [super init]) { self.exerciseDoType = RQExerciseDoType_Default; self.isRightAutoJumpToNext = [RQ_SDJK_DB_MANAGER getRightAutoJumpToNext]; self.isExerciseSound = [RQ_SDJK_DB_MANAGER getExerciseSound]; self.exerciseFontSize = [RQ_SDJK_DB_MANAGER getExerciseFontSize]; } return self; } #pragma mark - PublicMethods - (void)rq_RACIsAutoRead { [[[RACSignal combineLatest:@[RACObserve(RQ_Exercise_Module, isAutoRead),RACObserve(RQ_Exercise_Module, currrentExerciseModel)] reduce:^(id isAutoRead, RQExerciseModel *exerciseModel){ if (RQ_Exercise_Module.isAutoRead && !exerciseModel.isAuto) { return exerciseModel; } else if (RQ_Exercise_Module.isAutoRead && exerciseModel.isAuto) { [RQ_MUSIC_MANAGER rq_cancelStreamer]; [RQNotificationCenter postNotificationName:RQQuestionReloadNotification object:@{RQQuestionReloadExerciseModelKey : exerciseModel}]; RQExerciseModel *exerciseModel = nil; return exerciseModel; } else { exerciseModel.isAuto = NO; RQExerciseModel *exerciseModel = nil; return exerciseModel; } }] deliverOnMainThread] subscribeNext:^(RQExerciseModel *exerciseModel) { if (exerciseModel) { exerciseModel.isAuto = YES; NSLog(@"1.读题目---%@---%@",exerciseModel.issue,exerciseModel.issuemp3); [RQ_MUSIC_MANAGER rq_resetStreamerWithURLString:exerciseModel.issuemp3 DOUAudioStreamerStatusBlock:^(DOUAudioStreamerStatus status) { if (status == DOUAudioStreamerFinished) { NSLog(@"2.读技巧---%@---%@",exerciseModel.issue,exerciseModel.explain_mp3); [RQ_Exercise_Module rq_showSkillExplanationAlertWithMessage:exerciseModel.explain_jq skillkeyword:exerciseModel.skillkeyword explainGifUrl:exerciseModel.explain_gif mp3Url:exerciseModel.explain_mp3 completeBlock:^{ NSLog(@"3.结束---自动读题模式下: 当前题目正在自动读题 即将自动跳到下一题"); exerciseModel.isShowSkillExplanation = YES; exerciseModel.isAuto = NO; // self.currrentExerciseModel = exerciseModel; [RQNotificationCenter postNotificationName:RQQuestionReloadNotification object:@{RQQuestionReloadExerciseModelKey : exerciseModel}]; }]; exerciseModel.userAnswer = exerciseModel.answer; // self.currrentExerciseModel = exerciseModel; [RQNotificationCenter postNotificationName:RQQuestionReloadNotification object:@{RQQuestionReloadExerciseModelKey : exerciseModel}]; } }]; } }]; // [[RACObserve(RQ_Exercise_Module, isAutoRead) takeUntil:self.rac_willDeallocSignal] subscribeNext:^(id _Nullable x) { // if (RQ_Exercise_Module.isAutoRead) { // self.currrentExerciseModel.isAuto = YES; // NSLog(@"1.读题目---%@---%@",self.currrentExerciseModel.issue,self.currrentExerciseModel.issuemp3); // [RQ_MUSIC_MANAGER rq_resetStreamerWithURLString:self.currrentExerciseModel.issuemp3 DOUAudioStreamerStatusBlock:^(DOUAudioStreamerStatus status) { // if (status == DOUAudioStreamerFinished) { // NSLog(@"2.读技巧---%@---%@",self.currrentExerciseModel.issue,self.currrentExerciseModel.explain_mp3); // [RQ_Exercise_Module rq_showSkillExplanationAlertWithMessage:self.currrentExerciseModel.explain_jq skillkeyword:self.currrentExerciseModel.skillkeyword explainGifUrl:self.currrentExerciseModel.explain_gif mp3Url:self.currrentExerciseModel.explain_mp3 completeBlock:^{ // NSLog(@"3.结束---%@\r\n -%@\r\n -%@\r\n -%@\r\n -%@",self.currrentExerciseModel.issue,self.currrentExerciseModel.issuemp3,self.currrentExerciseModel.answermp3,self.currrentExerciseModel.explain_mp3,self.currrentExerciseModel.explainjsmp3); // self.currrentExerciseModel.isShowSkillExplanation = YES; // self.currrentExerciseModel.isAuto = NO; // self.currrentExerciseModel = self.currrentExerciseModel; // [RQNotificationCenter postNotificationName:RQQuestionReloadNotification object:nil]; // }]; // self.currrentExerciseModel.userAnswer = self.currrentExerciseModel.answer; // self.currrentExerciseModel = self.currrentExerciseModel; // [RQNotificationCenter postNotificationName:RQQuestionReloadNotification object:nil]; // } // }]; // } else { // [RQ_MUSIC_MANAGER rq_cancelStreamer]; // [RQNotificationCenter postNotificationName:RQQuestionReloadNotification object:nil]; // } // }]; } - (void)cancleAutoReadQuestion { [RQ_MUSIC_MANAGER rq_cancelStreamer]; RQ_Exercise_Module.isAutoRead = NO; } - (void)rq_showOfficialInterpretationAlertWithMessage:(NSString *)messageStr mp3Url:(NSString *)mp3Url { SCLAlertView *alert = [[SCLAlertView alloc] initWithNewWindowWidth:RQ_SCREEN_WIDTH - 80.f]; @weakify(alert) CGFloat viewTextWideth = RQ_SCREEN_WIDTH - (20 * 2) - (40 * 2); CGFloat textHeight = [messageStr heightForFont:[UIFont systemFontOfSize:16] width:viewTextWideth] > RQ_SCREEN_HEIGHT / 2.f? RQ_SCREEN_HEIGHT / 2.f : [messageStr heightForFont:[UIFont systemFontOfSize:16] width:viewTextWideth]; [alert removeTopCircle]; alert.tintTopCircle = NO; alert.useLargerIcon = NO; alert.iconTintColor = RQ_MAIN_COLOR; alert.cornerRadius = 10; alert.labelTitle.textColor = RQ_MAIN_TEXT_COLOR_1; alert.labelTitle.font = [UIFont boldSystemFontOfSize:20]; [alert.labelTitle mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_offset(20); make.centerX.mas_offset(0); make.size.mas_equalTo(CGSizeMake(viewTextWideth, 21.f)); }]; UITextView *messageTextView = [[UITextView alloc] initWithFrame:CGRectMake(20, alert.labelTitle.rq_y + alert.labelTitle.rq_height, viewTextWideth, textHeight)]; messageTextView.font = [UIFont systemFontOfSize:self.exerciseFontSize]; messageTextView.editable = NO; messageTextView.textColor = RQ_MAIN_TEXT_COLOR_3; messageTextView.textAlignment = NSTextAlignmentLeft; messageTextView.text = messageStr; [alert addCustomView:messageTextView]; [messageTextView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(alert.labelTitle.mas_bottom).mas_offset(20); make.centerX.mas_offset(0); make.size.mas_equalTo(CGSizeMake(viewTextWideth, textHeight)).priority(500); }]; SCLButton *closeButton = [alert addButton:@"关闭" actionBlock:^{ @strongify(alert); [alert hideView]; [RQ_MUSIC_MANAGER rq_cancelStreamer]; }]; closeButton.buttonFormatBlock = ^NSDictionary* (void) { NSMutableDictionary *buttonConfig = [[NSMutableDictionary alloc] init]; buttonConfig[@"cornerRadius"] = @"20.f"; buttonConfig[@"backgroundColor"] = RQ_MAIN_BACKGROUNDCOLOR; buttonConfig[@"textColor"] = RQ_MAIN_TEXT_COLOR_3; buttonConfig[@"borderWidth"] = @1.0f; buttonConfig[@"borderColor"] = RQ_MAIN_TEXT_COLOR_3; buttonConfig[@"font"] = [UIFont systemFontOfSize:16]; return buttonConfig; }; [closeButton mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(messageTextView.mas_bottom).mas_offset(20); make.left.mas_equalTo(messageTextView.mas_left); make.bottom.mas_offset(-20); make.size.mas_equalTo(CGSizeMake((viewTextWideth - 16) / 2.f, 40.f)); }]; SCLButton *rePlayButton = [alert addButton:@"语音重播" validationBlock:^BOOL{ [RQ_MUSIC_MANAGER rq_resetStreamerWithURLString:mp3Url]; return NO; } actionBlock:nil]; rePlayButton.buttonFormatBlock = ^NSDictionary* (void) { NSMutableDictionary *buttonConfig = [[NSMutableDictionary alloc] init]; buttonConfig[@"cornerRadius"] = @"20.f"; buttonConfig[@"backgroundColor"] = RQ_MAIN_COLOR; buttonConfig[@"textColor"] = RQ_MAIN_TEXT_COLOR_WHITE; buttonConfig[@"font"] = [UIFont systemFontOfSize:16]; return buttonConfig; }; [rePlayButton mas_makeConstraints:^(MASConstraintMaker *make) { make.right.mas_equalTo(messageTextView.mas_right); make.bottom.mas_offset(-20); make.size.mas_equalTo(CGSizeMake((viewTextWideth - 16) / 2.f, 40.f)); }]; alert.horizontalButtons = YES; alert.showAnimationType = SCLAlertViewShowAnimationFadeIn; [alert showTitle:@"官方解释" subTitle:nil style:SCLAlertViewStyleCustom closeButtonTitle:nil duration:0.f]; [RQ_MUSIC_MANAGER rq_resetStreamerWithURLString:mp3Url]; } - (void)rq_showSkillExplanationAlertWithMessage:(NSString *)messageStr skillkeyword:(NSString *)skillkeyword explainGifUrl:(NSString *)explainGifUrl mp3Url:(NSString *)mp3Url completeBlock:(void(^__nullable)(void))completeBlock { if (_isShow) { return; } self.messageTextView = nil; self.alert = [[SCLAlertView alloc] initWithNewWindowWidth:RQ_SCREEN_WIDTH - 80.f]; [_alert removeTopCircle]; _alert.tintTopCircle = NO; _alert.useLargerIcon = NO; _alert.iconTintColor = RQ_MAIN_COLOR; _alert.cornerRadius = 10; _alert.horizontalButtons = YES; _alert.showAnimationType = SCLAlertViewShowAnimationFadeIn; _alert.labelTitle.textColor = RQ_MAIN_TEXT_COLOR_1; _alert.labelTitle.font = [UIFont boldSystemFontOfSize:20]; CGFloat viewTextWideth = RQ_SCREEN_WIDTH - (20 * 2) - (40 * 2); CGFloat textHeight = [messageStr heightForFont:[UIFont systemFontOfSize:self.exerciseFontSize] width:viewTextWideth] > RQ_SCREEN_HEIGHT / 2.f? RQ_SCREEN_HEIGHT / 2.f : [messageStr heightForFont:[UIFont systemFontOfSize:self.exerciseFontSize] width:viewTextWideth]; [self.alert.labelTitle mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_offset(20); make.centerX.mas_offset(0); make.size.mas_equalTo(CGSizeMake(viewTextWideth, 21.f)); }]; UIImageView *gifImageView = [[UIImageView alloc] initWithFrame:CGRectMake(_alert.labelTitle.rq_x, _alert.labelTitle.rq_y + _alert.labelTitle.rq_height, viewTextWideth, viewTextWideth * 0.5)]; [gifImageView yy_setImageWithURL:[NSURL URLWithString:explainGifUrl] placeholder:RQWebImagePlaceholder() options:RQWebImageOptionAutomatic completion:^(UIImage * _Nullable image, NSURL * _Nonnull url, YYWebImageFromType from, YYWebImageStage stage, NSError * _Nullable error) { if ([url.path containsString:@".gif"]) { image = [UIImage qmui_animatedImageWithData:[NSData dataWithContentsOfURL:url]]; } gifImageView.image = image; }]; if (RQStringIsNotEmpty(explainGifUrl) && gifImageView.image) { [_alert addCustomView:gifImageView]; [gifImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(_alert.labelTitle.mas_bottom).mas_offset(20); make.centerX.mas_offset(0); make.size.mas_equalTo(CGSizeMake(viewTextWideth, viewTextWideth * 0.5)); }]; } if (RQStringIsNotEmpty(messageStr)) { UILabel *textViewTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(_alert.labelTitle.rq_x, (RQStringIsNotEmpty(explainGifUrl) && gifImageView.image)? gifImageView.rq_y + gifImageView.rq_height : _alert.labelTitle.rq_y + _alert.labelTitle.rq_height, 100, 18)]; textViewTitleLabel.text = @"本题速记口诀"; textViewTitleLabel.textColor = RQ_MAIN_TEXT_COLOR_1; textViewTitleLabel.font = [UIFont systemFontOfSize:16]; textViewTitleLabel.textAlignment = NSTextAlignmentCenter; [_alert addCustomView:textViewTitleLabel]; [textViewTitleLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo((RQStringIsNotEmpty(explainGifUrl) && gifImageView.image)? gifImageView.mas_bottom : _alert.labelTitle.mas_bottom).mas_offset(20); make.centerX.mas_offset(0); make.size.mas_equalTo(CGSizeMake(100, 18)); }]; UIImageView *leftLineImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 20, 1)]; leftLineImageView.backgroundColor = RQ_MAIN_TEXT_COLOR_5; [_alert addCustomView:leftLineImageView]; [leftLineImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.centerY.mas_equalTo(textViewTitleLabel); make.right.mas_equalTo(textViewTitleLabel.mas_left).mas_offset(- 5); make.size.mas_equalTo(CGSizeMake(20, 1)); }]; UIImageView *rightLineImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 20, 1)]; rightLineImageView.backgroundColor = RQ_MAIN_TEXT_COLOR_5; [_alert addCustomView:rightLineImageView]; [rightLineImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.centerY.mas_equalTo(textViewTitleLabel); make.left.mas_equalTo(textViewTitleLabel.mas_right).mas_offset(5); make.size.mas_equalTo(CGSizeMake(20, 1)); }]; self.messageTextView = [[UITextView alloc] initWithFrame:CGRectMake(_alert.labelTitle.rq_x, textViewTitleLabel.rq_y + textViewTitleLabel.rq_height, viewTextWideth, textHeight)]; self.messageTextView.font = [UIFont systemFontOfSize:self.exerciseFontSize]; self.messageTextView.editable = NO; self.messageTextView.textColor = RQ_MAIN_TEXT_COLOR_3; self.messageTextView.textAlignment = NSTextAlignmentLeft; [_alert addCustomView:self.messageTextView]; if (RQStringIsNotEmpty(skillkeyword)) { NSMutableAttributedString *abs = [[NSMutableAttributedString alloc] initWithString:messageStr? : @""]; NSArray *skillArr = [skillkeyword componentsSeparatedByString:@"-"]; __block NSRange lastRange = NSMakeRange(0, 0); [[skillArr.rac_sequence.signal deliverOnMainThread] subscribeNext:^(NSString * _Nullable skillkeywordStr) { NSInteger index = [skillArr indexOfObject:skillkeywordStr]; NSRange targetRange = NSMakeRange(0, messageStr.length); NSRange skillRange = targetRange; // while (true) { // if (skillRange.location != NSNotFound) { // // } else { // break; // } // } skillRange = [messageStr rangeOfString:skillkeywordStr options:NSLiteralSearch range:targetRange]; if (skillRange.location > messageStr.length || skillRange.length == 0) { if (lastRange.length != 0) { NSRange frontRange = NSMakeRange(NSMaxRange(lastRange), messageStr.length - NSMaxRange(lastRange)); [abs addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:self.exerciseFontSize] range:frontRange]; } else { [abs addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:self.exerciseFontSize] range:targetRange]; } return; } NSRange frontRange = NSMakeRange(0, skillRange.location); if (lastRange.length != 0) { if (skillRange.location > skillRange.location - NSMaxRange(lastRange)) { frontRange = NSMakeRange(NSMaxRange(lastRange), skillRange.location - NSMaxRange(lastRange)); } } [abs addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:self.exerciseFontSize] range:frontRange]; [abs addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:self.exerciseFontSize + 1] range:skillRange]; [abs addAttribute:NSForegroundColorAttributeName value:RQ_MAIN_TEXT_COLOR_RED range:skillRange]; lastRange = skillRange; if (index + 1 == skillArr.count) { NSRange backRange = NSMakeRange(NSMaxRange(skillRange), messageStr.length - NSMaxRange(skillRange)); [abs addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:self.exerciseFontSize] range:backRange]; } } completed:^{ self.messageTextView.attributedText = abs; }]; } else { self.messageTextView.text = messageStr; } [self.messageTextView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(textViewTitleLabel.mas_bottom).mas_offset(15); make.centerX.mas_offset(0); make.size.mas_equalTo(CGSizeMake(viewTextWideth, textHeight)).priority(500); }]; } @weakify(self) self.closeButton = [self.alert addButton:@"关闭" actionBlock:^{ @strongify(self); if (RQ_Exercise_Module.isAutoRead) { completeBlock? completeBlock() : nil; } [self.alert hideView]; _isShow = NO; [RQ_Exercise_Module cancleAutoReadQuestion]; }]; self.closeButton.buttonFormatBlock = ^NSDictionary* (void) { NSMutableDictionary *buttonConfig = [[NSMutableDictionary alloc] init]; buttonConfig[@"cornerRadius"] = @"20.f"; buttonConfig[@"backgroundColor"] = RQ_MAIN_BACKGROUNDCOLOR; buttonConfig[@"textColor"] = RQ_MAIN_TEXT_COLOR_3; buttonConfig[@"borderWidth"] = @1.0f; buttonConfig[@"borderColor"] = RQ_MAIN_TEXT_COLOR_3; buttonConfig[@"font"] = [UIFont systemFontOfSize:16]; return buttonConfig; }; [self.closeButton mas_makeConstraints:^(MASConstraintMaker *make) { if (self.messageTextView) { make.top.mas_equalTo(self.messageTextView.mas_bottom).mas_offset(20); } else { make.top.mas_equalTo((RQStringIsNotEmpty(explainGifUrl) && gifImageView.image)? gifImageView.mas_bottom : _alert.labelTitle.mas_bottom).mas_offset(20); } make.left.mas_equalTo(_alert.labelTitle.mas_left); make.bottom.mas_offset(-20); make.size.mas_equalTo(CGSizeMake((viewTextWideth - 16) / 2.f, 40.f)); }]; self.rePlayButton = [self.alert addButton:@"语音重播" validationBlock:^BOOL{ [RQ_MUSIC_MANAGER rq_resetStreamerWithURLString:mp3Url]; return NO; } actionBlock:nil]; self.rePlayButton.buttonFormatBlock = ^NSDictionary* (void) { NSMutableDictionary *buttonConfig = [[NSMutableDictionary alloc] init]; buttonConfig[@"cornerRadius"] = @"20.f"; buttonConfig[@"backgroundColor"] = RQ_MAIN_COLOR; buttonConfig[@"textColor"] = RQ_MAIN_TEXT_COLOR_WHITE; buttonConfig[@"font"] = [UIFont systemFontOfSize:16]; return buttonConfig; }; [self.rePlayButton mas_makeConstraints:^(MASConstraintMaker *make) { make.right.mas_equalTo(_alert.labelTitle.mas_right); make.bottom.mas_offset(-20); make.size.mas_equalTo(CGSizeMake((viewTextWideth - 16) / 2.f, 40.f)); }]; [_alert showTitle:@"技巧讲解" subTitle:nil style:SCLAlertViewStyleCustom closeButtonTitle:nil duration:0.f]; _isShow = YES; if (RQ_Exercise_Module.isAutoRead) { [RQ_MUSIC_MANAGER rq_resetStreamerWithURLString:mp3Url DOUAudioStreamerStatusBlock:^(DOUAudioStreamerStatus status) { if (status == DOUAudioStreamerFinished) { completeBlock(); [_alert hideView]; _isShow = NO; } }]; } else { [RQ_MUSIC_MANAGER rq_resetStreamerWithURLString:mp3Url]; } } @end