From 2187c85f138169f7b863bea0c5aff8b5d6cdf7b2 Mon Sep 17 00:00:00 2001 From: wuqifeng <540416539@qq.com> Date: Tue, 30 Apr 2024 03:14:15 +0800 Subject: [PATCH] feat:课程结构调整 --- lib/app/splash_page.dart | 4 ++-- lib/common/request/apis.dart | 3 +++ lib/common/request/dao/home_dao.dart | 31 ------------------------------- lib/common/request/dao/lesson_dao.dart | 42 ++++++++++++++++++++++++++++++++++++++++++ lib/generated/json/base/json_convert_content.dart | 6 ++++++ lib/generated/json/course_section_entity.g.dart | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/models/course_module_entity.dart | 2 +- lib/models/course_section_entity.dart | 29 +++++++++++++++++++++++++++++ lib/pages/home/bloc.dart | 45 +++++++++++++++++++++++++++++++++++++++++++++ lib/pages/home/bloc/home_bloc.dart | 76 ---------------------------------------------------------------------------- lib/pages/home/bloc/home_event.dart | 28 ---------------------------- lib/pages/home/bloc/home_state.dart | 20 -------------------- lib/pages/home/courese_module_model.dart | 87 --------------------------------------------------------------------------------------- lib/pages/home/event.dart | 3 +++ lib/pages/home/home_page.dart | 228 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ lib/pages/home/state.dart | 20 ++++++++++++++++++++ lib/pages/home/view.dart | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pages/home/widgets/BaseHomeHeaderWidget.dart | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pages/home/widgets/home_bouns_item.dart | 18 ------------------ lib/pages/home/widgets/home_tab_header_widget.dart | 141 --------------------------------------------------------------------------------------------------------------------------------------------- lib/pages/home/widgets/home_video_item.dart | 71 ----------------------------------------------------------------------- lib/pages/lessons/bloc/lesson_bloc.dart | 54 ------------------------------------------------------ lib/pages/lessons/bloc/lesson_event.dart | 11 ----------- lib/pages/lessons/bloc/lesson_state.dart | 10 ---------- lib/pages/lessons/lesson_page.dart | 180 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ lib/pages/lessons/widgets/lesson_item_widget.dart | 97 ------------------------------------------------------------------------------------------------- lib/pages/login/loginpage/login_page.dart | 2 +- lib/pages/module/bloc/module_bloc.dart | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pages/module/bloc/module_event.dart | 11 +++++++++++ lib/pages/module/bloc/module_state.dart | 10 ++++++++++ lib/pages/module/module_page.dart | 187 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pages/module/widgets/module_item_widget.dart | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pages/moduleSelect/bloc.dart | 46 ---------------------------------------------- lib/pages/moduleSelect/event.dart | 3 --- lib/pages/moduleSelect/state.dart | 20 -------------------- lib/pages/moduleSelect/view.dart | 238 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- lib/pages/moduleSelect/widgets/BaseHomeHeaderWidget.dart | 108 ------------------------------------------------------------------------------------------------------------ lib/pages/section/bloc/section_bloc.dart | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pages/section/bloc/section_event.dart | 28 ++++++++++++++++++++++++++++ lib/pages/section/bloc/section_state.dart | 20 ++++++++++++++++++++ lib/pages/section/courese_module_model.dart | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pages/section/section_page.dart | 232 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pages/section/widgets/home_video_item.dart | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pages/section/widgets/section_bouns_item.dart | 18 ++++++++++++++++++ lib/pages/section/widgets/section_header_widget.dart | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pages/tab/tab_page.dart | 8 ++++---- lib/pages/unit/bloc.dart | 35 ++++++++++++++++++++++++++++++----- lib/pages/unit/event.dart | 2 +- lib/pages/unit/view.dart | 73 ++++++++++++++++++++++++++++++++++++++++--------------------------------- lib/pages/unit/widget/course_unit_header_widget.dart | 55 ------------------------------------------------------- lib/pages/unit/widget/home_tab_header_widget.dart | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/route/route.dart | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------- 52 files changed, 1838 insertions(+), 1616 deletions(-) delete mode 100644 lib/common/request/dao/home_dao.dart create mode 100644 lib/common/request/dao/lesson_dao.dart create mode 100644 lib/generated/json/course_section_entity.g.dart create mode 100644 lib/models/course_section_entity.dart create mode 100644 lib/pages/home/bloc.dart delete mode 100644 lib/pages/home/bloc/home_bloc.dart delete mode 100644 lib/pages/home/bloc/home_event.dart delete mode 100644 lib/pages/home/bloc/home_state.dart delete mode 100644 lib/pages/home/courese_module_model.dart create mode 100644 lib/pages/home/event.dart delete mode 100644 lib/pages/home/home_page.dart create mode 100644 lib/pages/home/state.dart create mode 100644 lib/pages/home/view.dart create mode 100644 lib/pages/home/widgets/BaseHomeHeaderWidget.dart delete mode 100644 lib/pages/home/widgets/home_bouns_item.dart delete mode 100644 lib/pages/home/widgets/home_tab_header_widget.dart delete mode 100644 lib/pages/home/widgets/home_video_item.dart delete mode 100644 lib/pages/lessons/bloc/lesson_bloc.dart delete mode 100644 lib/pages/lessons/bloc/lesson_event.dart delete mode 100644 lib/pages/lessons/bloc/lesson_state.dart delete mode 100644 lib/pages/lessons/lesson_page.dart delete mode 100644 lib/pages/lessons/widgets/lesson_item_widget.dart create mode 100644 lib/pages/module/bloc/module_bloc.dart create mode 100644 lib/pages/module/bloc/module_event.dart create mode 100644 lib/pages/module/bloc/module_state.dart create mode 100644 lib/pages/module/module_page.dart create mode 100644 lib/pages/module/widgets/module_item_widget.dart delete mode 100644 lib/pages/moduleSelect/bloc.dart delete mode 100644 lib/pages/moduleSelect/event.dart delete mode 100644 lib/pages/moduleSelect/state.dart delete mode 100644 lib/pages/moduleSelect/view.dart delete mode 100644 lib/pages/moduleSelect/widgets/BaseHomeHeaderWidget.dart create mode 100644 lib/pages/section/bloc/section_bloc.dart create mode 100644 lib/pages/section/bloc/section_event.dart create mode 100644 lib/pages/section/bloc/section_state.dart create mode 100644 lib/pages/section/courese_module_model.dart create mode 100644 lib/pages/section/section_page.dart create mode 100644 lib/pages/section/widgets/home_video_item.dart create mode 100644 lib/pages/section/widgets/section_bouns_item.dart create mode 100644 lib/pages/section/widgets/section_header_widget.dart delete mode 100644 lib/pages/unit/widget/course_unit_header_widget.dart create mode 100644 lib/pages/unit/widget/home_tab_header_widget.dart diff --git a/lib/app/splash_page.dart b/lib/app/splash_page.dart index e4862b1..8162f4c 100644 --- a/lib/app/splash_page.dart +++ b/lib/app/splash_page.dart @@ -77,7 +77,7 @@ class _TransitionViewState extends State { }*/ bool isAggreementAccepted = AppConfigHelper.getAgreementAccepted(); if (isAggreementAccepted) { - pushNamedAndRemoveUntil(AppRouteName.moduleSelect, (route) => false); + pushNamedAndRemoveUntil(AppRouteName.home, (route) => false); } else { showDialog( context: context, @@ -91,7 +91,7 @@ class _TransitionViewState extends State { leftTap: () { AppConfigHelper.saveAgreementAccepted(true); pushNamedAndRemoveUntil( - AppRouteName.moduleSelect, (route) => false); + AppRouteName.home, (route) => false); }, rightTap: () { // 退出应用 diff --git a/lib/common/request/apis.dart b/lib/common/request/apis.dart index 71f960e..70e4f71 100644 --- a/lib/common/request/apis.dart +++ b/lib/common/request/apis.dart @@ -53,6 +53,9 @@ class Apis { // 接口地址:https://app.apifox.com/link/project/2684751/apis/api-89897662 static const String courseLesson = 'home/courseLesson'; + // 课程环节列表 + static const String courseSection = 'course/courseLesson'; + /// 磨耳朵 /// GET static const String ears = 'course/grinding/ears'; diff --git a/lib/common/request/dao/home_dao.dart b/lib/common/request/dao/home_dao.dart deleted file mode 100644 index b6603ed..0000000 --- a/lib/common/request/dao/home_dao.dart +++ /dev/null @@ -1,31 +0,0 @@ -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({int? moduleId}) async { - Map mapData = {}; - if (moduleId != null) { - mapData['moduleId'] = moduleId; - } - var data = await requestClient.get(Apis.courseLesson, queryParameters: mapData); - return data; - } -} diff --git a/lib/common/request/dao/lesson_dao.dart b/lib/common/request/dao/lesson_dao.dart new file mode 100644 index 0000000..ba6846d --- /dev/null +++ b/lib/common/request/dao/lesson_dao.dart @@ -0,0 +1,42 @@ +import 'package:wow_english/common/request/request_client.dart'; +import 'package:wow_english/models/course_entity.dart'; +import 'package:wow_english/models/course_section_entity.dart'; + +import '../../../models/course_module_entity.dart'; +import '../../../models/course_unit_entity.dart'; + +class LessonDao { + ///获取课程模块(列表)信息 + static Future?> courseModule() async { + var data = await requestClient.get>(Apis.courseModule); + return data; + } + + ///课程单元列表 + static Future courseUnit(int? moduleId) async { + Map mapData = {}; + if (moduleId != null) { + mapData['moduleId'] = moduleId; + } + var data = await requestClient.get(Apis.courseUnit, queryParameters: mapData); + return data; + } + + ///课程列表 + static Future courseLesson({int? courseUnitId}) async { + Map mapData = {}; + if (courseUnitId != null) { + mapData['courseUnitId'] = courseUnitId; + } + var data = await requestClient.get(Apis.courseLesson, queryParameters: mapData); + return data; + } + + ///课程(单元)列表 + static Future?> courseSection({required int courseUnitId}) async { + Map mapData = {}; + mapData['courseUnitId'] = courseUnitId; + var data = await requestClient.get?>(Apis.courseSection, queryParameters: mapData); + return data; + } +} diff --git a/lib/generated/json/base/json_convert_content.dart b/lib/generated/json/base/json_convert_content.dart index 9abac24..f673a33 100644 --- a/lib/generated/json/base/json_convert_content.dart +++ b/lib/generated/json/base/json_convert_content.dart @@ -10,6 +10,7 @@ import 'package:wow_english/models/app_version_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_section_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'; @@ -198,6 +199,10 @@ class JsonConvert { return data.map((Map e) => CourseProcessVideos.fromJson(e)).toList() as M; } + if ([] is M) { + return data.map((Map e) => + CourseSectionEntity.fromJson(e)).toList() as M; + } if ([] is M) { return data.map((Map e) => CourseUnitEntity.fromJson(e)).toList() as M; @@ -261,6 +266,7 @@ class JsonConvertClassCollection { (CourseProcessTopicsTopicAnswerList) .toString(): CourseProcessTopicsTopicAnswerList.fromJson, (CourseProcessVideos).toString(): CourseProcessVideos.fromJson, + (CourseSectionEntity).toString(): CourseSectionEntity.fromJson, (CourseUnitEntity).toString(): CourseUnitEntity.fromJson, (CourseUnitDetail).toString(): CourseUnitDetail.fromJson, (FollowReadEntity).toString(): FollowReadEntity.fromJson, diff --git a/lib/generated/json/course_section_entity.g.dart b/lib/generated/json/course_section_entity.g.dart new file mode 100644 index 0000000..19945d2 --- /dev/null +++ b/lib/generated/json/course_section_entity.g.dart @@ -0,0 +1,89 @@ +import 'package:wow_english/generated/json/base/json_convert_content.dart'; +import 'package:wow_english/models/course_section_entity.dart'; + +CourseSectionEntity $CourseSectionEntityFromJson(Map json) { + final CourseSectionEntity courseSectionEntity = CourseSectionEntity(); + final int? id = jsonConvert.convert(json['id']); + if (id != null) { + courseSectionEntity.id = id; + } + final int? courseUnitId = jsonConvert.convert(json['courseUnitId']); + if (courseUnitId != null) { + courseSectionEntity.courseUnitId = courseUnitId; + } + final int? courseModuleId = jsonConvert.convert(json['courseModuleId']); + if (courseModuleId != null) { + courseSectionEntity.courseModuleId = courseModuleId; + } + final String? name = jsonConvert.convert(json['name']); + if (name != null) { + courseSectionEntity.name = name; + } + final dynamic des = json['des']; + if (des != null) { + courseSectionEntity.des = des; + } + final int? courseType = jsonConvert.convert(json['courseType']); + if (courseType != null) { + courseSectionEntity.courseType = courseType; + } + final dynamic coverUrl = json['coverUrl']; + if (coverUrl != null) { + courseSectionEntity.coverUrl = coverUrl; + } + final int? sortOrder = jsonConvert.convert(json['sortOrder']); + if (sortOrder != null) { + courseSectionEntity.sortOrder = sortOrder; + } + final int? status = jsonConvert.convert(json['status']); + if (status != null) { + courseSectionEntity.status = status; + } + final bool? lock = jsonConvert.convert(json['lock']); + if (lock != null) { + courseSectionEntity.lock = lock; + } + return courseSectionEntity; +} + +Map $CourseSectionEntityToJson(CourseSectionEntity entity) { + final Map data = {}; + data['id'] = entity.id; + data['courseUnitId'] = entity.courseUnitId; + data['courseModuleId'] = entity.courseModuleId; + data['name'] = entity.name; + data['des'] = entity.des; + data['courseType'] = entity.courseType; + data['coverUrl'] = entity.coverUrl; + data['sortOrder'] = entity.sortOrder; + data['status'] = entity.status; + data['lock'] = entity.lock; + return data; +} + +extension CourseSectionEntityExtension on CourseSectionEntity { + CourseSectionEntity copyWith({ + int? id, + int? courseUnitId, + int? courseModuleId, + String? name, + dynamic des, + int? courseType, + dynamic coverUrl, + int? sortOrder, + int? status, + bool? lock, + }) { + return CourseSectionEntity() + ..id = id ?? this.id + ..courseUnitId = courseUnitId ?? this.courseUnitId + ..courseModuleId = courseModuleId ?? this.courseModuleId + ..name = name ?? this.name + ..des = des ?? this.des + ..courseType = courseType ?? this.courseType + ..coverUrl = coverUrl ?? this.coverUrl + ..sortOrder = sortOrder ?? this.sortOrder + ..status = status ?? this.status + ..lock = lock ?? this.lock; + } +} \ No newline at end of file diff --git a/lib/models/course_module_entity.dart b/lib/models/course_module_entity.dart index c59d3fe..0be37ea 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 int id; + int? id; String? code; int? courseModuleThemeId; int? courseTotal; diff --git a/lib/models/course_section_entity.dart b/lib/models/course_section_entity.dart new file mode 100644 index 0000000..a4f1047 --- /dev/null +++ b/lib/models/course_section_entity.dart @@ -0,0 +1,29 @@ +import 'package:wow_english/generated/json/base/json_field.dart'; +import 'package:wow_english/generated/json/course_section_entity.g.dart'; +import 'dart:convert'; +export 'package:wow_english/generated/json/course_section_entity.g.dart'; + +@JsonSerializable() +class CourseSectionEntity { + late int id; + late int courseUnitId; + late int courseModuleId; + late String name; + dynamic des; + late int courseType; + dynamic coverUrl; + late int sortOrder; + late int status; + late bool lock; + + CourseSectionEntity(); + + factory CourseSectionEntity.fromJson(Map json) => $CourseSectionEntityFromJson(json); + + Map toJson() => $CourseSectionEntityToJson(this); + + @override + String toString() { + return jsonEncode(this); + } +} \ No newline at end of file diff --git a/lib/pages/home/bloc.dart b/lib/pages/home/bloc.dart new file mode 100644 index 0000000..5279510 --- /dev/null +++ b/lib/pages/home/bloc.dart @@ -0,0 +1,45 @@ +import 'package:bloc/bloc.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; + +import '../../common/core/app_config_helper.dart'; +import '../../common/request/dao/system_dao.dart'; +import '../../models/app_version_entity.dart'; +import '../../utils/log_util.dart'; +import 'event.dart'; +import 'state.dart'; + +class ModuleSelectBloc extends Bloc { + ModuleSelectBloc() : super(HomeState().init()) { + on(_init); + } + + void _init(InitEvent event, Emitter emit) async { + await _checkUpdate(emit); + debugPrint('WQF ModuleSelectBloc _init'); + } + + Future _checkUpdate(Emitter emit) async { + if (AppConfigHelper.checkedUpdate) { + return; + } + int localVersion = int.parse(await AppConfigHelper.getAppVersion()); + AppVersionEntity? appVersionEntity = await SystemDao.getVersionInfo(); + AppConfigHelper.checkedUpdate = true; + if (appVersionEntity == null) { + return; + } + Log.d("WQF _checkUpdate appVersionEntity: $appVersionEntity localVersion=$localVersion"); + if (defaultTargetPlatform == TargetPlatform.iOS) { + if (localVersion < int.parse(appVersionEntity.version ?? '0')) { + emit(UpdateDialogState( + appVersionEntity.volType == UpdateStrategy.FORCE.name, appVersionEntity)); + } + } else { + if (localVersion < int.parse(appVersionEntity.version ?? '0')) { + emit(UpdateDialogState( + appVersionEntity.volType == UpdateStrategy.FORCE.name, appVersionEntity)); + } + } + } +} diff --git a/lib/pages/home/bloc/home_bloc.dart b/lib/pages/home/bloc/home_bloc.dart deleted file mode 100644 index ef0c7b1..0000000 --- a/lib/pages/home/bloc/home_bloc.dart +++ /dev/null @@ -1,76 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:wow_english/common/request/dao/home_dao.dart'; -import 'package:wow_english/common/request/exception.dart'; -import 'package:wow_english/models/course_entity.dart'; -import 'package:wow_english/common/request/dao/listen_dao.dart'; -import 'package:wow_english/models/course_process_entity.dart'; -import 'package:wow_english/utils/loading.dart'; -import 'package:wow_english/utils/toast_util.dart'; - -part 'home_event.dart'; -part 'home_state.dart'; - -class HomeBloc extends Bloc { - final int? moduleId; - - CourseEntity? _modelData; - - CourseEntity? get modelData => _modelData; - - CourseProcessEntity? _processEntity; - - CourseProcessEntity? get processEntity => _processEntity; - - HomeBloc(this.moduleId) : super(HomeInitial()) { - on(_requestData); - on(_requestExitClass); - on(_requestEnterClass); - on(_requestVideoLesson); - } - - void _requestData(RequestDataEvent event, Emitter emitter) async { - try { - await loading(() async { - _modelData = await HomeDao.courseLesson(moduleId: moduleId); - emitter(HomeDataLoadState()); - }); - } catch (e) { - if (e is ApiException) { - showToast(e.message.toString()); - } - } - } - - void _requestVideoLesson(RequestVideoLessonEvent event, Emitter emitter) async { - try { - await loading(() async { - _processEntity = await ListenDao.process(event.courseLessonId); - emitter(RequestVideoLessonState(event.courseLessonId,event.courseType)); - }); - } catch (e) { - if (e is ApiException) { - showToast(e.message??'请求失败,请检查网络连接'); - } - } - } - - - void _requestEnterClass(RequestEnterClassEvent event,Emitter emitter) async { - try { - await loading(() async { - await ListenDao.enterClass(event.courseLessonId); - emitter(RequestEnterClassState(event.courseLessonId,event.courseType)); - }); - } catch (e) { - if (e is ApiException) { - showToast(e.message??'请求失败,请检查网络连接'); - } - } - } - - void _requestExitClass(RequestExitClassEvent event,Emitter emitter) async { - await ListenDao.exitClass(event.courseLessonId,event.currentStep,event.currentTime); - } -} diff --git a/lib/pages/home/bloc/home_event.dart b/lib/pages/home/bloc/home_event.dart deleted file mode 100644 index a28e023..0000000 --- a/lib/pages/home/bloc/home_event.dart +++ /dev/null @@ -1,28 +0,0 @@ -part of 'home_bloc.dart'; - -@immutable -abstract class HomeEvent {} - -class RequestDataEvent extends HomeEvent {} - -///获取视频课程内容 -class RequestVideoLessonEvent extends HomeEvent { - final String courseLessonId; - final int courseType; - RequestVideoLessonEvent(this.courseLessonId, this.courseType); -} - -///进入课堂 -class RequestEnterClassEvent extends HomeEvent { - final String courseLessonId; - final int courseType; - RequestEnterClassEvent(this.courseLessonId,this.courseType); -} - -///退出课堂 -class RequestExitClassEvent extends HomeEvent { - final String courseLessonId; - final String currentStep; - final String currentTime; - RequestExitClassEvent(this.courseLessonId,this.currentStep,this.currentTime); -} diff --git a/lib/pages/home/bloc/home_state.dart b/lib/pages/home/bloc/home_state.dart deleted file mode 100644 index a58a828..0000000 --- a/lib/pages/home/bloc/home_state.dart +++ /dev/null @@ -1,20 +0,0 @@ -part of 'home_bloc.dart'; - -@immutable -abstract class HomeState {} - -class HomeInitial extends HomeState {} - -class HomeDataLoadState extends HomeState {} - -class RequestVideoLessonState extends HomeState { - final String courseLessonId; - final int type; - RequestVideoLessonState(this.courseLessonId,this.type); -} - -class RequestEnterClassState extends HomeState{ - final String courseLessonId; - final int courseType; - RequestEnterClassState(this.courseLessonId,this.courseType); -} diff --git a/lib/pages/home/courese_module_model.dart b/lib/pages/home/courese_module_model.dart deleted file mode 100644 index fb3e36c..0000000 --- a/lib/pages/home/courese_module_model.dart +++ /dev/null @@ -1,87 +0,0 @@ -import 'package:flutter/material.dart'; - -class CourseModuleModel { - Color get color => getCourseColor(); - String get courseModuleTitle => getCourseModuleTitle(); - String get courseModuleLogo => getCoureseImageName(); - - - String course; - - CourseModuleModel(this.course); - - Color getCourseColor() { - if (course == 'Phase-1') { - return Colors.yellow; - } - if (course == 'Phase-2') { - return Colors.red; - } - if (course == 'Phase-3') { - return Colors.blue; - } - if (course == 'Phase-4') { - return Colors.green; - } - if (course == 'Phase-5') { - return Colors.orange; - } - if (course == 'Phase-6') { - return const Color(0XFFC07347); - } - if (course == 'Phase-7') { - return const Color(0xFFA3A2A2); - } - return Colors.red; - } - - String getCourseModuleTitle() { - if (course == 'Phase-1') { - return 'learn wow! yellow'; - } - if (course == 'Phase-2') { - return 'learn wow! red'; - } - if (course == 'Phase-3') { - return 'learn wow! blue'; - } - if (course == 'Phase-4') { - return 'learn wow! green'; - } - if (course == 'Phase-5') { - return 'learn wow! orange'; - } - if (course == 'Phase-6') { - return 'learn wow! bronze'; - } - if (course == 'Phase-7') { - return 'learn wow! silver'; - } - return 'learn wow! red'; - } - - String getCoureseImageName() { - if (course == 'Phase-1') { - return 'yellow_positive'; - } - if (course == 'Phase-2') { - return 'red_positive'; - } - if (course == 'Phase-3') { - return 'blue_positive'; - } - if (course == 'Phase-4') { - return 'learn wow! green'; - } - if (course == 'Phase-5') { - return 'orange_positive'; - } - if (course == 'Phase-6') { - return 'bronze_positive'; - } - if (course == 'Phase-7') { - return 'silver_positive'; - } - return 'red_positive'; - } -} \ No newline at end of file diff --git a/lib/pages/home/event.dart b/lib/pages/home/event.dart new file mode 100644 index 0000000..e16af4c --- /dev/null +++ b/lib/pages/home/event.dart @@ -0,0 +1,3 @@ +abstract class HomeEvent {} + +class InitEvent extends HomeEvent {} \ No newline at end of file diff --git a/lib/pages/home/home_page.dart b/lib/pages/home/home_page.dart deleted file mode 100644 index cf0831b..0000000 --- a/lib/pages/home/home_page.dart +++ /dev/null @@ -1,228 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:wow_english/common/core/user_util.dart'; -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_video_item.dart'; -import 'package:wow_english/route/route.dart'; -import 'package:wow_english/utils/toast_util.dart'; - -import 'bloc/home_bloc.dart'; -import 'courese_module_model.dart'; - -class HomePage extends StatelessWidget { - const HomePage({super.key, this.moduleId}); - - /// 模块id - final int? moduleId; - - @override - Widget build(BuildContext context) { - return BlocProvider( - create: (context) => HomeBloc(moduleId)..add(RequestDataEvent()), - child: _HomePageView(context), - ); - } -} - -class _HomePageView extends StatelessWidget { - - const _HomePageView(this.context); - - final BuildContext context; - - void _headerActionEvent(HeaderActionType type) { - if (type == HeaderActionType.video) { - pushNamed(AppRouteName.reAfter); - } else if (type == HeaderActionType.phase) { - pushNamed(AppRouteName.lesson); - } else if (type == HeaderActionType.listen) { - pushNamed(AppRouteName.listen); - } else if (type == HeaderActionType.shop) { - pushNamed(AppRouteName.shop); - } else if (type == HeaderActionType.user) { - pushNamed(AppRouteName.user); - } else if (type == HeaderActionType.home) { - Navigator.pop(context); - } - } - - @override - Widget build(BuildContext context) { - final bloc = BlocProvider.of(context); - return BlocListener( - listener: (context, state) { - if (state is RequestVideoLessonState) { - final videoUrl = bloc.processEntity?.videos?.videoUrl??''; - var title = ''; - if (state.type == 1) { - title = 'song'; - } - - if (state.type == 2) { - title = 'video'; - } - - if (state.type == 5) { - title = 'bonus'; - } - - if (videoUrl.isEmpty || !videoUrl.contains('http')) { - return; - } - pushNamed(AppRouteName.lookVideo,arguments: {'videoUrl':videoUrl,'title':title,'courseLessonId':state.courseLessonId}).then((value) { - if (value != null) { - Map dataMap = value as Map; - bloc.add(RequestExitClassEvent( - dataMap['courseLessonId']!, - '0', - dataMap['currentTime']!, - )); - } - }); - return; - } - - if (state is RequestEnterClassState) { - if (state.courseType != 3 && state.courseType != 4) {///视频类型 - ///获取视频课程内容 - bloc.add(RequestVideoLessonEvent(state.courseLessonId,state.courseType)); - return; - } - - if (state.courseType == 4) {//绘本 - pushNamed(AppRouteName.reading, arguments: {'courseLessonId':state.courseLessonId}).then((value) { - if (value != null) { - Map dataMap = value as Map; - bloc.add(RequestExitClassEvent( - dataMap['courseLessonId']!, - dataMap['currentStep']!, - '0' - )); - } - }); - return; - } - - if (state.courseType == 3) {//练习 - pushNamed(AppRouteName.topicPic,arguments: {'courseLessonId':state.courseLessonId}).then((value) { - if (value != null) { - Map dataMap = value as Map; - bloc.add(RequestExitClassEvent( - dataMap['courseLessonId']!, - dataMap['currentStep']!, - '0' - )); - } - }); - return; - } - } - }, - child: _homeView(), - ); - } - - Widget _homeView() => BlocBuilder( - builder: (context, state) { - final bloc = BlocProvider.of(context); - return Scaffold( - body: Container( - color: Colors.white, - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - HomeTabHeaderWidget( - entity: bloc.modelData, - actionTap: (HeaderActionType type) { - _headerActionEvent(type); - }, - ), - Expanded( - child: ListView.builder( - itemCount: bloc.modelData?.totalCourseLesson??0, - scrollDirection: Axis.horizontal, - itemBuilder: (BuildContext context, int index) { - CourseCourseLessons? data = bloc.modelData?.courseLessons?[index]; - if (data?.courseType == 5) { - //彩蛋 - return GestureDetector( - onTap: () { - if (!UserUtil.isLogined()) { - pushNamed(AppRouteName.login); - return; - } - if (data!.lock!) { - showToast('当前课程暂未解锁'); - return; - } - ///进入课堂 - bloc.add(RequestEnterClassEvent(data.id!,data.courseType!)); - }, - child: HomeBoundsItem( - imageUrl: data?.coverUrl, - ), - ); - } else { - return GestureDetector( - onTap: () { - if (!UserUtil.isLogined()) { - pushNamed(AppRouteName.login); - return; - } - if (data!.lock!) { - showToast('当前课程暂未解锁'); - return; - } - ///进入课堂 - bloc.add(RequestEnterClassEvent(data.id!,data.courseType!)); - }, - child: HomeVideoItem( - entity: bloc.modelData, - lessons: data, - ), - ); - } - })), - SafeArea( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 13.w), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SizedBox( - height: 47.h, - width: 80.w, - ), - Container( - decoration: BoxDecoration( - color: CourseModuleModel(bloc.modelData?.courseModuleCode??'Phase-1').color, - borderRadius: BorderRadius.circular(14.5.r), - ), - padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 24.w), - child: Text( - '${(bloc.modelData?.nowCourseLesson??0)}/${bloc.modelData?.totalCourseLesson??0}', - style: TextStyle(color: Colors.white, fontSize: 12.sp), - ), - ), - Image.asset( - CourseModuleModel(bloc.modelData?.courseModuleCode??'Phase-1').courseModuleLogo.assetPng, - height: 47.h, - width: 80.w, - // color: Colors.red, - ), - ], - ), - ), - ) - ], - ), - ), - ), - ); - }); -} diff --git a/lib/pages/home/state.dart b/lib/pages/home/state.dart new file mode 100644 index 0000000..45a8985 --- /dev/null +++ b/lib/pages/home/state.dart @@ -0,0 +1,20 @@ +import 'package:wow_english/models/app_version_entity.dart'; + +class HomeState { + HomeState init() { + return HomeState(); + } + + HomeState clone() { + return HomeState(); + } +} + +class UpdateDialogState extends HomeState { + + final AppVersionEntity appVersionEntity; + + final bool forceUpdate; + + UpdateDialogState(this.forceUpdate, this.appVersionEntity); +} diff --git a/lib/pages/home/view.dart b/lib/pages/home/view.dart new file mode 100644 index 0000000..af9f5ef --- /dev/null +++ b/lib/pages/home/view.dart @@ -0,0 +1,238 @@ + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_app_update/azhon_app_update.dart'; +import 'package:flutter_app_update/update_model.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:wow_english/common/core/app_config_helper.dart'; +import 'package:wow_english/common/extension/string_extension.dart'; +import 'package:wow_english/models/app_version_entity.dart'; +import 'package:wow_english/pages/home/state.dart'; +import 'package:wow_english/pages/home/widgets/BaseHomeHeaderWidget.dart'; +import 'package:wow_english/pages/user/bloc/user_bloc.dart'; + +import '../../common/core/user_util.dart'; +import '../../common/dialogs/show_dialog.dart'; +import '../../utils/log_util.dart'; +import 'bloc.dart'; +import 'event.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:wow_english/route/route.dart'; + +class HomePage extends StatelessWidget { + const HomePage({super.key}); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (BuildContext context) => + ModuleSelectBloc() + ..add(InitEvent()), + child: Builder(builder: (context) => _HomePageView()), + ); + } +} + +class _HomePageView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MultiBlocListener(listeners: [ + BlocListener(listener: (context, state) { + debugPrint('WQF ModuleSelectPage BlocListener state: $state'); + }), + BlocListener( + listener: (context, state) { + if (state is UpdateDialogState) { + _showUpdateDialog(context, state.forceUpdate, state.appVersionEntity); + } + }, + ), + ], child: _homeView()); + } + + Widget _homeView() => + BlocBuilder( + builder: (context, state) { + return Scaffold( + body: Container( + color: Colors.white, + child: Column( + children: [ + const BaseHomeHeaderWidget(), + Expanded( + child: Center( + child: Row( + children: [ + Expanded( + child: GestureDetector( + onTap: () { + if (UserUtil.isLogined()) { + pushNamed(AppRouteName.courseUnit); + } else { + pushNamed(AppRouteName.login); + } + }, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Stack( + alignment: AlignmentDirectional.center, + children: [ + Image.asset( + 'bg_frame_module'.assetPng, + width: 162.5.w, height: 203.5.h), + Center( + child: Image.asset( + 'pic_module_study'.assetPng, + width: 140.5.w, + height: 172.h), + ) + ]), + 10.verticalSpace, + Image.asset('label_module_study'.assetPng, + width: 124.w, height: 34.h), + ], + ), + ), + ), + Expanded( + child: BlocBuilder( + builder: (context, userState) { + debugPrint( + 'WQF ModuleSelectPage BlocBuilder state: $userState'); + return GestureDetector( + onTap: () { + //如果没登录先登录 + if (UserUtil.isLogined()) { + if (AppConfigHelper + .shouldHidePay()) { + pushNamed(AppRouteName.games); + } else { + if (UserUtil + .hasGamePermission()) { + pushNamed(AppRouteName.games); + } else { + showTwoActionDialog( + '提示', '忽略', '去续费', + '您的课程已到期,请快快续费继续学习吧!', + leftTap: () { + popPage(); + }, rightTap: () { + popPage(); + pushNamed(AppRouteName.shop); + }); + } + } + } else { + pushNamed(AppRouteName.login); + } + }, + child: Column( + mainAxisAlignment: MainAxisAlignment + .center, + children: [ + Stack( + alignment: AlignmentDirectional + .center, + children: [ + Image.asset( + 'bg_frame_module' + .assetPng, + width: 162.5.w, + height: 203.5.h), + Image.asset( + 'pic_module_game' + .assetPng, + width: 140.5.w, + height: 172.h) + ]), + 10.verticalSpace, + Image.asset( + 'label_module_game'.assetPng, + width: 124.w, height: 34.h), + ], + )); + }), + ), + ], + ), + ), + ) + ], + ), + ), + ); + }); + + + ///Flutter侧处理升级对话框 + ///[forcedUpgrade] 是否强制升级 + _showUpdateDialog(BuildContext context, bool forcedUpgrade, + AppVersionEntity appVersionEntity) { + showDialog( + context: context, + // 当我们点击除开对话框内容以外的区域是否关闭对话需用用到barrierDismissible参数 . 这个参数默认值是true ,但不能为null . + barrierDismissible: !forcedUpgrade, + builder: (BuildContext context) { + return WillPopScope( + onWillPop: () => Future.value(!forcedUpgrade), + child: AlertDialog( + title: const Text('发现新版本'), + content: Text( + appVersionEntity.remark ?? + '修复了一些已知问题'), + actions: [ + TextButton( + child: Text(forcedUpgrade ? '退出' : '取消'), + onPressed: () => + { + if (forcedUpgrade) { + AppConfigHelper.exitApp() + } else + { + Navigator.of(context).pop() + } + }, + ), + TextButton( + child: const Text('升级'), + onPressed: () async { + if (defaultTargetPlatform == TargetPlatform.iOS) { + _launchAppStore("6450870731"); + return; + } + final String? apkUrl = appVersionEntity.packageUrl; + if (apkUrl == null || apkUrl.isEmpty) { + return; + } + UpdateModel model = UpdateModel( + apkUrl, + "wowenglish.apk", + "ic_launcher", + '', + ); + AzhonAppUpdate.update(model).then((value) => + debugPrint('$value')); + if (!forcedUpgrade) { + Navigator.of(context).pop(); + } + }, + ), + ], + ), + ); + }, + ); + } + + void _launchAppStore(String appId) async { + final String url = 'https://apps.apple.com/cn/app/wow-english/id$appId'; + if (await canLaunchUrl(Uri.parse(url))) { + await launchUrl(Uri.parse(url)); + } else { + throw 'Could not launch $url'; + } + } +} diff --git a/lib/pages/home/widgets/BaseHomeHeaderWidget.dart b/lib/pages/home/widgets/BaseHomeHeaderWidget.dart new file mode 100644 index 0000000..11a2ccf --- /dev/null +++ b/lib/pages/home/widgets/BaseHomeHeaderWidget.dart @@ -0,0 +1,108 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:wow_english/common/core/app_config_helper.dart'; +import 'package:wow_english/common/extension/string_extension.dart'; + +import '../../../common/core/user_util.dart'; +import '../../../models/course_entity.dart'; +import '../../../route/route.dart'; +import '../../../utils/image_util.dart'; +import '../../user/bloc/user_bloc.dart'; + +class BaseHomeHeaderWidget extends StatelessWidget { + const BaseHomeHeaderWidget({super.key, this.entity}); + + final CourseEntity? entity; + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + return Container( + height: 45, + width: double.infinity, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('bg_header_sliver'.assetPng), + fit: BoxFit.cover, + ), + ), + padding: EdgeInsets.symmetric(horizontal: 9.5.w), + child: Row( + children: [ + ScreenUtil().bottomBarHeight.horizontalSpace, + GestureDetector( + onTap: () => {onUserClick()}, + child: Container( + decoration: BoxDecoration( + border: Border.all( + width: 1.0, + color: const Color(0xFF140C10), + ), + borderRadius: BorderRadius.circular(21), + ), + child: CircleAvatar( + radius: 21, + backgroundImage: ImageUtil.getImageProviderOnDefault( + UserUtil.getUser()?.avatarUrl), + ), + ), + ), + GestureDetector( + onTap: () { + onUserClick(); + }, + child: Container( + margin: const EdgeInsets.only(left: 7), + padding: const EdgeInsets.all(4.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(2), + border: Border.all( + width: 1.0, + color: const Color(0xFF140C10), + style: BorderStyle.solid), + ), + child: Text( + UserUtil.getUser()?.name ?? '未登录', + style: TextStyle( + color: const Color(0xFF333333), fontSize: 16.sp), + ), + ), + ), + 20.horizontalSpace, + const Expanded( + child: Text( + "WOW ENGLISH", + textAlign: TextAlign.left, + style: TextStyle(color: Colors.white, fontSize: 30.0), + )), + Offstage( + offstage: AppConfigHelper.shouldHidePay(), + child: Row(children: [ + Image( + width: 20.0.w, + height: 20.0.h, + image: AssetImage('ic_countdown'.assetPng)), + // 替换为你的图片资源路径 + const SizedBox(width: 10.0), + // 图片和文本之间的间隔 + Text('还剩${UserUtil.getRemainingValidity()}天'), + ]), + ), + ScreenUtil().bottomBarHeight.horizontalSpace, + ], + )); + }, + ); + } +} + +void onUserClick() { + if (UserUtil.isLogined()) { + pushNamed(AppRouteName.user); + } else { + pushNamed(AppRouteName.login); + } +} diff --git a/lib/pages/home/widgets/home_bouns_item.dart b/lib/pages/home/widgets/home_bouns_item.dart deleted file mode 100644 index 27fa3da..0000000 --- a/lib/pages/home/widgets/home_bouns_item.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:wow_english/common/widgets/ow_image_widget.dart'; - -class HomeBoundsItem extends StatelessWidget { - const HomeBoundsItem({super.key, this.imageUrl}); - - final String? imageUrl; - - @override - Widget build(BuildContext context) { - return SizedBox( - height: 207.h, - width: 169.w, - child: OwImageWidget(name:imageUrl??''), - ); - } -} \ No newline at end of file diff --git a/lib/pages/home/widgets/home_tab_header_widget.dart b/lib/pages/home/widgets/home_tab_header_widget.dart deleted file mode 100644 index 0c544c4..0000000 --- a/lib/pages/home/widgets/home_tab_header_widget.dart +++ /dev/null @@ -1,141 +0,0 @@ -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 '../../../common/core/app_config_helper.dart'; -import '../../../models/course_entity.dart'; -import '../courese_module_model.dart'; - -enum HeaderActionType { - //视频跟读 - video, - //阶段选择 - phase, - //磨耳朵 - listen, - //购买 - shop, - //个人信息 - user, - //返回到(模块选择)首页 - home, -} - -class HomeTabHeaderWidget extends StatelessWidget { - const HomeTabHeaderWidget({super.key, this.entity, this.actionTap}); - - final CourseEntity? entity; - final Function(HeaderActionType type)? actionTap; - - @override - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - return Container( - height: 45, - width: double.infinity, - color: - CourseModuleModel(entity?.courseModuleCode ?? 'Phase-1').color, - padding: EdgeInsets.symmetric(horizontal: 9.5.w), - child: Row( - children: [ - ScreenUtil().bottomBarHeight.horizontalSpace, - GestureDetector( - onTap: () { - if (actionTap != null) { - actionTap!(HeaderActionType.home); - } - }, - child: Container( - alignment: Alignment.center, - child: Image.asset( - 'back_around'.assetPng, - height: 40.h, - width: 40.w, - ), - ), - ), - // GestureDetector( - // onTap: () => actionTap?.call(HeaderActionType.user), - // child: Container( - // decoration: BoxDecoration( - // border: Border.all( - // width: 1.0, - // color: const Color(0xFF140C10), - // ), - // borderRadius: BorderRadius.circular(21), - // ), - // child: CircleAvatar( - // radius: 21, - // backgroundImage: ImageUtil.getImageProviderOnDefault(UserUtil.getUser()?.avatarUrl), - // ), - // ), - // ), - // GestureDetector( - // onTap: () { - // if (actionTap != null) { - // actionTap!(HeaderActionType.user); - // } - // }, - // child: Container( - // margin: const EdgeInsets.only(left: 7), - // padding: const EdgeInsets.all(4.0), - // decoration: BoxDecoration( - // color: Colors.white, - // borderRadius: BorderRadius.circular(2), - // border: Border.all(width: 1.0, color: const Color(0xFF140C10), style: BorderStyle.solid), - // ), - // child: Text( - // UserUtil.getUser()?.name ?? '未登录', - // style: TextStyle(color: const Color(0xFF333333), fontSize: 16.sp), - // ), - // ), - // ), - 20.horizontalSpace, - Expanded( - child: Text( - CourseModuleModel(entity?.courseModuleCode ?? 'Phase-1') - .courseModuleTitle, - textAlign: TextAlign.left, - style: const TextStyle(color: Colors.white, fontSize: 30.0), - )), - // IconButton( - // onPressed: () { - // if (actionTap != null) { - // actionTap!(HeaderActionType.video); - // } - // }, - // icon: Image.asset('video'.assetPng)), - IconButton( - onPressed: () { - if (actionTap != null) { - actionTap!(HeaderActionType.phase); - } - }, - icon: Image.asset('home'.assetPng)), - IconButton( - onPressed: () { - if (actionTap != null) { - actionTap!(HeaderActionType.listen); - } - }, - icon: Image.asset('listen'.assetPng)), - Offstage( - offstage: AppConfigHelper.shouldHidePay(), - child: IconButton( - onPressed: () { - if (actionTap != null) { - actionTap!(HeaderActionType.shop); - } - }, - icon: Image.asset('shop'.assetPng)), - ), - ScreenUtil().bottomBarHeight.horizontalSpace, - ], - )); - }, - ); - } -} diff --git a/lib/pages/home/widgets/home_video_item.dart b/lib/pages/home/widgets/home_video_item.dart deleted file mode 100644 index 5917e54..0000000 --- a/lib/pages/home/widgets/home_video_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/bloc/lesson_bloc.dart b/lib/pages/lessons/bloc/lesson_bloc.dart deleted file mode 100644 index 5c4077f..0000000 --- a/lib/pages/lessons/bloc/lesson_bloc.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:wow_english/common/request/dao/home_dao.dart'; -import 'package:wow_english/common/request/exception.dart'; -import 'package:wow_english/models/course_module_entity.dart'; -import 'package:wow_english/utils/loading.dart'; -import 'package:wow_english/utils/toast_util.dart'; - -part 'lesson_event.dart'; -part 'lesson_state.dart'; - -class LessonBloc extends Bloc { - final int pageIndex; - - final PageController pageController; - - int _currentPageIndex = 0; - - int get currentPageIndex => _currentPageIndex; - - List _listData = []; - - List get listData => _listData; - - LessonBloc(this.pageIndex, this.pageController) : super(LessonInitial()) { - _currentPageIndex = pageIndex; - on(_pageIndexChange); - on(_requestData); - } - - void _pageIndexChange(PageViewChangeIndexEvent event, Emitter emitter) async { - _currentPageIndex = event.index; - emitter(PageIndexChangeState()); - } - - void _requestData(RequestDataEvent event, Emitter emitter) async { - try { - await loading(() async { - _listData = await HomeDao.courseModule() ?? []; - emitter(LessonDataLoadState()); - }); - } catch (e) { - if (e is ApiException) { - showToast(e.message ?? '请求失败,请检查网络连接'); - } - } - } - - @override - Future close() { - pageController.dispose(); - return super.close(); - } -} diff --git a/lib/pages/lessons/bloc/lesson_event.dart b/lib/pages/lessons/bloc/lesson_event.dart deleted file mode 100644 index 7dd5fda..0000000 --- a/lib/pages/lessons/bloc/lesson_event.dart +++ /dev/null @@ -1,11 +0,0 @@ -part of 'lesson_bloc.dart'; - -@immutable -abstract class LessonEvent {} - -class PageViewChangeIndexEvent extends LessonEvent { - final int index; - PageViewChangeIndexEvent(this.index); -} - -class RequestDataEvent extends LessonEvent {} diff --git a/lib/pages/lessons/bloc/lesson_state.dart b/lib/pages/lessons/bloc/lesson_state.dart deleted file mode 100644 index fac0b10..0000000 --- a/lib/pages/lessons/bloc/lesson_state.dart +++ /dev/null @@ -1,10 +0,0 @@ -part of 'lesson_bloc.dart'; - -@immutable -abstract class LessonState {} - -class LessonInitial extends LessonState {} - -class PageIndexChangeState extends LessonState {} - -class LessonDataLoadState extends LessonState {} diff --git a/lib/pages/lessons/lesson_page.dart b/lib/pages/lessons/lesson_page.dart deleted file mode 100644 index e3da130..0000000 --- a/lib/pages/lessons/lesson_page.dart +++ /dev/null @@ -1,180 +0,0 @@ -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/common/widgets/we_app_bar.dart'; -import 'package:wow_english/models/course_module_entity.dart'; -import 'package:wow_english/route/route.dart'; - -import 'bloc/lesson_bloc.dart'; -import 'widgets/lesson_item_widget.dart'; - -class LessonPage extends StatelessWidget { - const LessonPage({super.key, this.starPageIndex}); - - final int? starPageIndex; - - @override - Widget build(BuildContext context) { - return BlocProvider( - create: (context) => LessonBloc( - starPageIndex??0, - PageController( - initialPage: starPageIndex??0, - viewportFraction: 0.3 - ), - )..add(RequestDataEvent()), - child: _LessonPageView(), - ); - } -} - -class _LessonPageView extends StatelessWidget { - - final double _cardHeight = 240.h; - - final double _scale = 0.8; - - @override - Widget build(BuildContext context) { - return BlocListener( - listener: (context, state){}, - child: Scaffold( - appBar: WEAppBar( - leading: IconButton( - onPressed: (){ - popPage(); - }, - icon: Image.asset( - 'back'.assetPng, - height: 43, - width: 43, - ) - ), - // actions: [ - // IconButton( - // icon: Image.asset('shop'.assetPng), - // color: Colors.white, - // onPressed: () { - // showToast('购买'); - // }, - // ) - // ], - ), - body: _lessViewWidget(), - ), - ); - } - - Widget _lessViewWidget() => BlocBuilder( - builder: (context, state){ - final bloc = BlocProvider.of(context); - return Center( - child: SafeArea( - child: Column( - children: [ - SizedBox( - height: _cardHeight, - child: PageView.builder( - itemCount: bloc.listData.length, - controller: bloc.pageController, - onPageChanged: (int index) { - bloc.add(PageViewChangeIndexEvent(index)); - }, - itemBuilder: (context,index) => _itemTransCard(index) - ), - ), - 32.verticalSpace, - SizedBox( - height: 32.h, - width: 66.w * bloc.listData.length, - child: ListView.builder( - itemCount: bloc.listData.length, - scrollDirection: Axis.horizontal, - itemBuilder: (BuildContext context,int index){ - return Container( - height: 32.h, - width: 66.w, - padding: const EdgeInsets.symmetric(horizontal: 5), - child: GestureDetector( - onTap: () { - if (index == bloc.currentPageIndex) { - return; - } - int mill = (index - bloc.currentPageIndex) > 0 ? 100 * (index - bloc.currentPageIndex):100 * (bloc.currentPageIndex-index); - bloc.pageController.animateToPage(index, duration: Duration(milliseconds: mill), curve: Curves.ease); - }, - child: Container( - height: bloc.currentPageIndex == index ? 32:20, - decoration: BoxDecoration( - color: bloc.currentPageIndex == index ? Colors.red:Colors.white, - borderRadius: BorderRadius.circular(5.r), - border: Border.all( - width: 0.5, - color: Colors.black, - ), - ), - alignment: Alignment.center, - child: Text( - (index+1).toString(), - style: TextStyle( - color: bloc.currentPageIndex == index ? Colors.white:Colors.black - ), - ), - ), - ), - ); - }), - ) - ], - ), - ), - ); - }); - - Widget _itemTransCard(int index) => BlocBuilder( - builder: (context, state) { - final bloc = BlocProvider.of(context); - Matrix4 matrix4 = Matrix4.identity(); - if (index == bloc.currentPageIndex.floor()) { - //当前的item - double currScale = (1 - (bloc.currentPageIndex - index) * (1 - _scale)).toDouble(); - var currTrans = _cardHeight * (1 - currScale) / 2; - - matrix4 = Matrix4.diagonal3Values(1.0, currScale, 1.0) - ..setTranslationRaw(0.0, currTrans, 0.0); - } else if (index == bloc.currentPageIndex.floor() + 1) { - //右边的item - var currScale = _scale + (bloc.currentPageIndex - index + 1) * (1 - _scale); - var currTrans = _cardHeight * (1 - currScale) / 2; - - matrix4 = Matrix4.diagonal3Values(1.0, currScale, 1.0) - ..setTranslationRaw(0.0, currTrans, 0.0); - } else if (index == bloc.currentPageIndex - 1) { - //左边 - var currScale = (1 - (bloc.currentPageIndex - index) * (1 - _scale)).toDouble(); - var currTrans = _cardHeight * (1 - currScale) / 2; - - matrix4 = Matrix4.diagonal3Values(1.0, currScale, 1.0) - ..setTranslationRaw(0.0, currTrans, 0.0); - } else { - //其他,不在屏幕显示的item - matrix4 = Matrix4.diagonal3Values(1.0, _scale, 1.0) - ..setTranslationRaw(0.0, _cardHeight * (1 - _scale) / 2, 0.0); - } - CourseModuleEntity? model = bloc.listData[index]; - return Transform( - transform: matrix4, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 10), - child: LessonItemWidget( - model: model, - isSelected: bloc.currentPageIndex == index, - onClickEvent: () { - pushNamed(AppRouteName.unit, arguments: {'courseModuleEntity':model}); - }, - ), - ), - ); - }); -} diff --git a/lib/pages/lessons/widgets/lesson_item_widget.dart b/lib/pages/lessons/widgets/lesson_item_widget.dart deleted file mode 100644 index cad8353..0000000 --- a/lib/pages/lessons/widgets/lesson_item_widget.dart +++ /dev/null @@ -1,97 +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_module_entity.dart'; - -import '../../home/courese_module_model.dart'; - -class LessonItemWidget extends StatelessWidget { - const LessonItemWidget({super.key, required this.isSelected, this.model, this.onClickEvent}); - ///是否被选中 - final bool isSelected; - final CourseModuleEntity? model; - final Function()? onClickEvent; - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: () { - if (!isSelected) { - return; - } - onClickEvent?.call(); - }, - child: isSelected?_selectWidget():_unSelectWidget(), - ); - } - - Widget _unSelectWidget() { - return Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage('gendubeij'.assetPng) - ) - ), - child: OwImageWidget( - name: model?.picUrl??'', - ), - ); - } - - Widget _selectWidget() { - return Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage( - 'gendubeij'.assetPng, - ), - fit: BoxFit.fill - ), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: OwImageWidget( - name: model?.picUrl??'', - ), - ), - 10.verticalSpace, - Container( - decoration: BoxDecoration( - color: CourseModuleModel(model?.code??'Phase-1').color, - borderRadius: BorderRadius.circular(6.r), - border: Border.all( - color: const Color(0xFF333333), - width: 1.0 - ) - ), - padding: EdgeInsets.symmetric(horizontal: 10.w), - child: Column( - children: [ - Text( - model?.name??'', - style: TextStyle( - color: Colors.white, - fontSize: 12.sp - ), - ), - Text( - model?.des??'', - maxLines: 1, - style: TextStyle( - color: Colors.white, - fontSize: 12.sp - ), - ) - ], - ), - ) - ], - ), - ); - } -} \ No newline at end of file diff --git a/lib/pages/login/loginpage/login_page.dart b/lib/pages/login/loginpage/login_page.dart index 5ae615d..17e943a 100644 --- a/lib/pages/login/loginpage/login_page.dart +++ b/lib/pages/login/loginpage/login_page.dart @@ -34,7 +34,7 @@ class _LoginPageView extends StatelessWidget { if (state is LoginResultChangeState) { // 调试用 // Navigator.of(context).pushNamed(AppRouteName.home); - pushNamedAndRemoveUntil(AppRouteName.moduleSelect, (route) => false); + pushNamedAndRemoveUntil(AppRouteName.home, (route) => false); } }, child: _buildLoginViewWidget(), diff --git a/lib/pages/module/bloc/module_bloc.dart b/lib/pages/module/bloc/module_bloc.dart new file mode 100644 index 0000000..102d889 --- /dev/null +++ b/lib/pages/module/bloc/module_bloc.dart @@ -0,0 +1,54 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wow_english/common/request/dao/lesson_dao.dart'; +import 'package:wow_english/common/request/exception.dart'; +import 'package:wow_english/models/course_module_entity.dart'; +import 'package:wow_english/utils/loading.dart'; +import 'package:wow_english/utils/toast_util.dart'; + +part 'module_event.dart'; +part 'module_state.dart'; + +class ModuleBloc extends Bloc { + final int pageIndex; + + final PageController pageController; + + int _currentPageIndex = 0; + + int get currentPageIndex => _currentPageIndex; + + List _listData = []; + + List get listData => _listData; + + ModuleBloc(this.pageIndex, this.pageController) : super(ModuleInitial()) { + _currentPageIndex = pageIndex; + on(_pageIndexChange); + on(_requestData); + } + + void _pageIndexChange(PageViewChangeIndexEvent event, Emitter emitter) async { + _currentPageIndex = event.index; + emitter(PageIndexChangeState()); + } + + void _requestData(RequestDataEvent event, Emitter emitter) async { + try { + await loading(() async { + _listData = await LessonDao.courseModule() ?? []; + emitter(ModuleDataLoadState()); + }); + } catch (e) { + if (e is ApiException) { + showToast(e.message ?? '请求失败,请检查网络连接'); + } + } + } + + @override + Future close() { + pageController.dispose(); + return super.close(); + } +} diff --git a/lib/pages/module/bloc/module_event.dart b/lib/pages/module/bloc/module_event.dart new file mode 100644 index 0000000..ab002fa --- /dev/null +++ b/lib/pages/module/bloc/module_event.dart @@ -0,0 +1,11 @@ +part of 'module_bloc.dart'; + +@immutable +abstract class ModuleEvent {} + +class PageViewChangeIndexEvent extends ModuleEvent { + final int index; + PageViewChangeIndexEvent(this.index); +} + +class RequestDataEvent extends ModuleEvent {} diff --git a/lib/pages/module/bloc/module_state.dart b/lib/pages/module/bloc/module_state.dart new file mode 100644 index 0000000..138fe63 --- /dev/null +++ b/lib/pages/module/bloc/module_state.dart @@ -0,0 +1,10 @@ +part of 'module_bloc.dart'; + +@immutable +abstract class ModuleState {} + +class ModuleInitial extends ModuleState {} + +class PageIndexChangeState extends ModuleState {} + +class ModuleDataLoadState extends ModuleState {} diff --git a/lib/pages/module/module_page.dart b/lib/pages/module/module_page.dart new file mode 100644 index 0000000..dc29413 --- /dev/null +++ b/lib/pages/module/module_page.dart @@ -0,0 +1,187 @@ +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/common/widgets/we_app_bar.dart'; +import 'package:wow_english/models/course_module_entity.dart'; +import 'package:wow_english/route/route.dart'; + +import 'bloc/module_bloc.dart'; +import 'widgets/module_item_widget.dart'; + +// 阶段(模块)列表页 +class ModulePage extends StatelessWidget { + const ModulePage({super.key, this.starPageIndex}); + + final int? starPageIndex; + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => ModuleBloc( + starPageIndex ?? 0, + PageController(initialPage: starPageIndex ?? 0, viewportFraction: 0.3), + )..add(RequestDataEvent()), + child: _LessonPageView(), + ); + } +} + +class _LessonPageView extends StatelessWidget { + final double _cardHeight = 240.h; + + final double _scale = 0.8; + + @override + Widget build(BuildContext context) { + return BlocListener( + listener: (context, state) {}, + child: Scaffold( + appBar: WEAppBar( + leading: IconButton( + onPressed: () { + popPage(); + }, + icon: Image.asset( + 'back'.assetPng, + height: 43, + width: 43, + )), + // actions: [ + // IconButton( + // icon: Image.asset('shop'.assetPng), + // color: Colors.white, + // onPressed: () { + // showToast('购买'); + // }, + // ) + // ], + ), + body: _lessViewWidget(), + ), + ); + } + + Widget _lessViewWidget() => + BlocBuilder(builder: (context, state) { + final bloc = BlocProvider.of(context); + return Center( + child: SafeArea( + child: Column( + children: [ + SizedBox( + height: _cardHeight, + child: PageView.builder( + itemCount: bloc.listData.length, + controller: bloc.pageController, + onPageChanged: (int index) { + bloc.add(PageViewChangeIndexEvent(index)); + }, + itemBuilder: (context, index) => _itemTransCard(index)), + ), + 32.verticalSpace, + SizedBox( + height: 32.h, + width: 66.w * bloc.listData.length, + child: ListView.builder( + itemCount: bloc.listData.length, + scrollDirection: Axis.horizontal, + itemBuilder: (BuildContext context, int index) { + return Container( + height: 32.h, + width: 66.w, + padding: const EdgeInsets.symmetric(horizontal: 5), + child: GestureDetector( + onTap: () { + if (index == bloc.currentPageIndex) { + return; + } + int mill = (index - bloc.currentPageIndex) > 0 + ? 100 * (index - bloc.currentPageIndex) + : 100 * (bloc.currentPageIndex - index); + bloc.pageController.animateToPage(index, + duration: Duration(milliseconds: mill), + curve: Curves.ease); + }, + child: Container( + height: bloc.currentPageIndex == index ? 32 : 20, + decoration: BoxDecoration( + color: bloc.currentPageIndex == index + ? Colors.red + : Colors.white, + borderRadius: BorderRadius.circular(5.r), + border: Border.all( + width: 0.5, + color: Colors.black, + ), + ), + alignment: Alignment.center, + child: Text( + (index + 1).toString(), + style: TextStyle( + color: bloc.currentPageIndex == index + ? Colors.white + : Colors.black), + ), + ), + ), + ); + }), + ) + ], + ), + ), + ); + }); + + Widget _itemTransCard(int index) => + BlocBuilder(builder: (context, state) { + final bloc = BlocProvider.of(context); + Matrix4 matrix4 = Matrix4.identity(); + if (index == bloc.currentPageIndex.floor()) { + //当前的item + double currScale = + (1 - (bloc.currentPageIndex - index) * (1 - _scale)).toDouble(); + var currTrans = _cardHeight * (1 - currScale) / 2; + + matrix4 = Matrix4.diagonal3Values(1.0, currScale, 1.0) + ..setTranslationRaw(0.0, currTrans, 0.0); + } else if (index == bloc.currentPageIndex.floor() + 1) { + //右边的item + var currScale = + _scale + (bloc.currentPageIndex - index + 1) * (1 - _scale); + var currTrans = _cardHeight * (1 - currScale) / 2; + + matrix4 = Matrix4.diagonal3Values(1.0, currScale, 1.0) + ..setTranslationRaw(0.0, currTrans, 0.0); + } else if (index == bloc.currentPageIndex - 1) { + //左边 + var currScale = + (1 - (bloc.currentPageIndex - index) * (1 - _scale)).toDouble(); + var currTrans = _cardHeight * (1 - currScale) / 2; + + matrix4 = Matrix4.diagonal3Values(1.0, currScale, 1.0) + ..setTranslationRaw(0.0, currTrans, 0.0); + } else { + //其他,不在屏幕显示的item + matrix4 = Matrix4.diagonal3Values(1.0, _scale, 1.0) + ..setTranslationRaw(0.0, _cardHeight * (1 - _scale) / 2, 0.0); + } + CourseModuleEntity? model = bloc.listData[index]; + return Transform( + transform: matrix4, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: ModuleItemWidget( + model: model, + isSelected: bloc.currentPageIndex == index, + onClickEvent: () { + pushNamedAndRemoveUntil( + AppRouteName.courseUnit, (route) => route.isFirst, + arguments: {'courseModuleEntity': model}); + }, + ), + ), + ); + }); +} diff --git a/lib/pages/module/widgets/module_item_widget.dart b/lib/pages/module/widgets/module_item_widget.dart new file mode 100644 index 0000000..ad7e76b --- /dev/null +++ b/lib/pages/module/widgets/module_item_widget.dart @@ -0,0 +1,97 @@ +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_module_entity.dart'; + +import '../../section/courese_module_model.dart'; + +class ModuleItemWidget extends StatelessWidget { + const ModuleItemWidget({super.key, required this.isSelected, this.model, this.onClickEvent}); + ///是否被选中 + final bool isSelected; + final CourseModuleEntity? model; + final Function()? onClickEvent; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + if (!isSelected) { + return; + } + onClickEvent?.call(); + }, + child: isSelected?_selectWidget():_unSelectWidget(), + ); + } + + Widget _unSelectWidget() { + return Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('gendubeij'.assetPng) + ) + ), + child: OwImageWidget( + name: model?.picUrl??'', + ), + ); + } + + Widget _selectWidget() { + return Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + 'gendubeij'.assetPng, + ), + fit: BoxFit.fill + ), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: OwImageWidget( + name: model?.picUrl??'', + ), + ), + 10.verticalSpace, + Container( + decoration: BoxDecoration( + color: CourseModuleModel(model?.code??'Phase-1').color, + borderRadius: BorderRadius.circular(6.r), + border: Border.all( + color: const Color(0xFF333333), + width: 1.0 + ) + ), + padding: EdgeInsets.symmetric(horizontal: 10.w), + child: Column( + children: [ + Text( + model?.name??'', + style: TextStyle( + color: Colors.white, + fontSize: 12.sp + ), + ), + Text( + model?.des??'', + maxLines: 1, + style: TextStyle( + color: Colors.white, + fontSize: 12.sp + ), + ) + ], + ), + ) + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/pages/moduleSelect/bloc.dart b/lib/pages/moduleSelect/bloc.dart deleted file mode 100644 index 62e25c7..0000000 --- a/lib/pages/moduleSelect/bloc.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:bloc/bloc.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; -import 'package:wow_english/models/app_config_entity.dart'; - -import '../../common/core/app_config_helper.dart'; -import '../../common/request/dao/system_dao.dart'; -import '../../models/app_version_entity.dart'; -import '../../utils/log_util.dart'; -import 'event.dart'; -import 'state.dart'; - -class ModuleSelectBloc extends Bloc { - ModuleSelectBloc() : super(ModuleSelectState().init()) { - on(_init); - } - - void _init(InitEvent event, Emitter emit) async { - await _checkUpdate(emit); - debugPrint('WQF ModuleSelectBloc _init'); - } - - Future _checkUpdate(Emitter emit) async { - if (AppConfigHelper.checkedUpdate) { - return; - } - int localVersion = int.parse(await AppConfigHelper.getAppVersion()); - AppVersionEntity? appVersionEntity = await SystemDao.getVersionInfo(); - AppConfigHelper.checkedUpdate = true; - if (appVersionEntity == null) { - return; - } - Log.d("WQF _checkUpdate appVersionEntity: $appVersionEntity localVersion=$localVersion"); - if (defaultTargetPlatform == TargetPlatform.iOS) { - if (localVersion < int.parse(appVersionEntity.version ?? '0')) { - emit(UpdateDialogState( - appVersionEntity.volType == UpdateStrategy.FORCE.name, appVersionEntity)); - } - } else { - if (localVersion < int.parse(appVersionEntity.version ?? '0')) { - emit(UpdateDialogState( - appVersionEntity.volType == UpdateStrategy.FORCE.name, appVersionEntity)); - } - } - } -} diff --git a/lib/pages/moduleSelect/event.dart b/lib/pages/moduleSelect/event.dart deleted file mode 100644 index 5695068..0000000 --- a/lib/pages/moduleSelect/event.dart +++ /dev/null @@ -1,3 +0,0 @@ -abstract class ModuleSelectEvent {} - -class InitEvent extends ModuleSelectEvent {} \ No newline at end of file diff --git a/lib/pages/moduleSelect/state.dart b/lib/pages/moduleSelect/state.dart deleted file mode 100644 index 98e2581..0000000 --- a/lib/pages/moduleSelect/state.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:wow_english/models/app_version_entity.dart'; - -class ModuleSelectState { - ModuleSelectState init() { - return ModuleSelectState(); - } - - ModuleSelectState clone() { - return ModuleSelectState(); - } -} - -class UpdateDialogState extends ModuleSelectState { - - final AppVersionEntity appVersionEntity; - - final bool forceUpdate; - - UpdateDialogState(this.forceUpdate, this.appVersionEntity); -} diff --git a/lib/pages/moduleSelect/view.dart b/lib/pages/moduleSelect/view.dart deleted file mode 100644 index e191286..0000000 --- a/lib/pages/moduleSelect/view.dart +++ /dev/null @@ -1,238 +0,0 @@ - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_app_update/azhon_app_update.dart'; -import 'package:flutter_app_update/update_model.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:url_launcher/url_launcher.dart'; -import 'package:wow_english/common/core/app_config_helper.dart'; -import 'package:wow_english/common/extension/string_extension.dart'; -import 'package:wow_english/models/app_version_entity.dart'; -import 'package:wow_english/pages/moduleSelect/state.dart'; -import 'package:wow_english/pages/moduleSelect/widgets/BaseHomeHeaderWidget.dart'; -import 'package:wow_english/pages/user/bloc/user_bloc.dart'; - -import '../../common/core/user_util.dart'; -import '../../common/dialogs/show_dialog.dart'; -import '../../utils/log_util.dart'; -import 'bloc.dart'; -import 'event.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:wow_english/route/route.dart'; - -class ModuleSelectPage extends StatelessWidget { - const ModuleSelectPage({super.key}); - - @override - Widget build(BuildContext context) { - return BlocProvider( - create: (BuildContext context) => - ModuleSelectBloc() - ..add(InitEvent()), - child: Builder(builder: (context) => _HomePageView()), - ); - } -} - -class _HomePageView extends StatelessWidget { - @override - Widget build(BuildContext context) { - return MultiBlocListener(listeners: [ - BlocListener(listener: (context, state) { - debugPrint('WQF ModuleSelectPage BlocListener state: $state'); - }), - BlocListener( - listener: (context, state) { - if (state is UpdateDialogState) { - _showUpdateDialog(context, state.forceUpdate, state.appVersionEntity); - } - }, - ), - ], child: _homeView()); - } - - Widget _homeView() => - BlocBuilder( - builder: (context, state) { - return Scaffold( - body: Container( - color: Colors.white, - child: Column( - children: [ - const BaseHomeHeaderWidget(), - Expanded( - child: Center( - child: Row( - children: [ - Expanded( - child: GestureDetector( - onTap: () { - if (UserUtil.isLogined()) { - pushNamed(AppRouteName.home); - } else { - pushNamed(AppRouteName.login); - } - }, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Stack( - alignment: AlignmentDirectional.center, - children: [ - Image.asset( - 'bg_frame_module'.assetPng, - width: 162.5.w, height: 203.5.h), - Center( - child: Image.asset( - 'pic_module_study'.assetPng, - width: 140.5.w, - height: 172.h), - ) - ]), - 10.verticalSpace, - Image.asset('label_module_study'.assetPng, - width: 124.w, height: 34.h), - ], - ), - ), - ), - Expanded( - child: BlocBuilder( - builder: (context, userState) { - debugPrint( - 'WQF ModuleSelectPage BlocBuilder state: $userState'); - return GestureDetector( - onTap: () { - //如果没登录先登录 - if (UserUtil.isLogined()) { - if (AppConfigHelper - .shouldHidePay()) { - pushNamed(AppRouteName.games); - } else { - if (UserUtil - .hasGamePermission()) { - pushNamed(AppRouteName.games); - } else { - showTwoActionDialog( - '提示', '忽略', '去续费', - '您的课程已到期,请快快续费继续学习吧!', - leftTap: () { - popPage(); - }, rightTap: () { - popPage(); - pushNamed(AppRouteName.shop); - }); - } - } - } else { - pushNamed(AppRouteName.login); - } - }, - child: Column( - mainAxisAlignment: MainAxisAlignment - .center, - children: [ - Stack( - alignment: AlignmentDirectional - .center, - children: [ - Image.asset( - 'bg_frame_module' - .assetPng, - width: 162.5.w, - height: 203.5.h), - Image.asset( - 'pic_module_game' - .assetPng, - width: 140.5.w, - height: 172.h) - ]), - 10.verticalSpace, - Image.asset( - 'label_module_game'.assetPng, - width: 124.w, height: 34.h), - ], - )); - }), - ), - ], - ), - ), - ) - ], - ), - ), - ); - }); - - - ///Flutter侧处理升级对话框 - ///[forcedUpgrade] 是否强制升级 - _showUpdateDialog(BuildContext context, bool forcedUpgrade, - AppVersionEntity appVersionEntity) { - showDialog( - context: context, - // 当我们点击除开对话框内容以外的区域是否关闭对话需用用到barrierDismissible参数 . 这个参数默认值是true ,但不能为null . - barrierDismissible: !forcedUpgrade, - builder: (BuildContext context) { - return WillPopScope( - onWillPop: () => Future.value(!forcedUpgrade), - child: AlertDialog( - title: const Text('发现新版本'), - content: Text( - appVersionEntity.remark ?? - '修复了一些已知问题'), - actions: [ - TextButton( - child: Text(forcedUpgrade ? '退出' : '取消'), - onPressed: () => - { - if (forcedUpgrade) { - AppConfigHelper.exitApp() - } else - { - Navigator.of(context).pop() - } - }, - ), - TextButton( - child: const Text('升级'), - onPressed: () async { - if (defaultTargetPlatform == TargetPlatform.iOS) { - _launchAppStore("6450870731"); - return; - } - final String? apkUrl = appVersionEntity.packageUrl; - if (apkUrl == null || apkUrl.isEmpty) { - return; - } - UpdateModel model = UpdateModel( - apkUrl, - "wowenglish.apk", - "ic_launcher", - '', - ); - AzhonAppUpdate.update(model).then((value) => - debugPrint('$value')); - if (!forcedUpgrade) { - Navigator.of(context).pop(); - } - }, - ), - ], - ), - ); - }, - ); - } - - void _launchAppStore(String appId) async { - final String url = 'https://apps.apple.com/cn/app/wow-english/id$appId'; - if (await canLaunchUrl(Uri.parse(url))) { - await launchUrl(Uri.parse(url)); - } else { - throw 'Could not launch $url'; - } - } -} diff --git a/lib/pages/moduleSelect/widgets/BaseHomeHeaderWidget.dart b/lib/pages/moduleSelect/widgets/BaseHomeHeaderWidget.dart deleted file mode 100644 index 11a2ccf..0000000 --- a/lib/pages/moduleSelect/widgets/BaseHomeHeaderWidget.dart +++ /dev/null @@ -1,108 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:wow_english/common/core/app_config_helper.dart'; -import 'package:wow_english/common/extension/string_extension.dart'; - -import '../../../common/core/user_util.dart'; -import '../../../models/course_entity.dart'; -import '../../../route/route.dart'; -import '../../../utils/image_util.dart'; -import '../../user/bloc/user_bloc.dart'; - -class BaseHomeHeaderWidget extends StatelessWidget { - const BaseHomeHeaderWidget({super.key, this.entity}); - - final CourseEntity? entity; - - @override - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - return Container( - height: 45, - width: double.infinity, - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage('bg_header_sliver'.assetPng), - fit: BoxFit.cover, - ), - ), - padding: EdgeInsets.symmetric(horizontal: 9.5.w), - child: Row( - children: [ - ScreenUtil().bottomBarHeight.horizontalSpace, - GestureDetector( - onTap: () => {onUserClick()}, - child: Container( - decoration: BoxDecoration( - border: Border.all( - width: 1.0, - color: const Color(0xFF140C10), - ), - borderRadius: BorderRadius.circular(21), - ), - child: CircleAvatar( - radius: 21, - backgroundImage: ImageUtil.getImageProviderOnDefault( - UserUtil.getUser()?.avatarUrl), - ), - ), - ), - GestureDetector( - onTap: () { - onUserClick(); - }, - child: Container( - margin: const EdgeInsets.only(left: 7), - padding: const EdgeInsets.all(4.0), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(2), - border: Border.all( - width: 1.0, - color: const Color(0xFF140C10), - style: BorderStyle.solid), - ), - child: Text( - UserUtil.getUser()?.name ?? '未登录', - style: TextStyle( - color: const Color(0xFF333333), fontSize: 16.sp), - ), - ), - ), - 20.horizontalSpace, - const Expanded( - child: Text( - "WOW ENGLISH", - textAlign: TextAlign.left, - style: TextStyle(color: Colors.white, fontSize: 30.0), - )), - Offstage( - offstage: AppConfigHelper.shouldHidePay(), - child: Row(children: [ - Image( - width: 20.0.w, - height: 20.0.h, - image: AssetImage('ic_countdown'.assetPng)), - // 替换为你的图片资源路径 - const SizedBox(width: 10.0), - // 图片和文本之间的间隔 - Text('还剩${UserUtil.getRemainingValidity()}天'), - ]), - ), - ScreenUtil().bottomBarHeight.horizontalSpace, - ], - )); - }, - ); - } -} - -void onUserClick() { - if (UserUtil.isLogined()) { - pushNamed(AppRouteName.user); - } else { - pushNamed(AppRouteName.login); - } -} diff --git a/lib/pages/section/bloc/section_bloc.dart b/lib/pages/section/bloc/section_bloc.dart new file mode 100644 index 0000000..ef3b3f0 --- /dev/null +++ b/lib/pages/section/bloc/section_bloc.dart @@ -0,0 +1,85 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_bloc/flutter_bloc.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/models/course_process_entity.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'; + +part 'section_event.dart'; +part 'section_state.dart'; + +class SectionBloc extends Bloc { + + CourseUnitEntity _courseUnitEntity; + + CourseUnitEntity get courseUnitEntity => _courseUnitEntity; + + CourseUnitDetail _courseUnitDetail; + + CourseUnitDetail get courseUnitDetail => _courseUnitDetail; + + List? _courseSectionDatas; + + List? get courseSectionDatas => _courseSectionDatas; + + CourseProcessEntity? _processEntity; + + CourseProcessEntity? get processEntity => _processEntity; + + SectionBloc(this._courseUnitEntity, this._courseUnitDetail) : super(LessonInitial()) { + on(_requestData); + on(_requestExitClass); + on(_requestEnterClass); + on(_requestVideoLesson); + } + + void _requestData(RequestDataEvent event, Emitter emitter) async { + try { + await loading(() async { + _courseSectionDatas = await LessonDao.courseSection(courseUnitId: _courseUnitDetail.id!); + emitter(LessonDataLoadState()); + }); + } catch (e) { + if (e is ApiException) { + showToast(e.message.toString()); + } + } + } + + void _requestVideoLesson(RequestVideoLessonEvent event, Emitter emitter) async { + try { + await loading(() async { + _processEntity = await ListenDao.process(event.courseLessonId); + emitter(RequestVideoLessonState(event.courseLessonId,event.courseType)); + }); + } catch (e) { + if (e is ApiException) { + showToast(e.message??'请求失败,请检查网络连接'); + } + } + } + + + void _requestEnterClass(RequestEnterClassEvent event,Emitter emitter) async { + try { + await loading(() async { + await ListenDao.enterClass(event.courseLessonId); + emitter(RequestEnterClassState(event.courseLessonId,event.courseType)); + }); + } catch (e) { + if (e is ApiException) { + showToast(e.message??'请求失败,请检查网络连接'); + } + } + } + + void _requestExitClass(RequestExitClassEvent event,Emitter emitter) async { + await ListenDao.exitClass(event.courseLessonId,event.currentStep,event.currentTime); + } +} diff --git a/lib/pages/section/bloc/section_event.dart b/lib/pages/section/bloc/section_event.dart new file mode 100644 index 0000000..cff955d --- /dev/null +++ b/lib/pages/section/bloc/section_event.dart @@ -0,0 +1,28 @@ +part of 'section_bloc.dart'; + +@immutable +abstract class SectionEvent {} + +class RequestDataEvent extends SectionEvent {} + +///获取视频课程内容 +class RequestVideoLessonEvent extends SectionEvent { + final String courseLessonId; + final int courseType; + RequestVideoLessonEvent(this.courseLessonId, this.courseType); +} + +///进入课堂 +class RequestEnterClassEvent extends SectionEvent { + final String courseLessonId; + final int courseType; + RequestEnterClassEvent(this.courseLessonId,this.courseType); +} + +///退出课堂 +class RequestExitClassEvent extends SectionEvent { + final String courseLessonId; + final String currentStep; + final String currentTime; + RequestExitClassEvent(this.courseLessonId,this.currentStep,this.currentTime); +} diff --git a/lib/pages/section/bloc/section_state.dart b/lib/pages/section/bloc/section_state.dart new file mode 100644 index 0000000..9c50452 --- /dev/null +++ b/lib/pages/section/bloc/section_state.dart @@ -0,0 +1,20 @@ +part of 'section_bloc.dart'; + +@immutable +abstract class SectionState {} + +class LessonInitial extends SectionState {} + +class LessonDataLoadState extends SectionState {} + +class RequestVideoLessonState extends SectionState { + final String courseLessonId; + final int type; + RequestVideoLessonState(this.courseLessonId,this.type); +} + +class RequestEnterClassState extends SectionState{ + final String courseLessonId; + final int courseType; + RequestEnterClassState(this.courseLessonId,this.courseType); +} diff --git a/lib/pages/section/courese_module_model.dart b/lib/pages/section/courese_module_model.dart new file mode 100644 index 0000000..91db786 --- /dev/null +++ b/lib/pages/section/courese_module_model.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; + +class CourseModuleModel { + Color get color => getCourseColor(); + + String get courseModuleTitle => getCourseModuleTitle(); + + String get courseModuleLogo => getCoureseImageName(); + + String course; + + CourseModuleModel(this.course); + + Color getCourseColor() { + if (course == 'Phase-1') { + return Colors.yellow; + } + if (course == 'Phase-2') { + return Colors.red; + } + if (course == 'Phase-3') { + return Colors.blue; + } + if (course == 'Phase-4') { + return Colors.green; + } + if (course == 'Phase-5') { + return Colors.orange; + } + if (course == 'Phase-6') { + return const Color(0XFFC07347); + } + if (course == 'Phase-7') { + return const Color(0xFFA3A2A2); + } + return Colors.red; + } + + String getCourseModuleTitle() { + if (course == 'Phase-1') { + return 'learn wow! yellow'; + } + if (course == 'Phase-2') { + return 'learn wow! red'; + } + if (course == 'Phase-3') { + return 'learn wow! blue'; + } + if (course == 'Phase-4') { + return 'learn wow! green'; + } + if (course == 'Phase-5') { + return 'learn wow! orange'; + } + if (course == 'Phase-6') { + return 'learn wow! bronze'; + } + if (course == 'Phase-7') { + return 'learn wow! silver'; + } + return 'learn wow! red'; + } + + String getCoureseImageName() { + if (course == 'Phase-1') { + return 'yellow_positive'; + } + if (course == 'Phase-2') { + return 'red_positive'; + } + if (course == 'Phase-3') { + return 'blue_positive'; + } + if (course == 'Phase-4') { + return 'learn wow! green'; + } + if (course == 'Phase-5') { + return 'orange_positive'; + } + if (course == 'Phase-6') { + return 'bronze_positive'; + } + if (course == 'Phase-7') { + return 'silver_positive'; + } + return 'red_positive'; + } +} diff --git a/lib/pages/section/section_page.dart b/lib/pages/section/section_page.dart new file mode 100644 index 0000000..edf88c1 --- /dev/null +++ b/lib/pages/section/section_page.dart @@ -0,0 +1,232 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:wow_english/common/core/user_util.dart'; +import 'package:wow_english/common/extension/string_extension.dart'; +import 'package:wow_english/models/course_unit_entity.dart'; +import 'package:wow_english/pages/section/widgets/home_video_item.dart'; +import 'package:wow_english/pages/section/widgets/section_bouns_item.dart'; +import 'package:wow_english/pages/section/widgets/section_header_widget.dart'; +import 'package:wow_english/route/route.dart'; +import 'package:wow_english/utils/toast_util.dart'; + +import '../../models/course_section_entity.dart'; +import 'bloc/section_bloc.dart'; +import 'courese_module_model.dart'; + +/// 环节列表页 +class SectionPage extends StatelessWidget { + const SectionPage({super.key, required this.courseUnitEntity, required this.courseUnitDetail}); + + final CourseUnitEntity courseUnitEntity; + + /// unitId + final CourseUnitDetail courseUnitDetail; + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => SectionBloc(courseUnitEntity, courseUnitDetail)..add(RequestDataEvent()), + child: _SectionPageView(context), + ); + } +} + +class _SectionPageView extends StatelessWidget { + const _SectionPageView(this.context); + + final BuildContext context; + + @override + Widget build(BuildContext context) { + final bloc = BlocProvider.of(context); + return BlocListener( + listener: (context, state) { + if (state is RequestVideoLessonState) { + final videoUrl = bloc.processEntity?.videos?.videoUrl ?? ''; + var title = ''; + if (state.type == 1) { + title = 'song'; + } + + if (state.type == 2) { + title = 'video'; + } + + if (state.type == 5) { + title = 'bonus'; + } + + if (videoUrl.isEmpty || !videoUrl.contains('http')) { + return; + } + pushNamed(AppRouteName.lookVideo, arguments: { + 'videoUrl': videoUrl, + 'title': title, + 'courseLessonId': state.courseLessonId + }).then((value) { + if (value != null) { + Map dataMap = value as Map; + bloc.add(RequestExitClassEvent( + dataMap['courseLessonId']!, + '0', + dataMap['currentTime']!, + )); + } + }); + return; + } + + if (state is RequestEnterClassState) { + if (state.courseType != 3 && state.courseType != 4) { + ///视频类型 + ///获取视频课程内容 + bloc.add(RequestVideoLessonEvent( + state.courseLessonId, state.courseType)); + return; + } + + if (state.courseType == 4) { + //绘本 + pushNamed(AppRouteName.reading, + arguments: {'courseLessonId': state.courseLessonId}) + .then((value) { + if (value != null) { + Map dataMap = value as Map; + bloc.add(RequestExitClassEvent( + dataMap['courseLessonId']!, dataMap['currentStep']!, '0')); + } + }); + return; + } + + if (state.courseType == 3) { + //练习 + pushNamed(AppRouteName.topicPic, + arguments: {'courseLessonId': state.courseLessonId}) + .then((value) { + if (value != null) { + Map dataMap = value as Map; + bloc.add(RequestExitClassEvent( + dataMap['courseLessonId']!, dataMap['currentStep']!, '0')); + } + }); + return; + } + } + }, + child: _homeView(), + ); + } + + Widget _homeView() => + BlocBuilder(builder: (context, state) { + final bloc = BlocProvider.of(context); + return Scaffold( + body: Container( + color: Colors.white, + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SectionHeaderWidget( + title: bloc.courseUnitDetail.name, + courseModuleCode: bloc.courseUnitEntity.courseModuleCode), + Expanded( + child: ListView.builder( + itemCount: bloc.courseSectionDatas?.length ?? 0, + scrollDirection: Axis.horizontal, + itemBuilder: (BuildContext context, int index) { + CourseSectionEntity sectionData = + bloc.courseSectionDatas![index]; + if (sectionData.courseType == 5) { + //彩蛋 + return GestureDetector( + onTap: () { + if (!UserUtil.isLogined()) { + pushNamed(AppRouteName.login); + return; + } + if (sectionData.lock == true) { + showToast('当前课程暂未解锁'); + return; + } + + ///进入课堂 + bloc.add(RequestEnterClassEvent( + sectionData.id.toString(), sectionData.courseType)); + }, + child: SectionBoundsItem( + imageUrl: sectionData.coverUrl, + ), + ); + } else { + return GestureDetector( + onTap: () { + if (!UserUtil.isLogined()) { + pushNamed(AppRouteName.login); + return; + } + if (sectionData.lock == true) { + showToast('当前课程暂未解锁'); + return; + } + + ///进入课堂 + bloc.add(RequestEnterClassEvent( + sectionData.id.toString(), sectionData.courseType)); + }, + child: SectionVideoItem( + unitEntity: bloc.courseUnitEntity, + lessons: sectionData, + ), + ); + } + })), + SafeArea( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 13.w), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + height: 47.h, + width: 80.w, + ), + Container( + decoration: BoxDecoration( + color: CourseModuleModel( + bloc.courseUnitEntity.courseModuleCode ?? + 'Phase-1') + .color, + borderRadius: BorderRadius.circular(14.5.r), + ), + padding: EdgeInsets.symmetric( + vertical: 8.h, horizontal: 24.w), + child: Text( + '${(bloc.courseUnitEntity.nowStep ?? 0)}/${bloc.courseUnitEntity.total ?? 0}', + style: TextStyle( + color: Colors.white, fontSize: 12.sp), + ), + ), + Image.asset( + CourseModuleModel( + bloc.courseUnitEntity.courseModuleCode ?? + 'Phase-1') + .courseModuleLogo + .assetPng, + height: 47.h, + width: 80.w, + // color: Colors.red, + ), + ], + ), + ), + ) + ], + ), + ), + ), + ); + }); +} diff --git a/lib/pages/section/widgets/home_video_item.dart b/lib/pages/section/widgets/home_video_item.dart new file mode 100644 index 0000000..7542f42 --- /dev/null +++ b/lib/pages/section/widgets/home_video_item.dart @@ -0,0 +1,72 @@ +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_section_entity.dart'; +import '../../../models/course_unit_entity.dart'; +import '../courese_module_model.dart'; + +class SectionVideoItem extends StatelessWidget { + const SectionVideoItem({super.key, this.lessons, this.unitEntity}); + + final CourseUnitEntity? unitEntity; + final CourseSectionEntity? 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(unitEntity?.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/section/widgets/section_bouns_item.dart b/lib/pages/section/widgets/section_bouns_item.dart new file mode 100644 index 0000000..f9e779c --- /dev/null +++ b/lib/pages/section/widgets/section_bouns_item.dart @@ -0,0 +1,18 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:wow_english/common/widgets/ow_image_widget.dart'; + +class SectionBoundsItem extends StatelessWidget { + const SectionBoundsItem({super.key, this.imageUrl}); + + final String? imageUrl; + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 207.h, + width: 169.w, + child: OwImageWidget(name:imageUrl??''), + ); + } +} \ No newline at end of file diff --git a/lib/pages/section/widgets/section_header_widget.dart b/lib/pages/section/widgets/section_header_widget.dart new file mode 100644 index 0000000..91833df --- /dev/null +++ b/lib/pages/section/widgets/section_header_widget.dart @@ -0,0 +1,56 @@ +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 '../courese_module_model.dart'; + +class SectionHeaderWidget extends StatelessWidget { + const SectionHeaderWidget({super.key, this.title, this.courseModuleCode}); + + final String? title; + + final String? courseModuleCode; + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + return Container( + height: 45, + width: double.infinity, + color: CourseModuleModel(courseModuleCode ?? '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( + title ?? + CourseModuleModel(courseModuleCode ?? 'Phase-1') + .courseModuleTitle, + textAlign: TextAlign.left, + style: const TextStyle(color: Colors.white, fontSize: 30.0), + )), + ScreenUtil().bottomBarHeight.horizontalSpace, + ], + )); + }, + ); + } +} diff --git a/lib/pages/tab/tab_page.dart b/lib/pages/tab/tab_page.dart index 143d8f3..70ad7e7 100644 --- a/lib/pages/tab/tab_page.dart +++ b/lib/pages/tab/tab_page.dart @@ -1,16 +1,16 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:wow_english/pages/home/home_page.dart'; -import 'package:wow_english/pages/lessons/lesson_page.dart'; +import 'package:wow_english/pages/module/module_page.dart'; +import '../unit/view.dart'; import 'blocs/tab_bloc.dart'; class TabPage extends StatelessWidget { const TabPage({super.key}); final _pages =const [ - HomePage(), - LessonPage() + UnitPage(), + ModulePage() ]; final _tabIcons = const [ diff --git a/lib/pages/unit/bloc.dart b/lib/pages/unit/bloc.dart index 767b510..d54cd60 100644 --- a/lib/pages/unit/bloc.dart +++ b/lib/pages/unit/bloc.dart @@ -1,8 +1,11 @@ import 'package:bloc/bloc.dart'; +import 'package:wow_english/pages/unit/widget/home_tab_header_widget.dart'; -import '../../common/request/dao/home_dao.dart'; +import '../../common/request/dao/lesson_dao.dart'; import '../../common/request/exception.dart'; +import '../../models/course_module_entity.dart'; import '../../models/course_unit_entity.dart'; +import '../../route/route.dart'; import '../../utils/loading.dart'; import '../../utils/toast_util.dart'; import 'event.dart'; @@ -10,19 +13,23 @@ import 'state.dart'; class UnitBloc extends Bloc { - CourseUnitEntity? _modelData; + CourseModuleEntity? _moduleEntity; - CourseUnitEntity? get modelData => _modelData; + CourseModuleEntity? get moduleEntity => _moduleEntity; + CourseUnitEntity? _unitData; - UnitBloc() : super(UnitState().init()) { + CourseUnitEntity? get unitData => _unitData; + + + UnitBloc(CourseModuleEntity? courseEntity) : super(UnitState().init()) { on(_requestData); } void _requestData(RequestUnitDataEvent event, Emitter emitter) async { try { await loading(() async { - _modelData = await HomeDao.courseUnit(event.moduleId); + _unitData = await LessonDao.courseUnit(event.moduleId); emitter(UnitDataLoadState()); }); } catch (e) { @@ -31,4 +38,22 @@ class UnitBloc extends Bloc { } } } + + String? getCourseModuleCode() { + return _moduleEntity?.code ?? _unitData?.courseModuleCode; + } + + void headerActionEvent(HeaderActionType type) { + if (type == HeaderActionType.video) { + pushNamed(AppRouteName.reAfter); + } else if (type == HeaderActionType.phase) { + pushNamed(AppRouteName.courseModule); + } else if (type == HeaderActionType.listen) { + pushNamed(AppRouteName.listen); + } else if (type == HeaderActionType.shop) { + pushNamed(AppRouteName.shop); + } else if (type == HeaderActionType.user) { + pushNamed(AppRouteName.user); + } + } } diff --git a/lib/pages/unit/event.dart b/lib/pages/unit/event.dart index 6acbed4..53a8b93 100644 --- a/lib/pages/unit/event.dart +++ b/lib/pages/unit/event.dart @@ -2,7 +2,7 @@ abstract class UnitEvent {} // 获取课程单元数据 class RequestUnitDataEvent extends UnitEvent { - final int moduleId; + final int? moduleId; RequestUnitDataEvent(this.moduleId); } diff --git a/lib/pages/unit/view.dart b/lib/pages/unit/view.dart index fb24b78..f61d56b 100644 --- a/lib/pages/unit/view.dart +++ b/lib/pages/unit/view.dart @@ -2,8 +2,8 @@ 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/pages/unit/widget/home_tab_header_widget.dart'; import 'package:wow_english/route/route.dart'; import '../../models/course_module_entity.dart'; @@ -12,17 +12,18 @@ import '../../utils/toast_util.dart'; import 'bloc.dart'; import 'event.dart'; +// 课程列表页(多unit,参考口语星球的框或分割标志) class UnitPage extends StatelessWidget { - const UnitPage({super.key, required this.courseEntity}); + const UnitPage({super.key, this.courseModuleEntity}); /// 模块 - final CourseModuleEntity courseEntity; + final CourseModuleEntity? courseModuleEntity; @override Widget build(BuildContext context) { return BlocProvider( - create: (BuildContext context) => - UnitBloc()..add(RequestUnitDataEvent(courseEntity.id)), + create: (BuildContext context) => UnitBloc(courseModuleEntity) + ..add(RequestUnitDataEvent(courseModuleEntity?.id)), child: Builder(builder: (context) => _buildPage(context)), ); } @@ -37,36 +38,42 @@ class UnitPage extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - CourseUnitHeaderWidget(entity: courseEntity), + HomeTabHeaderWidget( + courseModuleCode: bloc.getCourseModuleCode(), + actionTap: (HeaderActionType type) { + bloc.headerActionEvent(type); + }, + ), 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; - } + child: Container( + margin: EdgeInsets.symmetric(horizontal: 12.w), + child: ListView.builder( + itemCount: + bloc.unitData?.courseUnitVOList?.length ?? 0, + scrollDirection: Axis.horizontal, + itemBuilder: (BuildContext context, int index) { + CourseUnitDetail? data = + bloc.unitData?.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!, - ), - ); - })), + pushNamed(AppRouteName.courseSection, + arguments: { + 'courseUnitEntity': bloc.unitData, + 'courseUnitDetail': data + }); + }, + child: CourseUnitItem( + unitEntity: bloc.unitData!, + unitLesson: data!, + ), + ); + })), + ), SafeArea( child: Column( children: [ diff --git a/lib/pages/unit/widget/course_unit_header_widget.dart b/lib/pages/unit/widget/course_unit_header_widget.dart deleted file mode 100644 index 47c3866..0000000 --- a/lib/pages/unit/widget/course_unit_header_widget.dart +++ /dev/null @@ -1,55 +0,0 @@ -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/home_tab_header_widget.dart b/lib/pages/unit/widget/home_tab_header_widget.dart new file mode 100644 index 0000000..465f8c9 --- /dev/null +++ b/lib/pages/unit/widget/home_tab_header_widget.dart @@ -0,0 +1,137 @@ +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 '../../../common/core/app_config_helper.dart'; +import '../../section/courese_module_model.dart'; + +enum HeaderActionType { + //视频跟读 + video, + //阶段选择 + phase, + //磨耳朵 + listen, + //购买 + shop, + //个人信息 + user, +} + +class HomeTabHeaderWidget extends StatelessWidget { + const HomeTabHeaderWidget({super.key, this.courseModuleCode, this.actionTap}); + + final String? courseModuleCode; + + final Function(HeaderActionType type)? actionTap; + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + return Container( + height: 45, + width: double.infinity, + color: + CourseModuleModel(courseModuleCode ?? '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, + ), + ), + ), + // GestureDetector( + // onTap: () => actionTap?.call(HeaderActionType.user), + // child: Container( + // decoration: BoxDecoration( + // border: Border.all( + // width: 1.0, + // color: const Color(0xFF140C10), + // ), + // borderRadius: BorderRadius.circular(21), + // ), + // child: CircleAvatar( + // radius: 21, + // backgroundImage: ImageUtil.getImageProviderOnDefault(UserUtil.getUser()?.avatarUrl), + // ), + // ), + // ), + // GestureDetector( + // onTap: () { + // if (actionTap != null) { + // actionTap!(HeaderActionType.user); + // } + // }, + // child: Container( + // margin: const EdgeInsets.only(left: 7), + // padding: const EdgeInsets.all(4.0), + // decoration: BoxDecoration( + // color: Colors.white, + // borderRadius: BorderRadius.circular(2), + // border: Border.all(width: 1.0, color: const Color(0xFF140C10), style: BorderStyle.solid), + // ), + // child: Text( + // UserUtil.getUser()?.name ?? '未登录', + // style: TextStyle(color: const Color(0xFF333333), fontSize: 16.sp), + // ), + // ), + // ), + 20.horizontalSpace, + Expanded( + child: Text( + CourseModuleModel(courseModuleCode ?? 'Phase-1') + .courseModuleTitle, + textAlign: TextAlign.left, + style: const TextStyle(color: Colors.white, fontSize: 30.0), + )), + // IconButton( + // onPressed: () { + // if (actionTap != null) { + // actionTap!(HeaderActionType.video); + // } + // }, + // icon: Image.asset('video'.assetPng)), + IconButton( + onPressed: () { + if (actionTap != null) { + actionTap!(HeaderActionType.phase); + } + }, + icon: Image.asset('home'.assetPng)), + IconButton( + onPressed: () { + if (actionTap != null) { + actionTap!(HeaderActionType.listen); + } + }, + icon: Image.asset('listen'.assetPng)), + Offstage( + offstage: AppConfigHelper.shouldHidePay(), + child: IconButton( + onPressed: () { + if (actionTap != null) { + actionTap!(HeaderActionType.shop); + } + }, + icon: Image.asset('shop'.assetPng)), + ), + ScreenUtil().bottomBarHeight.horizontalSpace, + ], + )); + }, + ); + } +} diff --git a/lib/route/route.dart b/lib/route/route.dart index 0a987c3..49020a9 100644 --- a/lib/route/route.dart +++ b/lib/route/route.dart @@ -3,22 +3,21 @@ import 'package:flutter/material.dart'; import 'package:wow_english/app/splash_page.dart'; import 'package:wow_english/common/pages/wow_web_page.dart'; import 'package:wow_english/generated/json/base/json_convert_content.dart'; +import 'package:wow_english/models/course_unit_entity.dart'; import 'package:wow_english/models/product_entity.dart'; import 'package:wow_english/pages/games/view.dart'; -import 'package:wow_english/pages/home/home_page.dart'; -import 'package:wow_english/pages/lessons/lesson_page.dart'; +import 'package:wow_english/pages/home/view.dart'; import 'package:wow_english/pages/listen/listen_page.dart'; import 'package:wow_english/pages/login/forgetpwd/forget_password_home_page.dart'; import 'package:wow_english/pages/login/loginpage/login_page.dart'; import 'package:wow_english/pages/login/setpwd/set_pwd_page.dart'; -import 'package:wow_english/pages/moduleSelect/view.dart'; +import 'package:wow_english/pages/module/module_page.dart'; import 'package:wow_english/pages/practice/topic_picture_page.dart'; import 'package:wow_english/pages/repeatafter/repeat_after_page.dart'; import 'package:wow_english/pages/repeataftercontent/repeat_after_content_page.dart'; import 'package:wow_english/pages/shop/exchane/exchange_lesson_page.dart'; import 'package:wow_english/pages/shop/exchangelist/exchange_lesson_list_page.dart'; import 'package:wow_english/pages/shop/home/shop_home_page.dart'; -import 'package:wow_english/pages/tab/tab_page.dart'; import 'package:wow_english/pages/user/information/user_information_page.dart'; import 'package:wow_english/pages/user/modify/modify_user_avatar_page.dart'; import 'package:wow_english/pages/user/modify/modify_user_information_page.dart'; @@ -28,7 +27,9 @@ 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/section/section_page.dart'; import '../pages/shopping/view.dart'; +import '../pages/tab/tab_page.dart'; import '../pages/unit/view.dart'; import '../pages/user/setting/delete_account_page.dart'; import '../pages/user/setting/reback_page.dart'; @@ -36,16 +37,16 @@ import '../pages/user/setting/reback_page.dart'; class AppRouteName { static const String splash = 'splash'; static const String login = 'login'; - static const String moduleSelect = 'moduleSelect'; - static const String games = 'games'; static const String home = 'home'; + static const String games = 'games'; static const String fogPwd = 'fogPwd'; /// 设置密码,修改密码;不要自己调用,使用[SetPassWordPage.push]方法,隐藏这种实现 //static const String setPwd = 'setPwd'; static const String webView = 'webView'; - static const String unit = 'courseUnits'; - static const String lesson = 'courseModules'; + static const String courseModule = 'courseModules'; + static const String courseUnit = 'courseUnits'; + static const String courseSection = 'courseSections'; static const String listen = 'listen'; static const String shop = 'shop'; static const String exLesson = 'exLesson'; @@ -57,6 +58,7 @@ class AppRouteName { /// 用户详细信息页 static const String userInformation = 'userInformation'; + /// 修改用户头像 static const String userAvatar = 'userAvatar'; @@ -64,15 +66,19 @@ class AppRouteName { //static const String userModifyInformation = 'userModifyInformation'; ///看视频 static const String lookVideo = 'lookVideo'; + ///绘本 static const String reading = 'reading'; + ///视频跟读详情 static const String readAfterContent = 'readAfterContent'; ///设置 static const String setting = 'setting'; + ///注销账号 static const String deleteAccount = 'deleteAccount'; + ///帮助与反馈 static const String reBack = 'reBack'; @@ -95,31 +101,42 @@ class AppRouter { transitionsBuilder: (_, __, ___, child) => child); case AppRouteName.login: // 是否默认密码登录,修改密码后跳登录页,优先密码登录体验好点 - final bool showPasswordPage = (settings.arguments as Map?)?.getOrNull('showPasswordPage') as bool? ?? false; - return CupertinoPageRoute(builder: (_) => LoginPage(preferencesPasswordLogin: showPasswordPage)); - case AppRouteName.moduleSelect: - return CupertinoPageRoute(builder: (_) => const ModuleSelectPage()); + final bool showPasswordPage = (settings.arguments as Map?) + ?.getOrNull('showPasswordPage') as bool? ?? + false; + return CupertinoPageRoute( + builder: (_) => + LoginPage(preferencesPasswordLogin: showPasswordPage)); + case AppRouteName.home: + return CupertinoPageRoute(builder: (_) => const HomePage()); case AppRouteName.games: return CupertinoPageRoute(builder: (_) => const GamesPage()); - case AppRouteName.home: - int? moduleId; + case AppRouteName.fogPwd: + return CupertinoPageRoute( + builder: (_) => const ForgetPasswordHomePage()); + case AppRouteName.courseModule: + return CupertinoPageRoute(builder: (_) => const ModulePage()); + case AppRouteName.courseUnit: + CourseModuleEntity courseModuleEntity = CourseModuleEntity(); if (settings.arguments != null) { - moduleId = (settings.arguments as Map).getOrNull('moduleId') as int?; + courseModuleEntity = (settings.arguments as Map) + .getOrNull('courseModuleEntity') as CourseModuleEntity; } return CupertinoPageRoute( - builder: (_) => HomePage( - moduleId: moduleId, - )); - case AppRouteName.fogPwd: - return CupertinoPageRoute(builder: (_) => const ForgetPasswordHomePage()); - case AppRouteName.lesson: - return CupertinoPageRoute(builder: (_) => const LessonPage()); - case AppRouteName.unit: - CourseModuleEntity courseEntity = CourseModuleEntity(); + builder: (_) => UnitPage(courseModuleEntity: courseModuleEntity)); + case AppRouteName.courseSection: + CourseUnitEntity courseUnitEntity = CourseUnitEntity(); + CourseUnitDetail courseUnitDetail = CourseUnitDetail(); if (settings.arguments != null) { - courseEntity = (settings.arguments as Map).getOrNull('courseModuleEntity') as CourseModuleEntity; + courseUnitEntity = (settings.arguments as Map) + .getOrNull('courseUnitEntity') as CourseUnitEntity; + courseUnitDetail = (settings.arguments as Map) + .getOrNull('courseUnitDetail') as CourseUnitDetail; } - return CupertinoPageRoute(builder: (_) => UnitPage(courseEntity: courseEntity)); + return CupertinoPageRoute( + builder: (_) => SectionPage( + courseUnitEntity: courseUnitEntity, + courseUnitDetail: courseUnitDetail)); case AppRouteName.listen: return CupertinoPageRoute(builder: (_) => const ListenPage()); case AppRouteName.shop: @@ -129,11 +146,13 @@ class AppRouter { if (settings.arguments != null && settings.arguments is ProductEntity) { productEntity = settings.arguments as ProductEntity; } - return CupertinoPageRoute(builder: (_) => ShoppingPage(productEntity: productEntity)); + return CupertinoPageRoute( + builder: (_) => ShoppingPage(productEntity: productEntity)); case AppRouteName.exLesson: return CupertinoPageRoute(builder: (_) => const ExchangeLessonPage()); case AppRouteName.exList: - return CupertinoPageRoute(builder: (_) => const ExchangeLessonListPage()); + return CupertinoPageRoute( + builder: (_) => const ExchangeLessonListPage()); case AppRouteName.reAfter: return CupertinoPageRoute(builder: (_) => const RepeatAfterPage()); case AppRouteName.user: @@ -161,19 +180,22 @@ class AppRouter { case AppRouteName.topicPic: var courseLessonId = ''; if (settings.arguments != null) { - courseLessonId = (settings.arguments as Map)['courseLessonId'] as String; + courseLessonId = + (settings.arguments as Map)['courseLessonId'] as String; } - return CupertinoPageRoute(builder: (_) => TopicPicturePage(courseLessonId: courseLessonId)); + return CupertinoPageRoute( + builder: (_) => TopicPicturePage(courseLessonId: courseLessonId)); case AppRouteName.lookVideo: final videoUrl = (settings.arguments as Map)['videoUrl'] as String; final title = (settings.arguments as Map)['title'] as String?; - final courseLessonId = (settings.arguments as Map)['courseLessonId'] as String?; + final courseLessonId = + (settings.arguments as Map)['courseLessonId'] as String?; return CupertinoPageRoute( builder: (_) => LookVideoPage( - videoUrl: videoUrl, - typeTitle: title, - courseLessonId: courseLessonId, - )); + videoUrl: videoUrl, + typeTitle: title, + courseLessonId: courseLessonId, + )); /*case AppRouteName.setPwd: case AppRouteName.setPwd: phoneNum: phoneNum, @@ -182,7 +204,8 @@ class AppRouter { ));*/ case AppRouteName.webView: final urlStr = (settings.arguments as Map)['urlStr'] as String; - final webViewTitle = (settings.arguments as Map)['webViewTitle'] as String; + final webViewTitle = + (settings.arguments as Map)['webViewTitle'] as String; return CupertinoPageRoute( builder: (_) => WowWebViewPage( urlStr: urlStr, @@ -191,13 +214,16 @@ class AppRouter { case AppRouteName.readAfterContent: var videoFollowReadId = ''; if (settings.arguments != null) { - videoFollowReadId = (settings.arguments as Map)['videoFollowReadId'] as String; + videoFollowReadId = + (settings.arguments as Map)['videoFollowReadId'] as String; } - return CupertinoPageRoute(builder: (_) => RepeatAfterContentPage(videoFollowReadId: videoFollowReadId)); + return CupertinoPageRoute( + builder: (_) => + RepeatAfterContentPage(videoFollowReadId: videoFollowReadId)); case AppRouteName.setting: - return CupertinoPageRoute(builder: (_) => const SettingPage()); + return CupertinoPageRoute(builder: (_) => const SettingPage()); case AppRouteName.deleteAccount: - return CupertinoPageRoute(builder: (_) => const DeleteAccountPage()); + return CupertinoPageRoute(builder: (_) => const DeleteAccountPage()); case AppRouteName.reBack: return CupertinoPageRoute(builder: (_) => const ReBackPage()); case AppRouteName.tab: @@ -210,26 +236,34 @@ class AppRouter { case AppRouteName.reading: var courseLessonId = ''; if (settings.arguments != null) { - courseLessonId = (settings.arguments as Map)['courseLessonId'] as String; + courseLessonId = + (settings.arguments as Map)['courseLessonId'] as String; } - return CupertinoPageRoute(builder: (_) => ReadingPage(courseLessonId: courseLessonId)); + return CupertinoPageRoute( + builder: (_) => ReadingPage(courseLessonId: courseLessonId)); default: return CupertinoPageRoute( - builder: (_) => Scaffold(body: Center(child: Text('No route defined for ${settings.name}')))); + builder: (_) => Scaffold( + body: Center( + child: Text('No route defined for ${settings.name}')))); } } } Future pushNamed(String routeName, {Object? arguments}) { - return Navigator.of(AppRouter.context).pushNamed(routeName, arguments: arguments).then((value) { + return Navigator.of(AppRouter.context) + .pushNamed(routeName, arguments: arguments) + .then((value) { return value; }); } -Future pushNamedAndRemoveUntil(String routeName, RoutePredicate predicate, {Object? arguments}) { - return Navigator.of(AppRouter.context).pushNamedAndRemoveUntil(routeName, predicate, arguments: arguments); +Future pushNamedAndRemoveUntil(String routeName, RoutePredicate predicate, + {Object? arguments}) { + return Navigator.of(AppRouter.context) + .pushNamedAndRemoveUntil(routeName, predicate, arguments: arguments); } void popPage({dynamic data}) { - Navigator.of(AppRouter.context).pop(data); + Navigator.of(AppRouter.context).pop(data); } -- libgit2 0.22.2