Blame view

lib/pages/section/bloc/section_bloc.dart 14.6 KB
0493c104   吴启风   feat:带音乐点击防抖函数优化
1
2
  import 'dart:async';
  
d35a4e87   liangchengyou   feat:磨耳朵功能UI
3
  import 'package:flutter/cupertino.dart';
8988aa69   liangchengyou   feat:首页+课程列表数据获取
4
  import 'package:flutter/foundation.dart';
8df5fbf9   吴启风   feat:单元列表页由于ios嵌套...
5
  import 'package:flutter/material.dart';
d35a4e87   liangchengyou   feat:磨耳朵功能UI
6
  import 'package:flutter_bloc/flutter_bloc.dart';
8df5fbf9   吴启风   feat:单元列表页由于ios嵌套...
7
  import 'package:flutter_screenutil/flutter_screenutil.dart';
e26da9e0   吴启风   feat: 隐藏审核账号受限内容
8
  import 'package:wow_english/common/core/user_util.dart';
2187c85f   吴启风   feat:课程结构调整
9
  import 'package:wow_english/common/request/dao/lesson_dao.dart';
13e6d11d   liangchengyou   feat:首页课程模块接口
10
  import 'package:wow_english/common/request/exception.dart';
3c1d5c64   liangchengyou   feat:练习功能完成
11
  import 'package:wow_english/common/request/dao/listen_dao.dart';
e26da9e0   吴启风   feat: 隐藏审核账号受限内容
12
  import 'package:wow_english/pages/section/section_type.dart';
025d8543   biao   首页gametime播放修改
13
  import 'package:wow_english/utils/audio_player_util.dart';
13e6d11d   liangchengyou   feat:首页课程模块接口
14
  import 'package:wow_english/utils/loading.dart';
c61b3c1a   Key   feat: toast_util....
15
  import 'package:wow_english/utils/toast_util.dart';
60e47f7c   liangchengyou   feat:课程选择功能
16
  
2187c85f   吴启风   feat:课程结构调整
17
18
  import '../../../models/course_section_entity.dart';
  import '../../../models/course_unit_entity.dart';
3ba925a9   吴启风   feat:环节页增加翻页切换单元效果
19
  import '../../../utils/list_ext.dart';
60e47f7c   liangchengyou   feat:课程选择功能
20
  
2187c85f   吴启风   feat:课程结构调整
21
  part 'section_event.dart';
8df5fbf9   吴启风   feat:单元列表页由于ios嵌套...
22
  
2187c85f   吴启风   feat:课程结构调整
23
  part 'section_state.dart';
8988aa69   liangchengyou   feat:首页+课程列表数据获取
24
  
2187c85f   吴启风   feat:课程结构调整
25
  class SectionBloc extends Bloc<SectionEvent, SectionState> {
3ba925a9   吴启风   feat:环节页增加翻页切换单元效果
26
27
28
29
30
31
32
33
34
35
36
37
38
    PageController _pageController;
  
    PageController get pageController => _pageController;
  
    ///当前页索引
    int _currentPage = 0;
  
    int get currentPage => _currentPage;
  
    ScrollController _listController;
  
    ScrollController get listController => _listController;
  
8df5fbf9   吴启风   feat:单元列表页由于ios嵌套...
39
40
41
42
    ScrollController _indicatorSrollController;
  
    ScrollController get indicatorSrollController => _indicatorSrollController;
  
42f15f6c   吴启风   feat:模块选择持久化&模块主题...
43
    ///之前传进来是用于根据courseModuleCode获取主题色的,现在不用了。参数还是先留着,预防后面需要
2187c85f   吴启风   feat:课程结构调整
44
45
46
47
    CourseUnitEntity _courseUnitEntity;
  
    CourseUnitEntity get courseUnitEntity => _courseUnitEntity;
  
0cbdbb34   吴启风   feat:环节列表页返回单元列表页...
48
49
50
    ///单元列表是否有刷新,有的话返回上一页时通知其刷新接口数据
    bool courseUnitEntityChanged = false;
  
66a7e3e7   吴启风   feat:退出课堂和结束课堂优化
51
52
    ///courseUnitId与课程环节列表的映射
    final Map<int, List<CourseSectionEntity>?> _courseSectionDatasMap = {};
2187c85f   吴启风   feat:课程结构调整
53
  
1ebed821   吴启风   feat:修复所有unit解锁态下...
54
55
    Map<int, List<CourseSectionEntity>?> get courseSectionDatasMap =>
        _courseSectionDatasMap;
8988aa69   liangchengyou   feat:首页+课程列表数据获取
56
  
1ebed821   吴启风   feat:修复所有unit解锁态下...
57
    SectionBloc(this._courseUnitEntity, this._currentPage, this._pageController,
8df5fbf9   吴启风   feat:单元列表页由于ios嵌套...
58
        this._listController, this._indicatorSrollController)
22f36232   吴启风   feat:过渡页-练习环节
59
        : super(LessonInitial()) {
66a7e3e7   吴启风   feat:退出课堂和结束课堂优化
60
      on<RequestDataEvent>(_requestSectionsData);
46675a89   吴启风   feat:过渡页-视频环节
61
      on<RequestEndClassEvent>(_requestEndClass);
cd32eb01   吴启风   feat:播放音乐防抖处理(课程环节页)
62
      on<RequestEnterClassEvent>(_onEnterClass);
3ba925a9   吴启风   feat:环节页增加翻页切换单元效果
63
      on<CurrentUnitIndexChangeEvent>(_pageControllerChange);
2d1ead53   吴启风   feat:背景音播放优化
64
      on<InitEvent>((event, emit) async {
0493c104   吴启风   feat:带音乐点击防抖函数优化
65
66
        await AudioPlayerUtil.getInstance()
            .playAudio(AudioPlayerUtilType.countWithMe);
5e2bbbd3   biao   添加音频
67
68
      });
    }
5e2bbbd3   biao   添加音频
69
  
66a7e3e7   吴启风   feat:退出课堂和结束课堂优化
70
    void _requestSectionsData(
22f36232   吴启风   feat:过渡页-练习环节
71
        RequestDataEvent event, Emitter<SectionState> emitter) async {
993c1a04   liangchengyou   feat:添加数据模型
72
73
      try {
        await loading(() async {
5e2bbbd3   biao   添加音频
74
75
          List<CourseSectionEntity>? courseSectionEntities =
              await LessonDao.courseSection(courseUnitId: event.courseUnitId);
42cf5d28   吴启风   feat:环节数据接口请求优化,解...
76
77
          if (courseSectionEntities != null) {
            _courseSectionDatasMap[event.courseUnitId] =
e26da9e0   吴启风   feat: 隐藏审核账号受限内容
78
                _filterReviewContent(courseSectionEntities);
42cf5d28   吴启风   feat:环节数据接口请求优化,解...
79
80
            emitter(LessonDataLoadState());
          }
993c1a04   liangchengyou   feat:添加数据模型
81
82
83
        });
      } catch (e) {
        if (e is ApiException) {
c61b3c1a   Key   feat: toast_util....
84
          showToast(e.message.toString());
13e6d11d   liangchengyou   feat:首页课程模块接口
85
86
87
        }
      }
    }
3c1d5c64   liangchengyou   feat:练习功能完成
88
  
cd32eb01   吴启风   feat:播放音乐防抖处理(课程环节页)
89
    void _onEnterClass(
22f36232   吴启风   feat:过渡页-练习环节
90
        RequestEnterClassEvent event, Emitter<SectionState> emitter) async {
cd32eb01   吴启风   feat:播放音乐防抖处理(课程环节页)
91
92
93
94
95
      emitter(RequestEnterClassState(event.courseLessonId, event.courseType));
    }
  
    ///进入课程接口请求函数封装
    ///onRequestEnterSuccess 接口请求成功后行为函数,比如跳转课程页面
0493c104   吴启风   feat:带音乐点击防抖函数优化
96
97
98
    Future<void> requestEnterClass(
        String courseLessonId, FutureOr<void> Function() onRequestEnterSuccess,
        {FutureOr<void> Function(Object)? onRequestEnterFailed}) async {
7b87c05c   吴启风   feat:进入课堂接口取消load...
99
100
101
102
103
104
105
106
107
      // await loading(() async {
      try {
        await ListenDao.enterClass(courseLessonId);
        await Future.sync(onRequestEnterSuccess);
      } catch (e) {
        if (e is ApiException) {
          showToast('进入课堂失败 ${e.message}');
        } else {
          showToast('进入课堂失败 $e');
934e2b47   liangchengyou   feat:权限调整+课程进度接口对接
108
        }
7b87c05c   吴启风   feat:进入课堂接口取消load...
109
110
111
112
113
        if (onRequestEnterFailed != null) {
          await Future.sync(onRequestEnterFailed(e) as FutureOr Function());
        }
      }
      // });
934e2b47   liangchengyou   feat:权限调整+课程进度接口对接
114
115
    }
  
22f36232   吴启风   feat:过渡页-练习环节
116
117
    void _requestEndClass(
        RequestEndClassEvent event, Emitter<SectionState> emitter) async {
66a7e3e7   吴启风   feat:退出课堂和结束课堂优化
118
119
      if (event.isCompleted) {
        await await ListenDao.endClass(event.courseLessonId,
1ebed821   吴启风   feat:修复所有unit解锁态下...
120
            currentStep: event.currentStep, currentTime: event.currentTime);
22f36232   吴启风   feat:过渡页-练习环节
121
      } else {
66a7e3e7   吴启风   feat:退出课堂和结束课堂优化
122
        await await ListenDao.exitClass(event.courseLessonId,
1ebed821   吴启风   feat:修复所有unit解锁态下...
123
            currentStep: event.currentStep, currentTime: event.currentTime);
22f36232   吴启风   feat:过渡页-练习环节
124
      }
46675a89   吴启风   feat:过渡页-视频环节
125
      if (event.autoNextSection) {
22f36232   吴启风   feat:过渡页-练习环节
126
        final nextCourseSection =
1ebed821   吴启风   feat:修复所有unit解锁态下...
127
            await getNextCourseSection(int.parse(event.courseLessonId), emitter);
336074ab   吴启风   feat:过渡页-绘本环节跨单元处理
128
129
        if (nextCourseSection != null) {
          ///进入课堂
1ebed821   吴启风   feat:修复所有unit解锁态下...
130
131
          add(RequestEnterClassEvent(
              nextCourseSection.id.toString(), nextCourseSection.courseType));
336074ab   吴启风   feat:过渡页-绘本环节跨单元处理
132
        }
46675a89   吴启风   feat:过渡页-视频环节
133
      }
934e2b47   liangchengyou   feat:权限调整+课程进度接口对接
134
    }
3ba925a9   吴启风   feat:环节页增加翻页切换单元效果
135
  
22f36232   吴启风   feat:过渡页-练习环节
136
137
    void _pageControllerChange(
        CurrentUnitIndexChangeEvent event, Emitter<SectionState> emitter) async {
3ba925a9   吴启风   feat:环节页增加翻页切换单元效果
138
      _currentPage = event.unitIndex;
8df5fbf9   吴启风   feat:单元列表页由于ios嵌套...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
      double indicatorWidth = 30.0.w; // 指示器宽度
  
      // 计算选中项的偏移量
      double offset = _currentPage * indicatorWidth -
          (_indicatorSrollController.position.viewportDimension -
                  indicatorWidth) /
              2;
  
      // 确保偏移量在合理范围内
      if (offset < 0) {
        offset = 0;
      } else if (offset >
          unlockPageCount() * indicatorWidth -
              _indicatorSrollController.position.viewportDimension) {
        offset = unlockPageCount() * indicatorWidth -
            _indicatorSrollController.position.viewportDimension;
      }
      _indicatorSrollController.animateTo(
        offset,
        duration: const Duration(milliseconds: 250),
        curve: Curves.easeInOut,
      );
3ba925a9   吴启风   feat:环节页增加翻页切换单元效果
161
162
163
      emitter(CurrentPageIndexState());
    }
  
336074ab   吴启风   feat:过渡页-绘本环节跨单元处理
164
    ///未锁定的页(单元)数
3ba925a9   吴启风   feat:环节页增加翻页切换单元效果
165
    int unlockPageCount() {
0cbdbb34   吴启风   feat:环节列表页返回单元列表页...
166
167
168
169
170
      // return _courseUnitEntity.courseUnitVOList
      //         ?.indexWhereOrNull((element) => element.lock == true) ??
      //     _courseUnitEntity.courseUnitVOList?.length ??
      //     0;
      return _courseUnitEntity.courseUnitVOList?.length ?? 0;
3ba925a9   吴启风   feat:环节页增加翻页切换单元效果
171
    }
46675a89   吴启风   feat:过渡页-视频环节
172
  
336074ab   吴启风   feat:过渡页-绘本环节跨单元处理
173
    ///当前页的课程详情
66a7e3e7   吴启风   feat:退出课堂和结束课堂优化
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
    CourseUnitDetail getCourseUnitDetail({int? pageIndex}) {
      return _courseUnitEntity.courseUnitVOList![pageIndex ?? _currentPage];
    }
  
    ///根据courseLessonId查找对应的courseSection
    CourseSectionEntity? findCourseSectionById(int courseLessonId) {
      for (var entry in courseSectionDatasMap.entries) {
        var sectionList = entry.value;
        if (sectionList != null) {
          for (var section in sectionList) {
            if (section.id == courseLessonId) {
              return section;
            }
          }
        }
      }
      return null;
    }
  
    ///根据sortOrder查找对应的courseSection
    CourseSectionEntity? findCourseSectionBySort(int sortOrder) {
      for (var entry in courseSectionDatasMap.entries) {
        var sectionList = entry.value;
        if (sectionList != null) {
          for (var section in sectionList) {
            if (section.sortOrder == sortOrder) {
              return section;
            }
          }
        }
      }
      return null;
    }
  
e26da9e0   吴启风   feat: 隐藏审核账号受限内容
208
209
210
211
212
213
214
215
216
217
    List<CourseSectionEntity> _filterReviewContent(
        List<CourseSectionEntity> courseSections) {
      if (!UserUtil.isAppReviewAccount()) {
        return courseSections;
      }
      return courseSections
          .where((section) => section.courseType != SectionType.pictureBook.value)
          .toList();
    }
  
af6af3c5   吴启风   fix: 修复播完环节后跨单元跳错...
218
219
    ///查找当前unit内当前环节的下一个环节
    ///sortOrder是unit内编号,不能跨unit全局按sortOrder查找,否则会命中前一个unit的同序号环节
e26da9e0   吴启风   feat: 隐藏审核账号受限内容
220
221
    CourseSectionEntity? _findNextVisibleCourseSection(
        CourseSectionEntity currentSection) {
e26da9e0   吴启风   feat: 隐藏审核账号受限内容
222
223
224
225
226
227
228
229
230
      final currentUnitSections =
          _courseSectionDatasMap[currentSection.courseUnitId];
      final nextSections = currentUnitSections
          ?.where((section) => section.sortOrder > currentSection.sortOrder)
          .toList()
        ?..sort((a, b) => a.sortOrder.compareTo(b.sortOrder));
      return nextSections?.firstOrNull;
    }
  
66a7e3e7   吴启风   feat:退出课堂和结束课堂优化
231
232
233
234
    ///根据courseLessonId查找对应的CourseUnitDetail
    CourseUnitDetail? findCourseUnitDetailById(int courseLessonId) {
      final curCourseSectionEntity = findCourseSectionById(courseLessonId);
      if (curCourseSectionEntity != null) {
1ebed821   吴启风   feat:修复所有unit解锁态下...
235
        final curCourseUnitDetail = _courseUnitEntity.courseUnitVOList
009cf00d   吴启风   feat:环节&单元解锁逻辑
236
            ?.firstWhereOrNull(
1ebed821   吴启风   feat:修复所有unit解锁态下...
237
                (element) => element.id == curCourseSectionEntity.courseUnitId);
66a7e3e7   吴启风   feat:退出课堂和结束课堂优化
238
239
240
241
242
        return curCourseUnitDetail;
      }
      return null;
    }
  
336074ab   吴启风   feat:过渡页-绘本环节跨单元处理
243
    ///根据courseLessonId查找下一个courseSection
1ebed821   吴启风   feat:修复所有unit解锁态下...
244
245
    Future<CourseSectionEntity?> getNextCourseSection(
        int courseLessonId, Emitter<SectionState> emitter) async {
66a7e3e7   吴启风   feat:退出课堂和结束课堂优化
246
247
      final curCourseSectionEntity = findCourseSectionById(courseLessonId);
      final curSectionSort = curCourseSectionEntity?.sortOrder ?? 0;
1ebed821   吴启风   feat:修复所有unit解锁态下...
248
  
009cf00d   吴启风   feat:环节&单元解锁逻辑
249
250
251
      try {
        ///查找当前unit的下一个section
        CourseSectionEntity? nextCourseSectionEntity =
e26da9e0   吴启风   feat: 隐藏审核账号受限内容
252
253
254
            curCourseSectionEntity == null
                ? findCourseSectionBySort(curSectionSort + 1)
                : _findNextVisibleCourseSection(curCourseSectionEntity);
5e2bbbd3   biao   添加音频
255
256
        return checkCourseSectionLocked(
            courseLessonId, nextCourseSectionEntity, emitter);
009cf00d   吴启风   feat:环节&单元解锁逻辑
257
258
259
260
261
262
263
264
265
      } catch (e) {
        if (e is ApiException) {
          showToast(e.message.toString());
        }
        return null;
      }
    }
  
    ///检查section是否锁定
5e2bbbd3   biao   添加音频
266
267
268
    Future<CourseSectionEntity?> checkCourseSectionLocked(
        int courseLessonId,
        CourseSectionEntity? courseSectionEntity,
009cf00d   吴启风   feat:环节&单元解锁逻辑
269
270
271
272
273
274
275
276
        Emitter<SectionState> emitter) async {
      if (courseSectionEntity != null) {
        if (courseSectionEntity.lock == false) {
          ///如果section没锁,直接返回
          return courseSectionEntity;
        } else {
          ///如果section锁了,请求当前unit下的section数据,查询解锁状态
          int courseUnitId = courseSectionEntity.courseUnitId;
5e2bbbd3   biao   添加音频
277
          CourseSectionEntity? result = await loading(() async {
009cf00d   吴启风   feat:环节&单元解锁逻辑
278
            List<CourseSectionEntity>? tempSectionEntities =
5e2bbbd3   biao   添加音频
279
                await LessonDao.courseSection(courseUnitId: courseUnitId);
009cf00d   吴启风   feat:环节&单元解锁逻辑
280
            if (tempSectionEntities != null) {
e26da9e0   吴启风   feat: 隐藏审核账号受限内容
281
              tempSectionEntities = _filterReviewContent(tempSectionEntities);
009cf00d   吴启风   feat:环节&单元解锁逻辑
282
283
284
285
              _courseSectionDatasMap[courseUnitId] = tempSectionEntities;
              emitter(LessonDataLoadState());
            }
            courseSectionEntity = tempSectionEntities?.firstWhereOrNull(
5e2bbbd3   biao   添加音频
286
                (element) => element.id == courseSectionEntity?.id);
009cf00d   吴启风   feat:环节&单元解锁逻辑
287
288
289
290
291
292
293
294
295
            if (courseSectionEntity?.lock == false) {
              ///刷新后的数据如果解锁了,直接返回
              return courseSectionEntity;
            } else {
              ///请求失败或者锁定状态没变(没变就感觉状态异常了,理论上不应该进入这条分支),返回null
              showToast('下个课程还没解锁哦');
              return null;
            }
          });
9e085b2a   吴启风   feat:异步返回优化
296
          return result;
009cf00d   吴启风   feat:环节&单元解锁逻辑
297
        }
46675a89   吴启风   feat:过渡页-视频环节
298
      } else {
009cf00d   吴启风   feat:环节&单元解锁逻辑
299
        ///section为空说明当前unit学完了,找下一个unit。(跨unit选section)
1ebed821   吴启风   feat:修复所有unit解锁态下...
300
        ///先根据courseLessonId找出当前的unit
66a7e3e7   吴启风   feat:退出课堂和结束课堂优化
301
        final curCourseUnitDetail = findCourseUnitDetailById(courseLessonId);
46675a89   吴启风   feat:过渡页-视频环节
302
        if (curCourseUnitDetail != null) {
009cf00d   吴启风   feat:环节&单元解锁逻辑
303
304
          ///再根据当前unit的sortOrder找出下一个unit
          CourseUnitDetail? nextCourseUnitDetail =
5e2bbbd3   biao   添加音频
305
306
              _courseUnitEntity.courseUnitVOList?.firstWhereOrNull((element) =>
                  element.sortOrder == (curCourseUnitDetail.sortOrder! + 1));
009cf00d   吴启风   feat:环节&单元解锁逻辑
307
  
46675a89   吴启风   feat:过渡页-视频环节
308
          if (nextCourseUnitDetail != null) {
009cf00d   吴启风   feat:环节&单元解锁逻辑
309
310
            if (nextCourseUnitDetail.lock == true) {
              ///如果下一个unit是锁定状态,请求数据刷新查询解锁状态
9e085b2a   吴启风   feat:异步返回优化
311
              CourseSectionEntity? result = await loading(() async {
5e2bbbd3   biao   添加音频
312
313
314
                CourseUnitEntity? newCourseUnitEntity =
                    await LessonDao.courseUnit(
                        _courseUnitEntity.nowCourseModuleId);
009cf00d   吴启风   feat:环节&单元解锁逻辑
315
316
  
                ///拿到重新获取到的unit后,再次判断是否解锁
5e2bbbd3   biao   添加音频
317
318
                nextCourseUnitDetail = newCourseUnitEntity?.courseUnitVOList
                    ?.firstWhereOrNull(
009cf00d   吴启风   feat:环节&单元解锁逻辑
319
320
321
322
                        (element) => element.id == nextCourseUnitDetail?.id);
                if (nextCourseUnitDetail?.lock == false) {
                  ///解锁状态从锁定到解锁,覆盖原unit数据并刷新ui
                  _courseUnitEntity = newCourseUnitEntity!;
0cbdbb34   吴启风   feat:环节列表页返回单元列表页...
323
                  courseUnitEntityChanged = true;
009cf00d   吴启风   feat:环节&单元解锁逻辑
324
325
                  emitter(LessonDataLoadState());
  
5e2bbbd3   biao   添加音频
326
327
                  return checkCourseSectionLockedOfNextUnit(
                      courseLessonId, nextCourseUnitDetail!.id!, emitter);
009cf00d   吴启风   feat:环节&单元解锁逻辑
328
329
330
331
332
333
                } else {
                  showToast('下个单元课程还没解锁哦');
  
                  ///如果还是锁定状态,返回null
                  return null;
                }
336074ab   吴启风   feat:过渡页-绘本环节跨单元处理
334
              });
9e085b2a   吴启风   feat:异步返回优化
335
              return result;
009cf00d   吴启风   feat:环节&单元解锁逻辑
336
            } else {
5e2bbbd3   biao   添加音频
337
338
              return checkCourseSectionLockedOfNextUnit(
                  courseLessonId, nextCourseUnitDetail.id!, emitter);
336074ab   吴启风   feat:过渡页-绘本环节跨单元处理
339
            }
46675a89   吴启风   feat:过渡页-视频环节
340
          } else {
009cf00d   吴启风   feat:环节&单元解锁逻辑
341
            showToast("恭喜你,本阶段学到顶啦");
5e2bbbd3   biao   添加音频
342
  
46675a89   吴启风   feat:过渡页-视频环节
343
344
345
346
347
348
349
350
            ///最后一个unit了
            return null;
          }
        } else {
          ///找不到对应的unitDetail,理论上不可能
          return null;
        }
      }
009cf00d   吴启风   feat:环节&单元解锁逻辑
351
352
353
    }
  
    ///检查下一个unit的(第一个)section
5e2bbbd3   biao   添加音频
354
355
356
    Future<CourseSectionEntity?> checkCourseSectionLockedOfNextUnit(
        int courseLessonId,
        int nextCourseUnitDetailId,
009cf00d   吴启风   feat:环节&单元解锁逻辑
357
        Emitter<SectionState> emitter) async {
5e2bbbd3   biao   添加音频
358
359
      CourseSectionEntity? firstSectionNextUnit =
          await getFirstSectionByUnitId(nextCourseUnitDetailId, emitter);
009cf00d   吴启风   feat:环节&单元解锁逻辑
360
361
      if (firstSectionNextUnit != null) {
        ///下个unit的第一个section如果不为空,再次检查是否锁定
5e2bbbd3   biao   添加音频
362
363
        CourseSectionEntity? courseSectionEntity = await checkCourseSectionLocked(
            courseLessonId, firstSectionNextUnit, emitter);
009cf00d   吴启风   feat:环节&单元解锁逻辑
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
        if (courseSectionEntity != null) {
          ///只有是下一unit的第一个section并且解锁了,才跳转
          _pageController.nextPage(
            duration: const Duration(milliseconds: 250),
            curve: Curves.ease,
          );
        }
        return courseSectionEntity;
      } else {
        ///下个unit的第一个section如果为空,返回null
        showToast('下个课程暂未找到');
        return null;
      }
    }
  
    ///根据unitId获取当前unit的第一个section
    Future<CourseSectionEntity?> getFirstSectionByUnitId(
        int courseUnitId, Emitter<SectionState> emitter) async {
      List<CourseSectionEntity>? courseSectionEntity =
          _courseSectionDatasMap[courseUnitId];
      if (courseSectionEntity == null) {
        ///如果没下载过,请求数据
        await loading(() async {
e26da9e0   吴启风   feat: 隐藏审核账号受限内容
387
          final courseSections =
009cf00d   吴启风   feat:环节&单元解锁逻辑
388
              await LessonDao.courseSection(courseUnitId: courseUnitId);
e26da9e0   吴启风   feat: 隐藏审核账号受限内容
389
390
391
392
          if (courseSections != null) {
            _courseSectionDatasMap[courseUnitId] =
                _filterReviewContent(courseSections);
          }
009cf00d   吴启风   feat:环节&单元解锁逻辑
393
394
395
396
          emitter(LessonDataLoadState());
        });
      }
      return _courseSectionDatasMap[courseUnitId]?.first;
46675a89   吴启风   feat:过渡页-视频环节
397
    }
60e47f7c   liangchengyou   feat:课程选择功能
398
  }