From 2a3621f8408a29461f5101e8faa5999701a2d8f5 Mon Sep 17 00:00:00 2001 From: wuqifeng <540416539@qq.com> Date: Mon, 29 Apr 2024 20:09:50 +0800 Subject: [PATCH] feat:课程层级调整(增加unit层) --- lib/common/request/apis.dart | 3 +++ lib/common/request/dao/home_dao.dart | 15 ++++++++++++--- lib/generated/json/app_config_entity.g.dart | 39 +++++++++++++++++++++++---------------- lib/generated/json/base/json_convert_content.dart | 11 +++++++++++ lib/generated/json/course_module_entity.g.dart | 4 ++-- lib/generated/json/course_unit_entity.g.dart | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/models/course_module_entity.dart | 2 +- lib/models/course_unit_entity.dart | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pages/home/bloc/home_bloc.dart | 4 ++-- lib/pages/home/home_page.dart | 4 ++-- lib/pages/home/widgets/home_video_item.dart | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pages/home/widgets/home_vidoe_item.dart | 71 ----------------------------------------------------------------------- lib/pages/lessons/lesson_page.dart | 2 +- lib/pages/unit/bloc.dart | 34 ++++++++++++++++++++++++++++++++++ lib/pages/unit/event.dart | 8 ++++++++ lib/pages/unit/state.dart | 11 +++++++++++ lib/pages/unit/view.dart | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pages/unit/widget/course_unit_header_widget.dart | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pages/unit/widget/course_unit_item.dart | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/route/route.dart | 16 ++++++++++++---- 20 files changed, 610 insertions(+), 102 deletions(-) create mode 100644 lib/generated/json/course_unit_entity.g.dart create mode 100644 lib/models/course_unit_entity.dart create mode 100644 lib/pages/home/widgets/home_video_item.dart delete mode 100644 lib/pages/home/widgets/home_vidoe_item.dart create mode 100644 lib/pages/unit/bloc.dart create mode 100644 lib/pages/unit/event.dart create mode 100644 lib/pages/unit/state.dart create mode 100644 lib/pages/unit/view.dart create mode 100644 lib/pages/unit/widget/course_unit_header_widget.dart create mode 100644 lib/pages/unit/widget/course_unit_item.dart diff --git a/lib/common/request/apis.dart b/lib/common/request/apis.dart index 3e40030..03d8800 100644 --- a/lib/common/request/apis.dart +++ b/lib/common/request/apis.dart @@ -42,6 +42,9 @@ class Apis { // 接口地址:https://app.apifox.com/link/project/2684751/apis/api-89897663 static const String courseModule = 'home/courseModule'; + /// 课程单元列表 + static const String courseUnit = 'home/courseUnit'; + /// 课程列表 // GET /home/courseLesson // 接口地址:https://app.apifox.com/link/project/2684751/apis/api-89897662 diff --git a/lib/common/request/dao/home_dao.dart b/lib/common/request/dao/home_dao.dart index 3bea2fb..b6603ed 100644 --- a/lib/common/request/dao/home_dao.dart +++ b/lib/common/request/dao/home_dao.dart @@ -2,18 +2,27 @@ import 'package:wow_english/common/request/request_client.dart'; import 'package:wow_english/models/course_entity.dart'; import '../../../models/course_module_entity.dart'; +import '../../../models/course_unit_entity.dart'; class HomeDao { - ///获取课程模块信息 + ///获取课程模块(列表)信息 static Future?> courseModule() async { var data = await requestClient.get>(Apis.courseModule); return data; } + ///课程单元列表 + static Future courseUnit(int moduleId) async { + Map mapData = {}; + mapData['moduleId'] = moduleId; + var data = await requestClient.get(Apis.courseUnit, queryParameters: mapData); + return data; + } + ///课程列表 - static Future courseLesson({String moduleId = ''}) async { + static Future courseLesson({int? moduleId}) async { Map mapData = {}; - if (moduleId.isNotEmpty) { + if (moduleId != null) { mapData['moduleId'] = moduleId; } var data = await requestClient.get(Apis.courseLesson, queryParameters: mapData); diff --git a/lib/generated/json/app_config_entity.g.dart b/lib/generated/json/app_config_entity.g.dart index c8e4f42..c04a542 100644 --- a/lib/generated/json/app_config_entity.g.dart +++ b/lib/generated/json/app_config_entity.g.dart @@ -1,56 +1,59 @@ import 'package:wow_english/generated/json/base/json_convert_content.dart'; import 'package:wow_english/models/app_config_entity.dart'; -AppConfigEntity $AppConfigEntityEntityFromJson( - Map json) { - final AppConfigEntity appConfigEntityEntity = AppConfigEntity(); +AppConfigEntity $AppConfigEntityFromJson(Map json) { + final AppConfigEntity appConfigEntity = AppConfigEntity(); final bool? androidForceUpdate = jsonConvert.convert( json['androidForceUpdate']); if (androidForceUpdate != null) { - appConfigEntityEntity.androidForceUpdate = androidForceUpdate; + appConfigEntity.androidForceUpdate = androidForceUpdate; } final bool? androidRecommendUpdate = jsonConvert.convert( json['androidRecommendUpdate']); if (androidRecommendUpdate != null) { - appConfigEntityEntity.androidRecommendUpdate = androidRecommendUpdate; + appConfigEntity.androidRecommendUpdate = androidRecommendUpdate; } final String? androidUpdatePackageUrl = jsonConvert.convert( json['androidUpdatePackageUrl']); if (androidUpdatePackageUrl != null) { - appConfigEntityEntity.androidUpdatePackageUrl = androidUpdatePackageUrl; + appConfigEntity.androidUpdatePackageUrl = androidUpdatePackageUrl; } final int? androidVersion = jsonConvert.convert(json['androidVersion']); if (androidVersion != null) { - appConfigEntityEntity.androidVersion = androidVersion; + appConfigEntity.androidVersion = androidVersion; } final bool? iosForceUpdate = jsonConvert.convert( json['iosForceUpdate']); if (iosForceUpdate != null) { - appConfigEntityEntity.iosForceUpdate = iosForceUpdate; + appConfigEntity.iosForceUpdate = iosForceUpdate; } final bool? iosRecommendUpdate = jsonConvert.convert( json['iosRecommendUpdate']); if (iosRecommendUpdate != null) { - appConfigEntityEntity.iosRecommendUpdate = iosRecommendUpdate; + appConfigEntity.iosRecommendUpdate = iosRecommendUpdate; } final int? iosVersion = jsonConvert.convert(json['iosVersion']); if (iosVersion != null) { - appConfigEntityEntity.iosVersion = iosVersion; + appConfigEntity.iosVersion = iosVersion; + } + final String? updatePackageDescription = jsonConvert.convert( + json['updatePackageDescription']); + if (updatePackageDescription != null) { + appConfigEntity.updatePackageDescription = updatePackageDescription; } final String? noticeBeforePurchaseUrl = jsonConvert.convert( json['noticeBeforePurchaseUrl']); if (noticeBeforePurchaseUrl != null) { - appConfigEntityEntity.noticeBeforePurchaseUrl = noticeBeforePurchaseUrl; + appConfigEntity.noticeBeforePurchaseUrl = noticeBeforePurchaseUrl; } final String? safe = jsonConvert.convert(json['safe']); if (safe != null) { - appConfigEntityEntity.safe = safe; + appConfigEntity.safe = safe; } - return appConfigEntityEntity; + return appConfigEntity; } -Map $AppConfigEntityEntityToJson( - AppConfigEntity entity) { +Map $AppConfigEntityToJson(AppConfigEntity entity) { final Map data = {}; data['androidForceUpdate'] = entity.androidForceUpdate; data['androidRecommendUpdate'] = entity.androidRecommendUpdate; @@ -59,12 +62,13 @@ Map $AppConfigEntityEntityToJson( data['iosForceUpdate'] = entity.iosForceUpdate; data['iosRecommendUpdate'] = entity.iosRecommendUpdate; data['iosVersion'] = entity.iosVersion; + data['updatePackageDescription'] = entity.updatePackageDescription; data['noticeBeforePurchaseUrl'] = entity.noticeBeforePurchaseUrl; data['safe'] = entity.safe; return data; } -extension AppConfigEntityEntityExtension on AppConfigEntity { +extension AppConfigEntityExtension on AppConfigEntity { AppConfigEntity copyWith({ bool? androidForceUpdate, bool? androidRecommendUpdate, @@ -73,6 +77,7 @@ extension AppConfigEntityEntityExtension on AppConfigEntity { bool? iosForceUpdate, bool? iosRecommendUpdate, int? iosVersion, + String? updatePackageDescription, String? noticeBeforePurchaseUrl, String? safe, }) { @@ -86,6 +91,8 @@ extension AppConfigEntityEntityExtension on AppConfigEntity { ..iosForceUpdate = iosForceUpdate ?? this.iosForceUpdate ..iosRecommendUpdate = iosRecommendUpdate ?? this.iosRecommendUpdate ..iosVersion = iosVersion ?? this.iosVersion + ..updatePackageDescription = updatePackageDescription ?? + this.updatePackageDescription ..noticeBeforePurchaseUrl = noticeBeforePurchaseUrl ?? this.noticeBeforePurchaseUrl ..safe = safe ?? this.safe; diff --git a/lib/generated/json/base/json_convert_content.dart b/lib/generated/json/base/json_convert_content.dart index f414ee0..874fd55 100644 --- a/lib/generated/json/base/json_convert_content.dart +++ b/lib/generated/json/base/json_convert_content.dart @@ -9,6 +9,7 @@ import 'package:wow_english/models/app_config_entity.dart'; import 'package:wow_english/models/course_entity.dart'; import 'package:wow_english/models/course_module_entity.dart'; import 'package:wow_english/models/course_process_entity.dart'; +import 'package:wow_english/models/course_unit_entity.dart'; import 'package:wow_english/models/follow_read_entity.dart'; import 'package:wow_english/models/listen_entity.dart'; import 'package:wow_english/models/product_entity.dart'; @@ -192,6 +193,14 @@ class JsonConvert { return data.map((Map e) => CourseProcessVideos.fromJson(e)).toList() as M; } + if ([] is M) { + return data.map((Map e) => + CourseUnitEntity.fromJson(e)).toList() as M; + } + if ([] is M) { + return data.map((Map e) => + CourseUnitDetail.fromJson(e)).toList() as M; + } if ([] is M) { return data.map((Map e) => FollowReadEntity.fromJson(e)).toList() as M; @@ -246,6 +255,8 @@ class JsonConvertClassCollection { (CourseProcessTopicsTopicAnswerList) .toString(): CourseProcessTopicsTopicAnswerList.fromJson, (CourseProcessVideos).toString(): CourseProcessVideos.fromJson, + (CourseUnitEntity).toString(): CourseUnitEntity.fromJson, + (CourseUnitDetail).toString(): CourseUnitDetail.fromJson, (FollowReadEntity).toString(): FollowReadEntity.fromJson, (ListenEntity).toString(): ListenEntity.fromJson, (ProductEntity).toString(): ProductEntity.fromJson, diff --git a/lib/generated/json/course_module_entity.g.dart b/lib/generated/json/course_module_entity.g.dart index e639928..aa33de3 100644 --- a/lib/generated/json/course_module_entity.g.dart +++ b/lib/generated/json/course_module_entity.g.dart @@ -3,7 +3,7 @@ import 'package:wow_english/models/course_module_entity.dart'; CourseModuleEntity $CourseModuleEntityFromJson(Map json) { final CourseModuleEntity courseModuleEntity = CourseModuleEntity(); - final String? id = jsonConvert.convert(json['id']); + final int? id = jsonConvert.convert(json['id']); if (id != null) { courseModuleEntity.id = id; } @@ -90,7 +90,7 @@ Map $CourseModuleEntityToJson(CourseModuleEntity entity) { extension CourseModuleEntityExtension on CourseModuleEntity { CourseModuleEntity copyWith({ - String? id, + int? id, String? code, int? courseModuleThemeId, int? courseTotal, diff --git a/lib/generated/json/course_unit_entity.g.dart b/lib/generated/json/course_unit_entity.g.dart new file mode 100644 index 0000000..8f07fc7 --- /dev/null +++ b/lib/generated/json/course_unit_entity.g.dart @@ -0,0 +1,145 @@ +import 'package:wow_english/generated/json/base/json_convert_content.dart'; +import 'package:wow_english/models/course_unit_entity.dart'; + +CourseUnitEntity $CourseUnitEntityFromJson(Map json) { + final CourseUnitEntity courseUnitEntity = CourseUnitEntity(); + final List< + CourseUnitDetail>? courseUnitVOList = (json['courseUnitVOList'] as List< + dynamic>?) + ?.map( + (e) => jsonConvert.convert(e) as CourseUnitDetail) + .toList(); + if (courseUnitVOList != null) { + courseUnitEntity.courseUnitVOList = courseUnitVOList; + } + final int? nowStep = jsonConvert.convert(json['nowStep']); + if (nowStep != null) { + courseUnitEntity.nowStep = nowStep; + } + final int? total = jsonConvert.convert(json['total']); + if (total != null) { + courseUnitEntity.total = total; + } + final int? nowCourseModuleId = jsonConvert.convert( + json['nowCourseModuleId']); + if (nowCourseModuleId != null) { + courseUnitEntity.nowCourseModuleId = nowCourseModuleId; + } + final String? nowCourseModuleName = jsonConvert.convert( + json['nowCourseModuleName']); + if (nowCourseModuleName != null) { + courseUnitEntity.nowCourseModuleName = nowCourseModuleName; + } + final String? courseModuleThemeColor = jsonConvert.convert( + json['courseModuleThemeColor']); + if (courseModuleThemeColor != null) { + courseUnitEntity.courseModuleThemeColor = courseModuleThemeColor; + } + final String? courseModuleCode = jsonConvert.convert( + json['courseModuleCode']); + if (courseModuleCode != null) { + courseUnitEntity.courseModuleCode = courseModuleCode; + } + return courseUnitEntity; +} + +Map $CourseUnitEntityToJson(CourseUnitEntity entity) { + final Map data = {}; + data['courseUnitVOList'] = + entity.courseUnitVOList?.map((v) => v.toJson()).toList(); + data['nowStep'] = entity.nowStep; + data['total'] = entity.total; + data['nowCourseModuleId'] = entity.nowCourseModuleId; + data['nowCourseModuleName'] = entity.nowCourseModuleName; + data['courseModuleThemeColor'] = entity.courseModuleThemeColor; + data['courseModuleCode'] = entity.courseModuleCode; + return data; +} + +extension CourseUnitEntityExtension on CourseUnitEntity { + CourseUnitEntity copyWith({ + List? courseUnitVOList, + int? nowStep, + int? total, + int? nowCourseModuleId, + String? nowCourseModuleName, + String? courseModuleThemeColor, + String? courseModuleCode, + }) { + return CourseUnitEntity() + ..courseUnitVOList = courseUnitVOList ?? this.courseUnitVOList + ..nowStep = nowStep ?? this.nowStep + ..total = total ?? this.total + ..nowCourseModuleId = nowCourseModuleId ?? this.nowCourseModuleId + ..nowCourseModuleName = nowCourseModuleName ?? this.nowCourseModuleName + ..courseModuleThemeColor = courseModuleThemeColor ?? + this.courseModuleThemeColor + ..courseModuleCode = courseModuleCode ?? this.courseModuleCode; + } +} + +CourseUnitDetail $CourseUnitDetailFromJson(Map json) { + final CourseUnitDetail courseUnitDetail = CourseUnitDetail(); + final int? courseModuleId = jsonConvert.convert(json['courseModuleId']); + if (courseModuleId != null) { + courseUnitDetail.courseModuleId = courseModuleId; + } + final int? id = jsonConvert.convert(json['id']); + if (id != null) { + courseUnitDetail.id = id; + } + final String? name = jsonConvert.convert(json['name']); + if (name != null) { + courseUnitDetail.name = name; + } + final String? coverUrl = jsonConvert.convert(json['coverUrl']); + if (coverUrl != null) { + courseUnitDetail.coverUrl = coverUrl; + } + final bool? lock = jsonConvert.convert(json['lock']); + if (lock != null) { + courseUnitDetail.lock = lock; + } + final int? sortOrder = jsonConvert.convert(json['sortOrder']); + if (sortOrder != null) { + courseUnitDetail.sortOrder = sortOrder; + } + final int? status = jsonConvert.convert(json['status']); + if (status != null) { + courseUnitDetail.status = status; + } + return courseUnitDetail; +} + +Map $CourseUnitDetailToJson(CourseUnitDetail entity) { + final Map data = {}; + data['courseModuleId'] = entity.courseModuleId; + data['id'] = entity.id; + data['name'] = entity.name; + data['coverUrl'] = entity.coverUrl; + data['lock'] = entity.lock; + data['sortOrder'] = entity.sortOrder; + data['status'] = entity.status; + return data; +} + +extension CourseUnitDetailExtension on CourseUnitDetail { + CourseUnitDetail copyWith({ + int? courseModuleId, + int? id, + String? name, + String? coverUrl, + bool? lock, + int? sortOrder, + int? status, + }) { + return CourseUnitDetail() + ..courseModuleId = courseModuleId ?? this.courseModuleId + ..id = id ?? this.id + ..name = name ?? this.name + ..coverUrl = coverUrl ?? this.coverUrl + ..lock = lock ?? this.lock + ..sortOrder = sortOrder ?? this.sortOrder + ..status = status ?? this.status; + } +} \ No newline at end of file diff --git a/lib/models/course_module_entity.dart b/lib/models/course_module_entity.dart index d3963c2..c59d3fe 100644 --- a/lib/models/course_module_entity.dart +++ b/lib/models/course_module_entity.dart @@ -5,7 +5,7 @@ import 'package:wow_english/generated/json/course_module_entity.g.dart'; @JsonSerializable() class CourseModuleEntity { - late String id; + late int id; String? code; int? courseModuleThemeId; int? courseTotal; diff --git a/lib/models/course_unit_entity.dart b/lib/models/course_unit_entity.dart new file mode 100644 index 0000000..a2703d7 --- /dev/null +++ b/lib/models/course_unit_entity.dart @@ -0,0 +1,75 @@ +import 'package:wow_english/generated/json/base/json_field.dart'; +import 'package:wow_english/generated/json/course_unit_entity.g.dart'; +import 'dart:convert'; + +export 'package:wow_english/generated/json/course_unit_entity.g.dart'; + +@JsonSerializable() +class CourseUnitEntity { + + // 课程详情列表 + List? courseUnitVOList; + + // 当前进行了多少节课程 + int? nowStep; + + // 当前模块一共多少节课程 + int? total; + + // 当前模块id + int? nowCourseModuleId; + + // 当前模块名 + String? nowCourseModuleName; + + // 主题颜色值 + String? courseModuleThemeColor; + + // 课程模块code + String? courseModuleCode; + + CourseUnitEntity(); + + factory CourseUnitEntity.fromJson(Map json) => $CourseUnitEntityFromJson(json); + + Map toJson() => $CourseUnitEntityToJson(this); + + @override + String toString() { + return jsonEncode(this); + } +} + + +@JsonSerializable() +class CourseUnitDetail { + + // 模块id + int? courseModuleId; + + // 单元 + int? id; + + // 单元名称 + String? name; + + // 单元封面 + String? coverUrl; + + bool? lock; + + int? sortOrder; + + int? status; + + CourseUnitDetail(); + + factory CourseUnitDetail.fromJson(Map json) => $CourseUnitDetailFromJson(json); + + Map toJson() => $CourseUnitDetailToJson(this); + + @override + String toString() { + return jsonEncode(this); + } +} \ No newline at end of file diff --git a/lib/pages/home/bloc/home_bloc.dart b/lib/pages/home/bloc/home_bloc.dart index 44e94f3..ef0c7b1 100644 --- a/lib/pages/home/bloc/home_bloc.dart +++ b/lib/pages/home/bloc/home_bloc.dart @@ -13,7 +13,7 @@ part 'home_event.dart'; part 'home_state.dart'; class HomeBloc extends Bloc { - final String? moduleId; + final int? moduleId; CourseEntity? _modelData; @@ -33,7 +33,7 @@ class HomeBloc extends Bloc { void _requestData(RequestDataEvent event, Emitter emitter) async { try { await loading(() async { - _modelData = await HomeDao.courseLesson(moduleId: moduleId ?? ''); + _modelData = await HomeDao.courseLesson(moduleId: moduleId); emitter(HomeDataLoadState()); }); } catch (e) { diff --git a/lib/pages/home/home_page.dart b/lib/pages/home/home_page.dart index c65d121..cf0831b 100644 --- a/lib/pages/home/home_page.dart +++ b/lib/pages/home/home_page.dart @@ -6,7 +6,7 @@ import 'package:wow_english/common/extension/string_extension.dart'; import 'package:wow_english/models/course_entity.dart'; import 'package:wow_english/pages/home/widgets/home_bouns_item.dart'; import 'package:wow_english/pages/home/widgets/home_tab_header_widget.dart'; -import 'package:wow_english/pages/home/widgets/home_vidoe_item.dart'; +import 'package:wow_english/pages/home/widgets/home_video_item.dart'; import 'package:wow_english/route/route.dart'; import 'package:wow_english/utils/toast_util.dart'; @@ -17,7 +17,7 @@ class HomePage extends StatelessWidget { const HomePage({super.key, this.moduleId}); /// 模块id - final String? moduleId; + final int? moduleId; @override Widget build(BuildContext context) { diff --git a/lib/pages/home/widgets/home_video_item.dart b/lib/pages/home/widgets/home_video_item.dart new file mode 100644 index 0000000..5917e54 --- /dev/null +++ b/lib/pages/home/widgets/home_video_item.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:wow_english/common/extension/string_extension.dart'; +import 'package:wow_english/common/widgets/ow_image_widget.dart'; +import 'package:wow_english/models/course_entity.dart'; + +import '../courese_module_model.dart'; + +class HomeVideoItem extends StatelessWidget { + const HomeVideoItem({super.key, this.lessons, this.entity}); + + final CourseEntity? entity; + final CourseCourseLessons? lessons; + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 12.w,vertical: 24.h), + child: Container( + width: 165.w, + padding: EdgeInsets.symmetric(horizontal: 16.w,vertical: 24.h), + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('gendubeij'.assetPng), + fit: BoxFit.fill + ), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + border: Border.all( + width: 2, + color: const Color(0xFF140C10), + ), + borderRadius: BorderRadius.circular(6) + ), + child: OwImageWidget( + name: lessons?.coverUrl??'', + fit: BoxFit.fitHeight, + ), + ) + ), + 24.verticalSpace, + Container( + decoration: BoxDecoration( + border: Border.all( + width: 2, + color: const Color(0xFF140C10), + ), + color: CourseModuleModel(entity?.courseModuleCode??'Phase-1').color, + borderRadius: BorderRadius.circular(6) + ), + padding: EdgeInsets.symmetric(horizontal: 10.w), + child: Text( + lessons?.name??'', + maxLines: 1, + style: TextStyle( + fontSize: 25.sp, + color: const Color(0xFF333333) + ), + ), + ) + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/pages/home/widgets/home_vidoe_item.dart b/lib/pages/home/widgets/home_vidoe_item.dart deleted file mode 100644 index 5917e54..0000000 --- a/lib/pages/home/widgets/home_vidoe_item.dart +++ /dev/null @@ -1,71 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:wow_english/common/extension/string_extension.dart'; -import 'package:wow_english/common/widgets/ow_image_widget.dart'; -import 'package:wow_english/models/course_entity.dart'; - -import '../courese_module_model.dart'; - -class HomeVideoItem extends StatelessWidget { - const HomeVideoItem({super.key, this.lessons, this.entity}); - - final CourseEntity? entity; - final CourseCourseLessons? lessons; - - @override - Widget build(BuildContext context) { - return Padding( - padding: EdgeInsets.symmetric(horizontal: 12.w,vertical: 24.h), - child: Container( - width: 165.w, - padding: EdgeInsets.symmetric(horizontal: 16.w,vertical: 24.h), - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage('gendubeij'.assetPng), - fit: BoxFit.fill - ), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Container( - decoration: BoxDecoration( - border: Border.all( - width: 2, - color: const Color(0xFF140C10), - ), - borderRadius: BorderRadius.circular(6) - ), - child: OwImageWidget( - name: lessons?.coverUrl??'', - fit: BoxFit.fitHeight, - ), - ) - ), - 24.verticalSpace, - Container( - decoration: BoxDecoration( - border: Border.all( - width: 2, - color: const Color(0xFF140C10), - ), - color: CourseModuleModel(entity?.courseModuleCode??'Phase-1').color, - borderRadius: BorderRadius.circular(6) - ), - padding: EdgeInsets.symmetric(horizontal: 10.w), - child: Text( - lessons?.name??'', - maxLines: 1, - style: TextStyle( - fontSize: 25.sp, - color: const Color(0xFF333333) - ), - ), - ) - ], - ), - ), - ); - } -} \ No newline at end of file diff --git a/lib/pages/lessons/lesson_page.dart b/lib/pages/lessons/lesson_page.dart index 495e7ba..e3da130 100644 --- a/lib/pages/lessons/lesson_page.dart +++ b/lib/pages/lessons/lesson_page.dart @@ -171,7 +171,7 @@ class _LessonPageView extends StatelessWidget { model: model, isSelected: bloc.currentPageIndex == index, onClickEvent: () { - pushNamedAndRemoveUntil(AppRouteName.home, (route) => false,arguments: {'moduleId':model?.id}); + pushNamed(AppRouteName.unit, arguments: {'courseModuleEntity':model}); }, ), ), diff --git a/lib/pages/unit/bloc.dart b/lib/pages/unit/bloc.dart new file mode 100644 index 0000000..767b510 --- /dev/null +++ b/lib/pages/unit/bloc.dart @@ -0,0 +1,34 @@ +import 'package:bloc/bloc.dart'; + +import '../../common/request/dao/home_dao.dart'; +import '../../common/request/exception.dart'; +import '../../models/course_unit_entity.dart'; +import '../../utils/loading.dart'; +import '../../utils/toast_util.dart'; +import 'event.dart'; +import 'state.dart'; + +class UnitBloc extends Bloc { + + CourseUnitEntity? _modelData; + + CourseUnitEntity? get modelData => _modelData; + + + UnitBloc() : super(UnitState().init()) { + on(_requestData); + } + + void _requestData(RequestUnitDataEvent event, Emitter emitter) async { + try { + await loading(() async { + _modelData = await HomeDao.courseUnit(event.moduleId); + emitter(UnitDataLoadState()); + }); + } catch (e) { + if (e is ApiException) { + showToast(e.message ?? '请求失败,请检查网络连接'); + } + } + } +} diff --git a/lib/pages/unit/event.dart b/lib/pages/unit/event.dart new file mode 100644 index 0000000..6acbed4 --- /dev/null +++ b/lib/pages/unit/event.dart @@ -0,0 +1,8 @@ +abstract class UnitEvent {} + +// 获取课程单元数据 +class RequestUnitDataEvent extends UnitEvent { + final int moduleId; + + RequestUnitDataEvent(this.moduleId); +} diff --git a/lib/pages/unit/state.dart b/lib/pages/unit/state.dart new file mode 100644 index 0000000..be7b1e9 --- /dev/null +++ b/lib/pages/unit/state.dart @@ -0,0 +1,11 @@ +class UnitState { + UnitState init() { + return UnitState(); + } + + UnitState clone() { + return UnitState(); + } +} + +class UnitDataLoadState extends UnitState {} \ No newline at end of file diff --git a/lib/pages/unit/view.dart b/lib/pages/unit/view.dart new file mode 100644 index 0000000..fb24b78 --- /dev/null +++ b/lib/pages/unit/view.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:wow_english/pages/unit/state.dart'; +import 'package:wow_english/pages/unit/widget/course_unit_header_widget.dart'; +import 'package:wow_english/pages/unit/widget/course_unit_item.dart'; +import 'package:wow_english/route/route.dart'; + +import '../../models/course_module_entity.dart'; +import '../../models/course_unit_entity.dart'; +import '../../utils/toast_util.dart'; +import 'bloc.dart'; +import 'event.dart'; + +class UnitPage extends StatelessWidget { + const UnitPage({super.key, required this.courseEntity}); + + /// 模块 + final CourseModuleEntity courseEntity; + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (BuildContext context) => + UnitBloc()..add(RequestUnitDataEvent(courseEntity.id)), + child: Builder(builder: (context) => _buildPage(context)), + ); + } + + Widget _buildPage(BuildContext context) { + return BlocBuilder(builder: (context, state) { + final bloc = BlocProvider.of(context); + return Scaffold( + body: Container( + color: Colors.white, + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + CourseUnitHeaderWidget(entity: courseEntity), + Expanded( + child: ListView.builder( + itemCount: + bloc.modelData?.courseUnitVOList?.length ?? 0, + scrollDirection: Axis.horizontal, + itemBuilder: (BuildContext context, int index) { + CourseUnitDetail? data = + bloc.modelData?.courseUnitVOList?[index]; + return GestureDetector( + onTap: () { + if (data.lock == true) { + showToast('当前unit暂未解锁'); + return; + } + + ///进入课堂 + pushNamedAndRemoveUntil( + AppRouteName.home, (route) => route.isFirst, + arguments: { + 'moduleId': data.courseModuleId, + 'unitId': data.id + }); + }, + child: CourseUnitItem( + unitEntity: bloc.modelData!, + unitLesson: data!, + ), + ); + })), + SafeArea( + child: Column( + children: [ + 6.verticalSpace, + ], + ), + ) + ], + ), + ), + ), + ); + }); + } +} diff --git a/lib/pages/unit/widget/course_unit_header_widget.dart b/lib/pages/unit/widget/course_unit_header_widget.dart new file mode 100644 index 0000000..47c3866 --- /dev/null +++ b/lib/pages/unit/widget/course_unit_header_widget.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:wow_english/common/extension/string_extension.dart'; +import 'package:wow_english/pages/user/bloc/user_bloc.dart'; + +import '../../../models/course_module_entity.dart'; +import '../../home/courese_module_model.dart'; + +class CourseUnitHeaderWidget extends StatelessWidget { + const CourseUnitHeaderWidget({super.key, this.entity}); + + final CourseModuleEntity? entity; + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + return Container( + height: 45, + width: double.infinity, + color: + CourseModuleModel(entity?.code ?? 'Phase-1').color, + padding: EdgeInsets.symmetric(horizontal: 9.5.w), + child: Row( + children: [ + ScreenUtil().bottomBarHeight.horizontalSpace, + GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + alignment: Alignment.center, + child: Image.asset( + 'back_around'.assetPng, + height: 40.h, + width: 40.w, + ), + ), + ), + 20.horizontalSpace, + Expanded( + child: Text(entity?.name ?? + CourseModuleModel(entity?.code ?? 'Phase-1') + .courseModuleTitle, + textAlign: TextAlign.left, + style: const TextStyle(color: Colors.white, fontSize: 30.0), + )), + ScreenUtil().bottomBarHeight.horizontalSpace, + ], + )); + }, + ); + } +} diff --git a/lib/pages/unit/widget/course_unit_item.dart b/lib/pages/unit/widget/course_unit_item.dart new file mode 100644 index 0000000..5428fc1 --- /dev/null +++ b/lib/pages/unit/widget/course_unit_item.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:wow_english/common/extension/string_extension.dart'; +import 'package:wow_english/common/widgets/ow_image_widget.dart'; + +import '../../../models/course_unit_entity.dart'; + +class CourseUnitItem extends StatelessWidget { + const CourseUnitItem( + {super.key, required this.unitEntity, required this.unitLesson}); + + final CourseUnitEntity unitEntity; + final CourseUnitDetail unitLesson; + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 24.h), + child: Container( + width: 165.w, + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 24.h), + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('gendubeij'.assetPng), fit: BoxFit.fill), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + border: Border.all( + width: 2, + color: const Color(0xFF140C10), + ), + borderRadius: BorderRadius.circular(6)), + child: OwImageWidget( + name: unitLesson.coverUrl ?? '', + fit: BoxFit.fitHeight, + ), + )), + 20.verticalSpace, + SizedBox( + height: 40.h, + child: Text( + unitLesson.name ?? '', + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: + TextStyle(fontSize: 11.sp, color: const Color(0xFF140C10)), + ), + ) + ], + ), + ), + ); + } +} diff --git a/lib/route/route.dart b/lib/route/route.dart index efe888b..0a987c3 100644 --- a/lib/route/route.dart +++ b/lib/route/route.dart @@ -26,11 +26,12 @@ import 'package:wow_english/pages/user/setting/setting_page.dart'; import 'package:wow_english/pages/user/user_page.dart'; import 'package:wow_english/pages/video/lookvideo/look_video_page.dart'; +import '../models/course_module_entity.dart'; import '../pages/reading/reading_page.dart'; import '../pages/shopping/view.dart'; +import '../pages/unit/view.dart'; import '../pages/user/setting/delete_account_page.dart'; import '../pages/user/setting/reback_page.dart'; -import '../utils/log_util.dart'; class AppRouteName { static const String splash = 'splash'; @@ -43,7 +44,8 @@ class AppRouteName { /// 设置密码,修改密码;不要自己调用,使用[SetPassWordPage.push]方法,隐藏这种实现 //static const String setPwd = 'setPwd'; static const String webView = 'webView'; - static const String lesson = 'lesson'; + static const String unit = 'courseUnits'; + static const String lesson = 'courseModules'; static const String listen = 'listen'; static const String shop = 'shop'; static const String exLesson = 'exLesson'; @@ -100,9 +102,9 @@ class AppRouter { case AppRouteName.games: return CupertinoPageRoute(builder: (_) => const GamesPage()); case AppRouteName.home: - var moduleId = ''; + int? moduleId; if (settings.arguments != null) { - moduleId = (settings.arguments as Map)['moduleId'] as String; + moduleId = (settings.arguments as Map).getOrNull('moduleId') as int?; } return CupertinoPageRoute( builder: (_) => HomePage( @@ -112,6 +114,12 @@ class AppRouter { return CupertinoPageRoute(builder: (_) => const ForgetPasswordHomePage()); case AppRouteName.lesson: return CupertinoPageRoute(builder: (_) => const LessonPage()); + case AppRouteName.unit: + CourseModuleEntity courseEntity = CourseModuleEntity(); + if (settings.arguments != null) { + courseEntity = (settings.arguments as Map).getOrNull('courseModuleEntity') as CourseModuleEntity; + } + return CupertinoPageRoute(builder: (_) => UnitPage(courseEntity: courseEntity)); case AppRouteName.listen: return CupertinoPageRoute(builder: (_) => const ListenPage()); case AppRouteName.shop: -- libgit2 0.22.2