Commit 009cf00df190ae47e21695b202bb86ee682ba403

Authored by 吴启风
1 parent 8df5fbf9

feat:环节&单元解锁逻辑

.gitignore
@@ -68,6 +68,7 @@ @@ -68,6 +68,7 @@
68 **/ios/xcode_build_ipa_adh 68 **/ios/xcode_build_ipa_adh
69 **/ios/xcode_build_ipa_aps 69 **/ios/xcode_build_ipa_aps
70 **/ios/xcode_build_ipa_dev 70 **/ios/xcode_build_ipa_dev
  71 +**/ios/build/
71 72
72 # Exceptions to above rules. 73 # Exceptions to above rules.
73 !**/ios/**/default.mode1v3 74 !**/ios/**/default.mode1v3
lib/pages/section/bloc/section_bloc.dart
@@ -200,7 +200,7 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { @@ -200,7 +200,7 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> {
200 final curCourseSectionEntity = findCourseSectionById(courseLessonId); 200 final curCourseSectionEntity = findCourseSectionById(courseLessonId);
201 if (curCourseSectionEntity != null) { 201 if (curCourseSectionEntity != null) {
202 final curCourseUnitDetail = _courseUnitEntity.courseUnitVOList 202 final curCourseUnitDetail = _courseUnitEntity.courseUnitVOList
203 - ?.firstWhere( 203 + ?.firstWhereOrNull(
204 (element) => element.id == curCourseSectionEntity.courseUnitId); 204 (element) => element.id == curCourseSectionEntity.courseUnitId);
205 return curCourseUnitDetail; 205 return curCourseUnitDetail;
206 } 206 }
@@ -213,39 +213,86 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { @@ -213,39 +213,86 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> {
213 final curCourseSectionEntity = findCourseSectionById(courseLessonId); 213 final curCourseSectionEntity = findCourseSectionById(courseLessonId);
214 final curSectionSort = curCourseSectionEntity?.sortOrder ?? 0; 214 final curSectionSort = curCourseSectionEntity?.sortOrder ?? 0;
215 215
216 - ///查找下一个section  
217 - final nextCourseSectionEntity = findCourseSectionBySort(curSectionSort + 1);  
218 - if (nextCourseSectionEntity != null) {  
219 - return nextCourseSectionEntity; 216 + try {
  217 + ///查找当前unit的下一个section
  218 + CourseSectionEntity? nextCourseSectionEntity =
  219 + findCourseSectionBySort(curSectionSort + 1);
  220 + return checkCourseSectionLocked(courseLessonId, nextCourseSectionEntity, emitter);
  221 + } catch (e) {
  222 + if (e is ApiException) {
  223 + showToast(e.message.toString());
  224 + }
  225 + return null;
  226 + }
  227 + }
  228 +
  229 + ///检查section是否锁定
  230 + Future<CourseSectionEntity?> checkCourseSectionLocked(int courseLessonId, CourseSectionEntity? courseSectionEntity,
  231 + Emitter<SectionState> emitter) async {
  232 + if (courseSectionEntity != null) {
  233 + if (courseSectionEntity.lock == false) {
  234 + ///如果section没锁,直接返回
  235 + return courseSectionEntity;
  236 + } else {
  237 + ///如果section锁了,请求当前unit下的section数据,查询解锁状态
  238 + int courseUnitId = courseSectionEntity.courseUnitId;
  239 + await loading(() async {
  240 + List<CourseSectionEntity>? tempSectionEntities =
  241 + await LessonDao.courseSection(courseUnitId: courseUnitId);
  242 + if (tempSectionEntities != null) {
  243 + _courseSectionDatasMap[courseUnitId] = tempSectionEntities;
  244 + emitter(LessonDataLoadState());
  245 + }
  246 + courseSectionEntity = tempSectionEntities?.firstWhereOrNull(
  247 + (element) => element.id == courseSectionEntity?.id);
  248 + if (courseSectionEntity?.lock == false) {
  249 + ///刷新后的数据如果解锁了,直接返回
  250 + return courseSectionEntity;
  251 + } else {
  252 + ///请求失败或者锁定状态没变(没变就感觉状态异常了,理论上不应该进入这条分支),返回null
  253 + showToast('下个课程还没解锁哦');
  254 + return null;
  255 + }
  256 + });
  257 + }
220 } else { 258 } else {
221 - ///section为空说明当前unit学完了,找下一个unit。(跨unit选lesson) 259 + ///section为空说明当前unit学完了,找下一个unit。(跨unit选section)
222 ///先根据courseLessonId找出当前的unit 260 ///先根据courseLessonId找出当前的unit
223 final curCourseUnitDetail = findCourseUnitDetailById(courseLessonId); 261 final curCourseUnitDetail = findCourseUnitDetailById(courseLessonId);
224 if (curCourseUnitDetail != null) { 262 if (curCourseUnitDetail != null) {
225 - ///再根据当前unit找出下一个unit  
226 - final nextCourseUnitDetail = _courseUnitEntity.courseUnitVOList  
227 - ?.firstWhere((element) =>  
228 - element.sortOrder == (curCourseUnitDetail.sortOrder! + 1)); 263 + ///再根据当前unit的sortOrder找出下一个unit
  264 + CourseUnitDetail? nextCourseUnitDetail =
  265 + _courseUnitEntity.courseUnitVOList?.firstWhereOrNull((element) =>
  266 + element.sortOrder == (curCourseUnitDetail.sortOrder! + 1));
  267 +
229 if (nextCourseUnitDetail != null) { 268 if (nextCourseUnitDetail != null) {
230 - final courseUnitId = nextCourseUnitDetail.id!;  
231 - try { 269 + if (nextCourseUnitDetail.lock == true) {
  270 + ///如果下一个unit是锁定状态,请求数据刷新查询解锁状态
232 await loading(() async { 271 await loading(() async {
233 - _courseSectionDatasMap[courseUnitId] =  
234 - await LessonDao.courseSection(courseUnitId: courseUnitId);  
235 - emitter(LessonDataLoadState()); 272 + CourseUnitEntity? newCourseUnitEntity = await LessonDao.courseUnit(
  273 + _courseUnitEntity.nowCourseModuleId);
  274 +
  275 + ///拿到重新获取到的unit后,再次判断是否解锁
  276 + nextCourseUnitDetail = newCourseUnitEntity?.courseUnitVOList?.firstWhereOrNull(
  277 + (element) => element.id == nextCourseUnitDetail?.id);
  278 + if (nextCourseUnitDetail?.lock == false) {
  279 + ///解锁状态从锁定到解锁,覆盖原unit数据并刷新ui
  280 + _courseUnitEntity = newCourseUnitEntity!;
  281 + emitter(LessonDataLoadState());
  282 +
  283 + return checkCourseSectionLockedOfNextUnit(courseLessonId, nextCourseUnitDetail!.id!, emitter);
  284 + } else {
  285 + showToast('下个单元课程还没解锁哦');
  286 +
  287 + ///如果还是锁定状态,返回null
  288 + return null;
  289 + }
236 }); 290 });
237 - _pageController.nextPage(  
238 - duration: const Duration(milliseconds: 500),  
239 - curve: Curves.ease,  
240 - );  
241 - return _courseSectionDatasMap[courseUnitId]!.first;  
242 - } catch (e) {  
243 - if (e is ApiException) {  
244 - showToast(e.message.toString());  
245 - }  
246 - return null; 291 + } else {
  292 + return checkCourseSectionLockedOfNextUnit(courseLessonId, nextCourseUnitDetail.id!, emitter);
247 } 293 }
248 } else { 294 } else {
  295 + showToast("恭喜你,本阶段学到顶啦");
249 ///最后一个unit了 296 ///最后一个unit了
250 return null; 297 return null;
251 } 298 }
@@ -254,5 +301,45 @@ class SectionBloc extends Bloc&lt;SectionEvent, SectionState&gt; { @@ -254,5 +301,45 @@ class SectionBloc extends Bloc&lt;SectionEvent, SectionState&gt; {
254 return null; 301 return null;
255 } 302 }
256 } 303 }
  304 + return null;
  305 + }
  306 +
  307 + ///检查下一个unit的(第一个)section
  308 + Future<CourseSectionEntity?> checkCourseSectionLockedOfNextUnit(int courseLessonId, int nextCourseUnitDetailId,
  309 + Emitter<SectionState> emitter) async {
  310 + CourseSectionEntity? firstSectionNextUnit = await getFirstSectionByUnitId(
  311 + nextCourseUnitDetailId, emitter);
  312 + if (firstSectionNextUnit != null) {
  313 + ///下个unit的第一个section如果不为空,再次检查是否锁定
  314 + CourseSectionEntity? courseSectionEntity = await checkCourseSectionLocked(courseLessonId, firstSectionNextUnit, emitter);
  315 + if (courseSectionEntity != null) {
  316 + ///只有是下一unit的第一个section并且解锁了,才跳转
  317 + _pageController.nextPage(
  318 + duration: const Duration(milliseconds: 250),
  319 + curve: Curves.ease,
  320 + );
  321 + }
  322 + return courseSectionEntity;
  323 + } else {
  324 + ///下个unit的第一个section如果为空,返回null
  325 + showToast('下个课程暂未找到');
  326 + return null;
  327 + }
  328 + }
  329 +
  330 + ///根据unitId获取当前unit的第一个section
  331 + Future<CourseSectionEntity?> getFirstSectionByUnitId(
  332 + int courseUnitId, Emitter<SectionState> emitter) async {
  333 + List<CourseSectionEntity>? courseSectionEntity =
  334 + _courseSectionDatasMap[courseUnitId];
  335 + if (courseSectionEntity == null) {
  336 + ///如果没下载过,请求数据
  337 + await loading(() async {
  338 + _courseSectionDatasMap[courseUnitId] =
  339 + await LessonDao.courseSection(courseUnitId: courseUnitId);
  340 + emitter(LessonDataLoadState());
  341 + });
  342 + }
  343 + return _courseSectionDatasMap[courseUnitId]?.first;
257 } 344 }
258 } 345 }
lib/pages/unit/bloc.dart
@@ -23,10 +23,10 @@ class UnitBloc extends Bloc&lt;UnitEvent, UnitState&gt; { @@ -23,10 +23,10 @@ class UnitBloc extends Bloc&lt;UnitEvent, UnitState&gt; {
23 23
24 24
25 UnitBloc(CourseModuleEntity? courseEntity) : super(UnitState().init()) { 25 UnitBloc(CourseModuleEntity? courseEntity) : super(UnitState().init()) {
26 - on<RequestUnitDataEvent>(_requestData); 26 + on<RequestUnitDataEvent>(_requestUnitDatas);
27 } 27 }
28 28
29 - void _requestData(RequestUnitDataEvent event, Emitter<UnitState> emitter) async { 29 + void _requestUnitDatas(RequestUnitDataEvent event, Emitter<UnitState> emitter) async {
30 try { 30 try {
31 await loading(() async { 31 await loading(() async {
32 _unitData = await LessonDao.courseUnit(event.moduleId); 32 _unitData = await LessonDao.courseUnit(event.moduleId);
lib/pages/unit/view.dart
@@ -57,7 +57,7 @@ class UnitPage extends StatelessWidget { @@ -57,7 +57,7 @@ class UnitPage extends StatelessWidget {
57 return GestureDetector( 57 return GestureDetector(
58 onTap: () { 58 onTap: () {
59 if (data.lock == true) { 59 if (data.lock == true) {
60 - showToast('当前课程暂未解锁'); 60 + showToast('当前单元课程暂未解锁');
61 return; 61 return;
62 } 62 }
63 63
lib/utils/list_ext.dart
@@ -8,4 +8,14 @@ extension ListExtension&lt;E&gt; on List&lt;E&gt; { @@ -8,4 +8,14 @@ extension ListExtension&lt;E&gt; on List&lt;E&gt; {
8 } 8 }
9 return null; 9 return null;
10 } 10 }
  11 +
  12 + /// 获取数组中第一个匹配元素,没有就返回null
  13 + E? firstWhereOrNull(bool Function(E element) test) {
  14 + for (E element in this) {
  15 + if (test(element)) {
  16 + return element;
  17 + }
  18 + }
  19 + return null;
  20 + }
11 } 21 }