Commit 42f15f6c1954d7adc8d5c7ad9908c6b99953ca7f
1 parent
8616f94b
feat:模块选择持久化&模块主题色从缓存获取
Showing
15 changed files
with
208 additions
and
68 deletions
lib/app/app.dart
| @@ -32,6 +32,8 @@ class App extends StatelessWidget { | @@ -32,6 +32,8 @@ class App extends StatelessWidget { | ||
| 32 | fontFamily: 'HannotateSC', | 32 | fontFamily: 'HannotateSC', |
| 33 | colorScheme: ColorScheme.fromSeed(seedColor: Colors.white), | 33 | colorScheme: ColorScheme.fromSeed(seedColor: Colors.white), |
| 34 | useMaterial3: true, | 34 | useMaterial3: true, |
| 35 | + ///系统主题色 | ||
| 36 | + primaryColor: const Color(0xFF00B6F1) | ||
| 35 | ), | 37 | ), |
| 36 | builder: EasyLoading.init( | 38 | builder: EasyLoading.init( |
| 37 | builder: (context, child) => ResponsiveBreakpoints(breakpoints: const [ | 39 | builder: (context, child) => ResponsiveBreakpoints(breakpoints: const [ |
lib/app/splash_page.dart
| @@ -19,6 +19,7 @@ import 'package:wow_english/utils/log_util.dart'; | @@ -19,6 +19,7 @@ import 'package:wow_english/utils/log_util.dart'; | ||
| 19 | import 'package:wow_english/utils/sp_util.dart'; | 19 | import 'package:wow_english/utils/sp_util.dart'; |
| 20 | 20 | ||
| 21 | import '../common/core/app_consts.dart'; | 21 | import '../common/core/app_consts.dart'; |
| 22 | +import '../common/core/module_cache.dart'; | ||
| 22 | import '../common/widgets/webview_dialog.dart'; | 23 | import '../common/widgets/webview_dialog.dart'; |
| 23 | 24 | ||
| 24 | class SplashPage extends StatelessWidget { | 25 | class SplashPage extends StatelessWidget { |
| @@ -167,6 +168,7 @@ class _TransitionViewState extends State<TransitionView> { | @@ -167,6 +168,7 @@ class _TransitionViewState extends State<TransitionView> { | ||
| 167 | void init() async { | 168 | void init() async { |
| 168 | changeDevice(); | 169 | changeDevice(); |
| 169 | await SpUtil.preInit(); | 170 | await SpUtil.preInit(); |
| 171 | + ModuleCache.instance.init(); | ||
| 170 | AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.welcomeToWow); | 172 | AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.welcomeToWow); |
| 171 | startTime(); | 173 | startTime(); |
| 172 | } | 174 | } |
lib/common/core/module_cache.dart
0 → 100644
| 1 | +import 'dart:convert'; | ||
| 2 | +import 'dart:ui'; | ||
| 3 | + | ||
| 4 | +import '../../models/course_module_entity.dart'; | ||
| 5 | +import '../../utils/sp_util.dart'; | ||
| 6 | +import '../utils/color_parser.dart'; | ||
| 7 | + | ||
| 8 | +///模块缓存类 | ||
| 9 | +class ModuleCache { | ||
| 10 | + // Private constructor | ||
| 11 | + ModuleCache._privateConstructor(); | ||
| 12 | + | ||
| 13 | + // Singleton instance | ||
| 14 | + static final ModuleCache _instance = ModuleCache._privateConstructor(); | ||
| 15 | + | ||
| 16 | + // Public accessor for the singleton instance | ||
| 17 | + static ModuleCache get instance => _instance; | ||
| 18 | + | ||
| 19 | + // Variable to store the current module entity | ||
| 20 | + CourseModuleEntity? _currentModule; | ||
| 21 | + | ||
| 22 | + // Key for SharedPreferences | ||
| 23 | + static const String _moduleKey = "courseModule"; | ||
| 24 | + | ||
| 25 | + // Initialize the cache by loading data from SharedPreferences | ||
| 26 | + Future<void> init() async { | ||
| 27 | + String? jsonString = SpUtil.getInstance().get<String>(_moduleKey); | ||
| 28 | + if (jsonString != null) { | ||
| 29 | + _currentModule = CourseModuleEntity.fromJson(json.decode(jsonString)); | ||
| 30 | + } | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + // Getter and setter for the current module | ||
| 34 | + CourseModuleEntity? get currentModule => _currentModule; | ||
| 35 | + set currentModule(CourseModuleEntity? value) { | ||
| 36 | + _currentModule = value; | ||
| 37 | + _saveToPrefs(value); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + // Method to clear the cached module data | ||
| 41 | + void clear() { | ||
| 42 | + _currentModule = null; | ||
| 43 | + _clearPrefs(); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + // Save module data to SharedPreferences | ||
| 47 | + void _saveToPrefs(CourseModuleEntity? module) { | ||
| 48 | + if (module != null) { | ||
| 49 | + String jsonString = json.encode(module.toJson()); | ||
| 50 | + SpUtil.getInstance().setData(_moduleKey, jsonString); | ||
| 51 | + } else { | ||
| 52 | + SpUtil.getInstance().remove(_moduleKey); | ||
| 53 | + } | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + String getCurrentThemeColorStr({String? colorStr}) { | ||
| 57 | + return colorStr ?? _currentModule.getSafeThemeColor(); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + ///根据当前课程阶段获取系统主题色 | ||
| 61 | + Color getCurrentThemeColor({String? colorStr}) { | ||
| 62 | + return parseColor(getCurrentThemeColorStr(colorStr: colorStr)); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + ///根据当前课程阶段获取系统主题名称 | ||
| 66 | + String getCurrentThemeName({String? name}) { | ||
| 67 | + return name ?? _currentModule.getSafeName(); | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + // Clear all data from SharedPreferences | ||
| 71 | + void _clearPrefs() async { | ||
| 72 | + SpUtil.getInstance().remove(_moduleKey); | ||
| 73 | + } | ||
| 74 | +} | ||
| 0 | \ No newline at end of file | 75 | \ No newline at end of file |
lib/common/utils/color_parser.dart
0 → 100644
| 1 | +import 'package:flutter/material.dart'; | ||
| 2 | + | ||
| 3 | +/// 将"#80FFFF00"字符串类型的颜色值转成Color对象类型 | ||
| 4 | +Color parseColor(String color) { | ||
| 5 | + // Remove the '#' character from the beginning of the string | ||
| 6 | + String hexColor = color.replaceAll("#", ""); | ||
| 7 | + | ||
| 8 | + // Check if the color is in the correct length (6 or 8) | ||
| 9 | + if (hexColor.length == 6) { | ||
| 10 | + // Add 'FF' for the alpha value if not provided | ||
| 11 | + hexColor = "FF$hexColor"; | ||
| 12 | + } else if (hexColor.length != 8) { | ||
| 13 | + ///如果数据异常,返回主题色兜底 | ||
| 14 | + // throw const FormatException("Invalid color format"); | ||
| 15 | + hexColor = "FF00B6F1"; | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + // Convert the hex string to an integer and create a Color object | ||
| 19 | + return Color(int.parse(hexColor, radix: 16)); | ||
| 20 | +} | ||
| 0 | \ No newline at end of file | 21 | \ No newline at end of file |
lib/generated/json/base/json_convert_content.dart
| @@ -139,7 +139,12 @@ class JsonConvert { | @@ -139,7 +139,12 @@ class JsonConvert { | ||
| 139 | if (value == null) { | 139 | if (value == null) { |
| 140 | return null; | 140 | return null; |
| 141 | } | 141 | } |
| 142 | - return convertFuncMap[type]!(value as Map<String, dynamic>) as T; | 142 | + var covertFunc = convertFuncMap[type]!; |
| 143 | + if (covertFunc is Map<String, dynamic>) { | ||
| 144 | + return covertFunc(value as Map<String, dynamic>) as T; | ||
| 145 | + } else { | ||
| 146 | + return covertFunc(Map<String, dynamic>.from(value)) as T; | ||
| 147 | + } | ||
| 143 | } else { | 148 | } else { |
| 144 | throw UnimplementedError( | 149 | throw UnimplementedError( |
| 145 | '$type unimplemented,you can try running the app again'); | 150 | '$type unimplemented,you can try running the app again'); |
lib/models/course_module_entity.dart
| @@ -21,14 +21,49 @@ class CourseModuleEntity { | @@ -21,14 +21,49 @@ class CourseModuleEntity { | ||
| 21 | int? status; | 21 | int? status; |
| 22 | String? courseModuleThemeColor; | 22 | String? courseModuleThemeColor; |
| 23 | 23 | ||
| 24 | - CourseModuleEntity(); | 24 | + // 无参构造函数 |
| 25 | + CourseModuleEntity.empty(); | ||
| 25 | 26 | ||
| 26 | - factory CourseModuleEntity.fromJson(Map<String, dynamic> json) => $CourseModuleEntityFromJson(json); | 27 | + // 命名构造函数 |
| 28 | + CourseModuleEntity( | ||
| 29 | + {int? id, | ||
| 30 | + String? code, | ||
| 31 | + String? courseModuleName, | ||
| 32 | + String? courseModuleThemeColor}); | ||
| 33 | + | ||
| 34 | + factory CourseModuleEntity.fromJson(Map<String, dynamic> json) => | ||
| 35 | + $CourseModuleEntityFromJson(json); | ||
| 27 | 36 | ||
| 28 | Map<String, dynamic> toJson() => $CourseModuleEntityToJson(this); | 37 | Map<String, dynamic> toJson() => $CourseModuleEntityToJson(this); |
| 29 | 38 | ||
| 39 | + // Factory constructor for creating an instance with only three parameters | ||
| 40 | + factory CourseModuleEntity.of(int? courseModuleId, String? courseModuleCode, | ||
| 41 | + String? courseModuleName, String? courseModuleThemeColor) { | ||
| 42 | + return CourseModuleEntity( | ||
| 43 | + id: courseModuleId, | ||
| 44 | + code: courseModuleCode, | ||
| 45 | + courseModuleName: courseModuleName, | ||
| 46 | + courseModuleThemeColor: courseModuleThemeColor, | ||
| 47 | + // Set default values or leave other fields null | ||
| 48 | + ); | ||
| 49 | + } | ||
| 50 | + | ||
| 30 | @override | 51 | @override |
| 31 | String toString() { | 52 | String toString() { |
| 32 | return jsonEncode(this); | 53 | return jsonEncode(this); |
| 33 | } | 54 | } |
| 34 | } | 55 | } |
| 56 | + | ||
| 57 | +///对可空的CourseModuleEntity对象扩展 | ||
| 58 | +extension PersonSafeExt on CourseModuleEntity? { | ||
| 59 | + | ||
| 60 | + ///获取非空的主题色,系统主题色0xFF00B6F1兜底 | ||
| 61 | + String getSafeThemeColor() { | ||
| 62 | + return this?.courseModuleThemeColor ?? '0xFF00B6F1'; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + ///获取非空的阶段名称 | ||
| 66 | + String getSafeName() { | ||
| 67 | + return this?.name ?? 'learn wow!'; | ||
| 68 | + } | ||
| 69 | +} |
lib/pages/module/course_module_page.dart
| @@ -5,9 +5,10 @@ import 'package:wow_english/common/widgets/we_app_bar.dart'; | @@ -5,9 +5,10 @@ import 'package:wow_english/common/widgets/we_app_bar.dart'; | ||
| 5 | import 'package:wow_english/models/course_module_entity.dart'; | 5 | import 'package:wow_english/models/course_module_entity.dart'; |
| 6 | import 'package:wow_english/route/route.dart'; | 6 | import 'package:wow_english/route/route.dart'; |
| 7 | 7 | ||
| 8 | +import '../../common/core/module_cache.dart'; | ||
| 8 | import '../../common/utils/click_with_music_controller.dart'; | 9 | import '../../common/utils/click_with_music_controller.dart'; |
| 10 | +import '../../common/utils/color_parser.dart'; | ||
| 9 | import '../../utils/audio_player_util.dart'; | 11 | import '../../utils/audio_player_util.dart'; |
| 10 | -import '../section/courese_module_model.dart'; | ||
| 11 | import 'bloc/module_bloc.dart'; | 12 | import 'bloc/module_bloc.dart'; |
| 12 | import 'widgets/module_item_widget.dart'; | 13 | import 'widgets/module_item_widget.dart'; |
| 13 | 14 | ||
| @@ -94,12 +95,11 @@ class _LessonPageView extends StatelessWidget { | @@ -94,12 +95,11 @@ class _LessonPageView extends StatelessWidget { | ||
| 94 | // ? Colors.red | 95 | // ? Colors.red |
| 95 | // : Colors.white, | 96 | // : Colors.white, |
| 96 | color: | 97 | color: |
| 97 | - CourseModuleModel(model?.code ?? 'Phase-1') | ||
| 98 | - .color | 98 | + parseColor(model.getSafeThemeColor()) |
| 99 | .withOpacity( | 99 | .withOpacity( |
| 100 | bloc.currentPageIndex == index | 100 | bloc.currentPageIndex == index |
| 101 | ? 1 | 101 | ? 1 |
| 102 | - : 0.35), | 102 | + : 0.15), |
| 103 | borderRadius: BorderRadius.circular(5.r), | 103 | borderRadius: BorderRadius.circular(5.r), |
| 104 | border: Border.all( | 104 | border: Border.all( |
| 105 | width: 0.5, | 105 | width: 0.5, |
| @@ -167,6 +167,7 @@ class _LessonPageView extends StatelessWidget { | @@ -167,6 +167,7 @@ class _LessonPageView extends StatelessWidget { | ||
| 167 | model: model, | 167 | model: model, |
| 168 | isSelected: bloc.currentPageIndex == index, | 168 | isSelected: bloc.currentPageIndex == index, |
| 169 | onClickEvent: () { | 169 | onClickEvent: () { |
| 170 | + ModuleCache.instance.currentModule = model; | ||
| 170 | ///todo 不同阶段音乐文件待提供 | 171 | ///todo 不同阶段音乐文件待提供 |
| 171 | ClickWithMusicController.instance.playMusicAndPerformAction( | 172 | ClickWithMusicController.instance.playMusicAndPerformAction( |
| 172 | context, | 173 | context, |
lib/pages/module/widgets/module_item_widget.dart
| 1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
| 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; | 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; |
| 3 | import 'package:wow_english/common/extension/string_extension.dart'; | 3 | import 'package:wow_english/common/extension/string_extension.dart'; |
| 4 | +import 'package:wow_english/common/utils/color_parser.dart'; | ||
| 4 | import 'package:wow_english/common/widgets/ow_image_widget.dart'; | 5 | import 'package:wow_english/common/widgets/ow_image_widget.dart'; |
| 5 | import 'package:wow_english/models/course_module_entity.dart'; | 6 | import 'package:wow_english/models/course_module_entity.dart'; |
| 6 | 7 | ||
| 7 | -import '../../section/courese_module_model.dart'; | ||
| 8 | - | ||
| 9 | ///阶段(模块)item布局 | 8 | ///阶段(模块)item布局 |
| 10 | class ModuleItemWidget extends StatelessWidget { | 9 | class ModuleItemWidget extends StatelessWidget { |
| 11 | - const ModuleItemWidget({super.key, required this.isSelected, this.model, this.onClickEvent}); | 10 | + const ModuleItemWidget( |
| 11 | + {super.key, required this.isSelected, this.model, this.onClickEvent}); | ||
| 12 | + | ||
| 12 | ///是否被选中 | 13 | ///是否被选中 |
| 13 | final bool isSelected; | 14 | final bool isSelected; |
| 14 | final CourseModuleEntity? model; | 15 | final CourseModuleEntity? model; |
| @@ -23,7 +24,7 @@ class ModuleItemWidget extends StatelessWidget { | @@ -23,7 +24,7 @@ class ModuleItemWidget extends StatelessWidget { | ||
| 23 | } | 24 | } |
| 24 | onClickEvent?.call(); | 25 | onClickEvent?.call(); |
| 25 | }, | 26 | }, |
| 26 | - child: isSelected?_selectWidget():_unSelectWidget(), | 27 | + child: isSelected ? _selectWidget() : _unSelectWidget(), |
| 27 | ); | 28 | ); |
| 28 | } | 29 | } |
| 29 | 30 | ||
| @@ -31,12 +32,9 @@ class ModuleItemWidget extends StatelessWidget { | @@ -31,12 +32,9 @@ class ModuleItemWidget extends StatelessWidget { | ||
| 31 | return Container( | 32 | return Container( |
| 32 | padding: const EdgeInsets.all(20), | 33 | padding: const EdgeInsets.all(20), |
| 33 | decoration: BoxDecoration( | 34 | decoration: BoxDecoration( |
| 34 | - image: DecorationImage( | ||
| 35 | - image: AssetImage('gendubeij'.assetPng) | ||
| 36 | - ) | ||
| 37 | - ), | 35 | + image: DecorationImage(image: AssetImage('gendubeij'.assetPng))), |
| 38 | child: OwImageWidget( | 36 | child: OwImageWidget( |
| 39 | - name: model?.picUrl??'', | 37 | + name: model?.picUrl ?? '', |
| 40 | ), | 38 | ), |
| 41 | ); | 39 | ); |
| 42 | } | 40 | } |
| @@ -45,48 +43,37 @@ class ModuleItemWidget extends StatelessWidget { | @@ -45,48 +43,37 @@ class ModuleItemWidget extends StatelessWidget { | ||
| 45 | return Container( | 43 | return Container( |
| 46 | padding: const EdgeInsets.all(10), | 44 | padding: const EdgeInsets.all(10), |
| 47 | decoration: BoxDecoration( | 45 | decoration: BoxDecoration( |
| 48 | - image: DecorationImage( | ||
| 49 | - image: AssetImage( | ||
| 50 | - 'gendubeij'.assetPng, | ||
| 51 | - ), | ||
| 52 | - fit: BoxFit.fill | ||
| 53 | - ), | 46 | + image: DecorationImage( |
| 47 | + image: AssetImage( | ||
| 48 | + 'gendubeij'.assetPng, | ||
| 49 | + ), | ||
| 50 | + fit: BoxFit.fill), | ||
| 54 | ), | 51 | ), |
| 55 | - child: Column( | 52 | + child: Column( |
| 56 | mainAxisAlignment: MainAxisAlignment.spaceBetween, | 53 | mainAxisAlignment: MainAxisAlignment.spaceBetween, |
| 57 | children: [ | 54 | children: [ |
| 58 | Expanded( | 55 | Expanded( |
| 59 | child: OwImageWidget( | 56 | child: OwImageWidget( |
| 60 | - name: model?.picUrl??'', | 57 | + name: model?.picUrl ?? '', |
| 61 | ), | 58 | ), |
| 62 | ), | 59 | ), |
| 63 | 10.verticalSpace, | 60 | 10.verticalSpace, |
| 64 | Container( | 61 | Container( |
| 65 | decoration: BoxDecoration( | 62 | decoration: BoxDecoration( |
| 66 | - color: CourseModuleModel(model?.code??'Phase-1').color, | ||
| 67 | - borderRadius: BorderRadius.circular(6.r), | ||
| 68 | - border: Border.all( | ||
| 69 | - color: const Color(0xFF333333), | ||
| 70 | - width: 1.0 | ||
| 71 | - ) | ||
| 72 | - ), | 63 | + color: parseColor(model.getSafeThemeColor()), |
| 64 | + borderRadius: BorderRadius.circular(6.r), | ||
| 65 | + border: Border.all(color: const Color(0xFF333333), width: 1.0)), | ||
| 73 | padding: EdgeInsets.symmetric(horizontal: 10.w), | 66 | padding: EdgeInsets.symmetric(horizontal: 10.w), |
| 74 | child: Column( | 67 | child: Column( |
| 75 | children: [ | 68 | children: [ |
| 76 | Text( | 69 | Text( |
| 77 | - model?.name??'', | ||
| 78 | - style: TextStyle( | ||
| 79 | - color: Colors.white, | ||
| 80 | - fontSize: 12.sp | ||
| 81 | - ), | 70 | + model?.getSafeName() ?? '', |
| 71 | + style: TextStyle(color: Colors.white, fontSize: 12.sp), | ||
| 82 | ), | 72 | ), |
| 83 | Text( | 73 | Text( |
| 84 | - model?.des??'', | 74 | + model?.des ?? '', |
| 85 | maxLines: 1, | 75 | maxLines: 1, |
| 86 | - style: TextStyle( | ||
| 87 | - color: Colors.white, | ||
| 88 | - fontSize: 12.sp | ||
| 89 | - ), | 76 | + style: TextStyle(color: Colors.white, fontSize: 12.sp), |
| 90 | ) | 77 | ) |
| 91 | ], | 78 | ], |
| 92 | ), | 79 | ), |
| @@ -95,4 +82,4 @@ class ModuleItemWidget extends StatelessWidget { | @@ -95,4 +82,4 @@ class ModuleItemWidget extends StatelessWidget { | ||
| 95 | ), | 82 | ), |
| 96 | ); | 83 | ); |
| 97 | } | 84 | } |
| 98 | -} | ||
| 99 | \ No newline at end of file | 85 | \ No newline at end of file |
| 86 | +} |
lib/pages/section/bloc/section_bloc.dart
| @@ -38,6 +38,7 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | @@ -38,6 +38,7 @@ class SectionBloc extends Bloc<SectionEvent, SectionState> { | ||
| 38 | 38 | ||
| 39 | ScrollController get indicatorSrollController => _indicatorSrollController; | 39 | ScrollController get indicatorSrollController => _indicatorSrollController; |
| 40 | 40 | ||
| 41 | + ///之前传进来是用于根据courseModuleCode获取主题色的,现在不用了。参数还是先留着,预防后面需要 | ||
| 41 | CourseUnitEntity _courseUnitEntity; | 42 | CourseUnitEntity _courseUnitEntity; |
| 42 | 43 | ||
| 43 | CourseUnitEntity get courseUnitEntity => _courseUnitEntity; | 44 | CourseUnitEntity get courseUnitEntity => _courseUnitEntity; |
lib/pages/section/section_page.dart
| @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; | @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; | ||
| 3 | import 'package:flutter_bloc/flutter_bloc.dart'; | 3 | import 'package:flutter_bloc/flutter_bloc.dart'; |
| 4 | import 'package:flutter_screenutil/flutter_screenutil.dart'; | 4 | import 'package:flutter_screenutil/flutter_screenutil.dart'; |
| 5 | import 'package:nested_scroll_views/material.dart'; | 5 | import 'package:nested_scroll_views/material.dart'; |
| 6 | +import 'package:wow_english/common/core/module_cache.dart'; | ||
| 6 | import 'package:wow_english/common/core/user_util.dart'; | 7 | import 'package:wow_english/common/core/user_util.dart'; |
| 7 | import 'package:wow_english/common/utils/click_with_music_controller.dart'; | 8 | import 'package:wow_english/common/utils/click_with_music_controller.dart'; |
| 8 | import 'package:wow_english/models/course_unit_entity.dart'; | 9 | import 'package:wow_english/models/course_unit_entity.dart'; |
| @@ -138,9 +139,7 @@ class _SectionPageView extends StatelessWidget { | @@ -138,9 +139,7 @@ class _SectionPageView extends StatelessWidget { | ||
| 138 | await bloc.requestEnterClass(courseLessonId, () { | 139 | await bloc.requestEnterClass(courseLessonId, () { |
| 139 | pushNamed(AppRouteName.topicPic, arguments: { | 140 | pushNamed(AppRouteName.topicPic, arguments: { |
| 140 | 'courseLessonId': courseLessonId, | 141 | 'courseLessonId': courseLessonId, |
| 141 | - 'moduleColor': CourseModuleModel( | ||
| 142 | - bloc.courseUnitEntity.courseModuleCode ?? 'Phase-1') | ||
| 143 | - .color | 142 | + 'moduleColor': ModuleCache.instance.getCurrentThemeColor() |
| 144 | }).then((value) { | 143 | }).then((value) { |
| 145 | if (value != null) { | 144 | if (value != null) { |
| 146 | Map<String, dynamic> dataMap = | 145 | Map<String, dynamic> dataMap = |
| @@ -175,7 +174,6 @@ class _SectionPageView extends StatelessWidget { | @@ -175,7 +174,6 @@ class _SectionPageView extends StatelessWidget { | ||
| 175 | children: [ | 174 | children: [ |
| 176 | SectionHeaderWidget( | 175 | SectionHeaderWidget( |
| 177 | title: bloc.getCourseUnitDetail().name, | 176 | title: bloc.getCourseUnitDetail().name, |
| 178 | - courseModuleCode: bloc.courseUnitEntity.courseModuleCode, | ||
| 179 | onBack: () { | 177 | onBack: () { |
| 180 | popPage(data: { | 178 | popPage(data: { |
| 181 | 'needRefresh': bloc.courseUnitEntityChanged, | 179 | 'needRefresh': bloc.courseUnitEntityChanged, |
| @@ -281,9 +279,7 @@ Widget _itemTransCard( | @@ -281,9 +279,7 @@ Widget _itemTransCard( | ||
| 281 | const SizedBox(height: 16.0), | 279 | const SizedBox(height: 16.0), |
| 282 | // 间距 | 280 | // 间距 |
| 283 | CircularProgressIndicator( | 281 | CircularProgressIndicator( |
| 284 | - color: CourseModuleModel( | ||
| 285 | - bloc.courseUnitEntity.courseModuleCode ?? 'Phase-1') | ||
| 286 | - .color), | 282 | + color: ModuleCache.instance.getCurrentThemeColor()), |
| 287 | // 加载动画 | 283 | // 加载动画 |
| 288 | ], | 284 | ], |
| 289 | ), | 285 | ), |
| @@ -332,7 +328,6 @@ Widget _itemTransCard( | @@ -332,7 +328,6 @@ Widget _itemTransCard( | ||
| 332 | sectionData.id.toString(), sectionData.courseType)); | 328 | sectionData.id.toString(), sectionData.courseType)); |
| 333 | }, | 329 | }, |
| 334 | child: SectionItem( | 330 | child: SectionItem( |
| 335 | - courseModuleId: bloc.courseUnitEntity.courseModuleCode, | ||
| 336 | lessons: sectionData, | 331 | lessons: sectionData, |
| 337 | ), | 332 | ), |
| 338 | ); | 333 | ); |
lib/pages/section/widgets/section_header_widget.dart
| @@ -4,17 +4,15 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; | @@ -4,17 +4,15 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; | ||
| 4 | import 'package:wow_english/common/extension/string_extension.dart'; | 4 | import 'package:wow_english/common/extension/string_extension.dart'; |
| 5 | import 'package:wow_english/pages/user/bloc/user_bloc.dart'; | 5 | import 'package:wow_english/pages/user/bloc/user_bloc.dart'; |
| 6 | 6 | ||
| 7 | -import '../courese_module_model.dart'; | 7 | +import '../../../common/core/module_cache.dart'; |
| 8 | 8 | ||
| 9 | /// 环节(课程)列表页标题栏 | 9 | /// 环节(课程)列表页标题栏 |
| 10 | class SectionHeaderWidget extends StatelessWidget { | 10 | class SectionHeaderWidget extends StatelessWidget { |
| 11 | const SectionHeaderWidget( | 11 | const SectionHeaderWidget( |
| 12 | - {super.key, this.title, this.courseModuleCode, this.onBack}); | 12 | + {super.key, this.title, this.onBack}); |
| 13 | 13 | ||
| 14 | final String? title; | 14 | final String? title; |
| 15 | 15 | ||
| 16 | - final String? courseModuleCode; | ||
| 17 | - | ||
| 18 | final VoidCallback? onBack; | 16 | final VoidCallback? onBack; |
| 19 | 17 | ||
| 20 | @override | 18 | @override |
| @@ -24,7 +22,7 @@ class SectionHeaderWidget extends StatelessWidget { | @@ -24,7 +22,7 @@ class SectionHeaderWidget extends StatelessWidget { | ||
| 24 | return Container( | 22 | return Container( |
| 25 | height: 45, | 23 | height: 45, |
| 26 | width: double.infinity, | 24 | width: double.infinity, |
| 27 | - color: CourseModuleModel(courseModuleCode ?? 'Phase-1').color, | 25 | + color: ModuleCache.instance.getCurrentThemeColor(), |
| 28 | padding: EdgeInsets.symmetric(horizontal: 9.5.w), | 26 | padding: EdgeInsets.symmetric(horizontal: 9.5.w), |
| 29 | child: Row( | 27 | child: Row( |
| 30 | children: [ | 28 | children: [ |
| @@ -49,9 +47,7 @@ class SectionHeaderWidget extends StatelessWidget { | @@ -49,9 +47,7 @@ class SectionHeaderWidget extends StatelessWidget { | ||
| 49 | 20.horizontalSpace, | 47 | 20.horizontalSpace, |
| 50 | Expanded( | 48 | Expanded( |
| 51 | child: Text( | 49 | child: Text( |
| 52 | - title ?? | ||
| 53 | - CourseModuleModel(courseModuleCode ?? 'Phase-1') | ||
| 54 | - .courseModuleTitle, | 50 | + title ?? ModuleCache.instance.getCurrentThemeName(), |
| 55 | textAlign: TextAlign.left, | 51 | textAlign: TextAlign.left, |
| 56 | style: const TextStyle(color: Colors.white, fontSize: 30.0), | 52 | style: const TextStyle(color: Colors.white, fontSize: 30.0), |
| 57 | )), | 53 | )), |
lib/pages/section/widgets/section_item.dart
| @@ -3,15 +3,13 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; | @@ -3,15 +3,13 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; | ||
| 3 | import 'package:wow_english/common/extension/string_extension.dart'; | 3 | import 'package:wow_english/common/extension/string_extension.dart'; |
| 4 | import 'package:wow_english/common/widgets/ow_image_widget.dart'; | 4 | import 'package:wow_english/common/widgets/ow_image_widget.dart'; |
| 5 | 5 | ||
| 6 | +import '../../../common/core/module_cache.dart'; | ||
| 6 | import '../../../models/course_section_entity.dart'; | 7 | import '../../../models/course_section_entity.dart'; |
| 7 | -import '../../../models/course_unit_entity.dart'; | ||
| 8 | -import '../courese_module_model.dart'; | ||
| 9 | 8 | ||
| 10 | ///环节item布局 | 9 | ///环节item布局 |
| 11 | class SectionItem extends StatelessWidget { | 10 | class SectionItem extends StatelessWidget { |
| 12 | - const SectionItem({super.key, this.lessons, this.courseModuleId}); | 11 | + const SectionItem({super.key, this.lessons}); |
| 13 | 12 | ||
| 14 | - final String? courseModuleId; | ||
| 15 | final CourseSectionEntity? lessons; | 13 | final CourseSectionEntity? lessons; |
| 16 | 14 | ||
| 17 | @override | 15 | @override |
| @@ -62,7 +60,7 @@ class SectionItem extends StatelessWidget { | @@ -62,7 +60,7 @@ class SectionItem extends StatelessWidget { | ||
| 62 | width: 2, | 60 | width: 2, |
| 63 | color: const Color(0xFF140C10), | 61 | color: const Color(0xFF140C10), |
| 64 | ), | 62 | ), |
| 65 | - color: CourseModuleModel(courseModuleId ?? 'Phase-1').color, | 63 | + color: ModuleCache.instance.getCurrentThemeColor(), |
| 66 | borderRadius: BorderRadius.circular(6) | 64 | borderRadius: BorderRadius.circular(6) |
| 67 | ), | 65 | ), |
| 68 | padding: EdgeInsets.symmetric(horizontal: 10.w), | 66 | padding: EdgeInsets.symmetric(horizontal: 10.w), |
lib/pages/unit/bloc.dart
| @@ -2,6 +2,7 @@ import 'package:bloc/bloc.dart'; | @@ -2,6 +2,7 @@ import 'package:bloc/bloc.dart'; | ||
| 2 | import 'package:wow_english/pages/unit/widget/home_tab_header_widget.dart'; | 2 | import 'package:wow_english/pages/unit/widget/home_tab_header_widget.dart'; |
| 3 | import 'package:wow_english/utils/audio_player_util.dart'; | 3 | import 'package:wow_english/utils/audio_player_util.dart'; |
| 4 | 4 | ||
| 5 | +import '../../common/core/module_cache.dart'; | ||
| 5 | import '../../common/request/dao/lesson_dao.dart'; | 6 | import '../../common/request/dao/lesson_dao.dart'; |
| 6 | import '../../common/request/exception.dart'; | 7 | import '../../common/request/exception.dart'; |
| 7 | import '../../models/course_module_entity.dart'; | 8 | import '../../models/course_module_entity.dart'; |
| @@ -24,6 +25,8 @@ class UnitBloc extends Bloc<UnitEvent, UnitState> { | @@ -24,6 +25,8 @@ class UnitBloc extends Bloc<UnitEvent, UnitState> { | ||
| 24 | bool exchangeResult = false; | 25 | bool exchangeResult = false; |
| 25 | 26 | ||
| 26 | UnitBloc(CourseModuleEntity? courseEntity) : super(UnitState().init()) { | 27 | UnitBloc(CourseModuleEntity? courseEntity) : super(UnitState().init()) { |
| 28 | + ///缓存当前模块信息 | ||
| 29 | + setIfNotNull(courseEntity); | ||
| 27 | on<RequestUnitDataEvent>(_requestUnitDatas); | 30 | on<RequestUnitDataEvent>(_requestUnitDatas); |
| 28 | on<UnitInitEvent>((event, emit) { | 31 | on<UnitInitEvent>((event, emit) { |
| 29 | AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.inMyTummy); | 32 | AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.inMyTummy); |
| @@ -35,6 +38,7 @@ class UnitBloc extends Bloc<UnitEvent, UnitState> { | @@ -35,6 +38,7 @@ class UnitBloc extends Bloc<UnitEvent, UnitState> { | ||
| 35 | try { | 38 | try { |
| 36 | await loading(() async { | 39 | await loading(() async { |
| 37 | _unitData = await LessonDao.courseUnit(event.moduleId); | 40 | _unitData = await LessonDao.courseUnit(event.moduleId); |
| 41 | + setIfNull(_unitData); | ||
| 38 | emitter(UnitDataLoadState()); | 42 | emitter(UnitDataLoadState()); |
| 39 | }); | 43 | }); |
| 40 | } catch (e) { | 44 | } catch (e) { |
| @@ -44,6 +48,27 @@ class UnitBloc extends Bloc<UnitEvent, UnitState> { | @@ -44,6 +48,27 @@ class UnitBloc extends Bloc<UnitEvent, UnitState> { | ||
| 44 | } | 48 | } |
| 45 | } | 49 | } |
| 46 | 50 | ||
| 51 | + ///如果从模块页选择回来,则刷新缓存,否则认为是从 | ||
| 52 | + void setIfNotNull(CourseModuleEntity? courseModuleEntity) { | ||
| 53 | + if (courseModuleEntity != null) { | ||
| 54 | + _moduleEntity = courseModuleEntity; | ||
| 55 | + } else { | ||
| 56 | + _moduleEntity = ModuleCache.instance.currentModule; | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + ///理论上只有没有缓存的情况下首次进入单元列表,数据请求成功后构建第一次缓存 | ||
| 61 | + void setIfNull(CourseUnitEntity? courseUnitData) { | ||
| 62 | + if (_moduleEntity == null && courseUnitData != null) { | ||
| 63 | + _moduleEntity = CourseModuleEntity.of( | ||
| 64 | + courseUnitData.nowCourseModuleId, | ||
| 65 | + courseUnitData.courseModuleCode, | ||
| 66 | + courseUnitData.nowCourseModuleName, | ||
| 67 | + courseUnitData.courseModuleThemeColor); | ||
| 68 | + ModuleCache.instance.currentModule = _moduleEntity; | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + | ||
| 47 | String? getCourseModuleCode() { | 72 | String? getCourseModuleCode() { |
| 48 | return _moduleEntity?.code ?? _unitData?.courseModuleCode; | 73 | return _moduleEntity?.code ?? _unitData?.courseModuleCode; |
| 49 | } | 74 | } |
lib/pages/unit/widget/home_tab_header_widget.dart
| @@ -5,7 +5,7 @@ import 'package:wow_english/common/extension/string_extension.dart'; | @@ -5,7 +5,7 @@ import 'package:wow_english/common/extension/string_extension.dart'; | ||
| 5 | import 'package:wow_english/pages/user/bloc/user_bloc.dart'; | 5 | import 'package:wow_english/pages/user/bloc/user_bloc.dart'; |
| 6 | 6 | ||
| 7 | import '../../../common/core/app_config_helper.dart'; | 7 | import '../../../common/core/app_config_helper.dart'; |
| 8 | -import '../../section/courese_module_model.dart'; | 8 | +import '../../../common/core/module_cache.dart'; |
| 9 | 9 | ||
| 10 | enum HeaderActionType { | 10 | enum HeaderActionType { |
| 11 | //视频跟读 | 11 | //视频跟读 |
| @@ -35,7 +35,7 @@ class HomeTabHeaderWidget extends StatelessWidget { | @@ -35,7 +35,7 @@ class HomeTabHeaderWidget extends StatelessWidget { | ||
| 35 | return Container( | 35 | return Container( |
| 36 | height: 45, | 36 | height: 45, |
| 37 | width: double.infinity, | 37 | width: double.infinity, |
| 38 | - color: CourseModuleModel(courseModuleCode ?? 'Phase-1').color, | 38 | + color: ModuleCache.instance.getCurrentThemeColor(), |
| 39 | padding: EdgeInsets.symmetric(horizontal: 9.5.w), | 39 | padding: EdgeInsets.symmetric(horizontal: 9.5.w), |
| 40 | child: Row( | 40 | child: Row( |
| 41 | children: [ | 41 | children: [ |
| @@ -60,8 +60,7 @@ class HomeTabHeaderWidget extends StatelessWidget { | @@ -60,8 +60,7 @@ class HomeTabHeaderWidget extends StatelessWidget { | ||
| 60 | 20.horizontalSpace, | 60 | 20.horizontalSpace, |
| 61 | Expanded( | 61 | Expanded( |
| 62 | child: Text( | 62 | child: Text( |
| 63 | - CourseModuleModel(courseModuleCode ?? 'Phase-1') | ||
| 64 | - .courseModuleTitle, | 63 | + ModuleCache.instance.getCurrentThemeName(), |
| 65 | textAlign: TextAlign.left, | 64 | textAlign: TextAlign.left, |
| 66 | style: const TextStyle(color: Colors.white, fontSize: 30.0), | 65 | style: const TextStyle(color: Colors.white, fontSize: 30.0), |
| 67 | )), | 66 | )), |
lib/route/route.dart
| @@ -119,7 +119,7 @@ class AppRouter { | @@ -119,7 +119,7 @@ class AppRouter { | ||
| 119 | case AppRouteName.courseModule: | 119 | case AppRouteName.courseModule: |
| 120 | return CupertinoPageRoute(builder: (_) => const CourseModulePage()); | 120 | return CupertinoPageRoute(builder: (_) => const CourseModulePage()); |
| 121 | case AppRouteName.courseUnit: | 121 | case AppRouteName.courseUnit: |
| 122 | - CourseModuleEntity courseModuleEntity = CourseModuleEntity(); | 122 | + CourseModuleEntity? courseModuleEntity; |
| 123 | if (settings.arguments != null) { | 123 | if (settings.arguments != null) { |
| 124 | courseModuleEntity = (settings.arguments as Map) | 124 | courseModuleEntity = (settings.arguments as Map) |
| 125 | .getOrNull('courseModuleEntity') as CourseModuleEntity; | 125 | .getOrNull('courseModuleEntity') as CourseModuleEntity; |