section_bloc.dart
13.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:wow_english/common/request/dao/lesson_dao.dart';
import 'package:wow_english/common/request/exception.dart';
import 'package:wow_english/common/request/dao/listen_dao.dart';
import 'package:wow_english/utils/audio_player_util.dart';
import 'package:wow_english/utils/loading.dart';
import 'package:wow_english/utils/toast_util.dart';
import '../../../models/course_section_entity.dart';
import '../../../models/course_unit_entity.dart';
import '../../../utils/list_ext.dart';
part 'section_event.dart';
part 'section_state.dart';
class SectionBloc extends Bloc<SectionEvent, SectionState> {
PageController _pageController;
PageController get pageController => _pageController;
///当前页索引
int _currentPage = 0;
int get currentPage => _currentPage;
ScrollController _listController;
ScrollController get listController => _listController;
ScrollController _indicatorSrollController;
ScrollController get indicatorSrollController => _indicatorSrollController;
///之前传进来是用于根据courseModuleCode获取主题色的,现在不用了。参数还是先留着,预防后面需要
CourseUnitEntity _courseUnitEntity;
CourseUnitEntity get courseUnitEntity => _courseUnitEntity;
///单元列表是否有刷新,有的话返回上一页时通知其刷新接口数据
bool courseUnitEntityChanged = false;
///courseUnitId与课程环节列表的映射
final Map<int, List<CourseSectionEntity>?> _courseSectionDatasMap = {};
Map<int, List<CourseSectionEntity>?> get courseSectionDatasMap =>
_courseSectionDatasMap;
SectionBloc(this._courseUnitEntity, this._currentPage, this._pageController,
this._listController, this._indicatorSrollController)
: super(LessonInitial()) {
on<RequestDataEvent>(_requestSectionsData);
on<RequestEndClassEvent>(_requestEndClass);
on<RequestEnterClassEvent>(_onEnterClass);
on<CurrentUnitIndexChangeEvent>(_pageControllerChange);
on<InitEvent>((event, emit) async {
await AudioPlayerUtil.getInstance()
.playAudio(AudioPlayerUtilType.countWithMe);
});
}
void _requestSectionsData(
RequestDataEvent event, Emitter<SectionState> emitter) async {
try {
await loading(() async {
List<CourseSectionEntity>? courseSectionEntities =
await LessonDao.courseSection(courseUnitId: event.courseUnitId);
if (courseSectionEntities != null) {
_courseSectionDatasMap[event.courseUnitId] =
await LessonDao.courseSection(courseUnitId: event.courseUnitId);
emitter(LessonDataLoadState());
}
});
} catch (e) {
if (e is ApiException) {
showToast(e.message.toString());
}
}
}
void _onEnterClass(
RequestEnterClassEvent event, Emitter<SectionState> emitter) async {
emitter(RequestEnterClassState(event.courseLessonId, event.courseType));
}
///进入课程接口请求函数封装
///onRequestEnterSuccess 接口请求成功后行为函数,比如跳转课程页面
Future<void> requestEnterClass(
String courseLessonId, FutureOr<void> Function() onRequestEnterSuccess,
{FutureOr<void> Function(Object)? onRequestEnterFailed}) async {
// await loading(() async {
try {
await ListenDao.enterClass(courseLessonId);
await Future.sync(onRequestEnterSuccess);
} catch (e) {
if (e is ApiException) {
showToast('进入课堂失败 ${e.message}');
} else {
showToast('进入课堂失败 $e');
}
if (onRequestEnterFailed != null) {
await Future.sync(onRequestEnterFailed(e) as FutureOr Function());
}
}
// });
}
void _requestEndClass(
RequestEndClassEvent event, Emitter<SectionState> emitter) async {
if (event.isCompleted) {
await await ListenDao.endClass(event.courseLessonId,
currentStep: event.currentStep, currentTime: event.currentTime);
} else {
await await ListenDao.exitClass(event.courseLessonId,
currentStep: event.currentStep, currentTime: event.currentTime);
}
if (event.autoNextSection) {
final nextCourseSection =
await getNextCourseSection(int.parse(event.courseLessonId), emitter);
if (nextCourseSection != null) {
///进入课堂
add(RequestEnterClassEvent(
nextCourseSection.id.toString(), nextCourseSection.courseType));
}
}
}
void _pageControllerChange(
CurrentUnitIndexChangeEvent event, Emitter<SectionState> emitter) async {
_currentPage = event.unitIndex;
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,
);
emitter(CurrentPageIndexState());
}
///未锁定的页(单元)数
int unlockPageCount() {
// return _courseUnitEntity.courseUnitVOList
// ?.indexWhereOrNull((element) => element.lock == true) ??
// _courseUnitEntity.courseUnitVOList?.length ??
// 0;
return _courseUnitEntity.courseUnitVOList?.length ?? 0;
}
///当前页的课程详情
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;
}
///根据courseLessonId查找对应的CourseUnitDetail
CourseUnitDetail? findCourseUnitDetailById(int courseLessonId) {
final curCourseSectionEntity = findCourseSectionById(courseLessonId);
if (curCourseSectionEntity != null) {
final curCourseUnitDetail = _courseUnitEntity.courseUnitVOList
?.firstWhereOrNull(
(element) => element.id == curCourseSectionEntity.courseUnitId);
return curCourseUnitDetail;
}
return null;
}
///根据courseLessonId查找下一个courseSection
Future<CourseSectionEntity?> getNextCourseSection(
int courseLessonId, Emitter<SectionState> emitter) async {
final curCourseSectionEntity = findCourseSectionById(courseLessonId);
final curSectionSort = curCourseSectionEntity?.sortOrder ?? 0;
try {
///查找当前unit的下一个section
CourseSectionEntity? nextCourseSectionEntity =
findCourseSectionBySort(curSectionSort + 1);
return checkCourseSectionLocked(
courseLessonId, nextCourseSectionEntity, emitter);
} catch (e) {
if (e is ApiException) {
showToast(e.message.toString());
}
return null;
}
}
///检查section是否锁定
Future<CourseSectionEntity?> checkCourseSectionLocked(
int courseLessonId,
CourseSectionEntity? courseSectionEntity,
Emitter<SectionState> emitter) async {
if (courseSectionEntity != null) {
if (courseSectionEntity.lock == false) {
///如果section没锁,直接返回
return courseSectionEntity;
} else {
///如果section锁了,请求当前unit下的section数据,查询解锁状态
int courseUnitId = courseSectionEntity.courseUnitId;
CourseSectionEntity? result = await loading(() async {
List<CourseSectionEntity>? tempSectionEntities =
await LessonDao.courseSection(courseUnitId: courseUnitId);
if (tempSectionEntities != null) {
_courseSectionDatasMap[courseUnitId] = tempSectionEntities;
emitter(LessonDataLoadState());
}
courseSectionEntity = tempSectionEntities?.firstWhereOrNull(
(element) => element.id == courseSectionEntity?.id);
if (courseSectionEntity?.lock == false) {
///刷新后的数据如果解锁了,直接返回
return courseSectionEntity;
} else {
///请求失败或者锁定状态没变(没变就感觉状态异常了,理论上不应该进入这条分支),返回null
showToast('下个课程还没解锁哦');
return null;
}
});
return result;
}
} else {
///section为空说明当前unit学完了,找下一个unit。(跨unit选section)
///先根据courseLessonId找出当前的unit
final curCourseUnitDetail = findCourseUnitDetailById(courseLessonId);
if (curCourseUnitDetail != null) {
///再根据当前unit的sortOrder找出下一个unit
CourseUnitDetail? nextCourseUnitDetail =
_courseUnitEntity.courseUnitVOList?.firstWhereOrNull((element) =>
element.sortOrder == (curCourseUnitDetail.sortOrder! + 1));
if (nextCourseUnitDetail != null) {
if (nextCourseUnitDetail.lock == true) {
///如果下一个unit是锁定状态,请求数据刷新查询解锁状态
CourseSectionEntity? result = await loading(() async {
CourseUnitEntity? newCourseUnitEntity =
await LessonDao.courseUnit(
_courseUnitEntity.nowCourseModuleId);
///拿到重新获取到的unit后,再次判断是否解锁
nextCourseUnitDetail = newCourseUnitEntity?.courseUnitVOList
?.firstWhereOrNull(
(element) => element.id == nextCourseUnitDetail?.id);
if (nextCourseUnitDetail?.lock == false) {
///解锁状态从锁定到解锁,覆盖原unit数据并刷新ui
_courseUnitEntity = newCourseUnitEntity!;
courseUnitEntityChanged = true;
emitter(LessonDataLoadState());
return checkCourseSectionLockedOfNextUnit(
courseLessonId, nextCourseUnitDetail!.id!, emitter);
} else {
showToast('下个单元课程还没解锁哦');
///如果还是锁定状态,返回null
return null;
}
});
return result;
} else {
return checkCourseSectionLockedOfNextUnit(
courseLessonId, nextCourseUnitDetail.id!, emitter);
}
} else {
showToast("恭喜你,本阶段学到顶啦");
///最后一个unit了
return null;
}
} else {
///找不到对应的unitDetail,理论上不可能
return null;
}
}
}
///检查下一个unit的(第一个)section
Future<CourseSectionEntity?> checkCourseSectionLockedOfNextUnit(
int courseLessonId,
int nextCourseUnitDetailId,
Emitter<SectionState> emitter) async {
CourseSectionEntity? firstSectionNextUnit =
await getFirstSectionByUnitId(nextCourseUnitDetailId, emitter);
if (firstSectionNextUnit != null) {
///下个unit的第一个section如果不为空,再次检查是否锁定
CourseSectionEntity? courseSectionEntity = await checkCourseSectionLocked(
courseLessonId, firstSectionNextUnit, emitter);
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 {
_courseSectionDatasMap[courseUnitId] =
await LessonDao.courseSection(courseUnitId: courseUnitId);
emitter(LessonDataLoadState());
});
}
return _courseSectionDatasMap[courseUnitId]?.first;
}
}