Commit 009cf00df190ae47e21695b202bb86ee682ba403
1 parent
8df5fbf9
feat:环节&单元解锁逻辑
Showing
5 changed files
with
126 additions
and
28 deletions
.gitignore
lib/pages/section/bloc/section_bloc.dart
| ... | ... | @@ -200,7 +200,7 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { |
| 200 | 200 | final curCourseSectionEntity = findCourseSectionById(courseLessonId); |
| 201 | 201 | if (curCourseSectionEntity != null) { |
| 202 | 202 | final curCourseUnitDetail = _courseUnitEntity.courseUnitVOList |
| 203 | - ?.firstWhere( | |
| 203 | + ?.firstWhereOrNull( | |
| 204 | 204 | (element) => element.id == curCourseSectionEntity.courseUnitId); |
| 205 | 205 | return curCourseUnitDetail; |
| 206 | 206 | } |
| ... | ... | @@ -213,39 +213,86 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { |
| 213 | 213 | final curCourseSectionEntity = findCourseSectionById(courseLessonId); |
| 214 | 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 | 258 | } else { |
| 221 | - ///section为空说明当前unit学完了,找下一个unit。(跨unit选lesson) | |
| 259 | + ///section为空说明当前unit学完了,找下一个unit。(跨unit选section) | |
| 222 | 260 | ///先根据courseLessonId找出当前的unit |
| 223 | 261 | final curCourseUnitDetail = findCourseUnitDetailById(courseLessonId); |
| 224 | 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 | 268 | if (nextCourseUnitDetail != null) { |
| 230 | - final courseUnitId = nextCourseUnitDetail.id!; | |
| 231 | - try { | |
| 269 | + if (nextCourseUnitDetail.lock == true) { | |
| 270 | + ///如果下一个unit是锁定状态,请求数据刷新查询解锁状态 | |
| 232 | 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 | 294 | } else { |
| 295 | + showToast("恭喜你,本阶段学到顶啦"); | |
| 249 | 296 | ///最后一个unit了 |
| 250 | 297 | return null; |
| 251 | 298 | } |
| ... | ... | @@ -254,5 +301,45 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { |
| 254 | 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<UnitEvent, UnitState> { |
| 23 | 23 | |
| 24 | 24 | |
| 25 | 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 | 30 | try { |
| 31 | 31 | await loading(() async { |
| 32 | 32 | _unitData = await LessonDao.courseUnit(event.moduleId); | ... | ... |
lib/pages/unit/view.dart
lib/utils/list_ext.dart
| ... | ... | @@ -8,4 +8,14 @@ extension ListExtension<E> on List<E> { |
| 8 | 8 | } |
| 9 | 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 | } | ... | ... |