diff --git a/.fvm/flutter_sdk b/.fvm/flutter_sdk new file mode 120000 index 0000000..143ba8c --- /dev/null +++ b/.fvm/flutter_sdk @@ -0,0 +1 @@ +/Users/stay/fvm/versions/3.19.2 \ No newline at end of file diff --git a/.fvm/fvm_config.json b/.fvm/fvm_config.json new file mode 100644 index 0000000..7691f75 --- /dev/null +++ b/.fvm/fvm_config.json @@ -0,0 +1,4 @@ +{ + "flutterSdkVersion": "3.19.2", + "flavors": {} +} \ No newline at end of file diff --git a/assets/images/listen_lock.png b/assets/images/iv_lock.png index 618912d..618912d 100644 --- a/assets/images/listen_lock.png +++ b/assets/images/iv_lock.png diff --git a/lib/common/widgets/throttledGesture_gesture_detector.dart b/lib/common/widgets/throttledGesture_gesture_detector.dart new file mode 100644 index 0000000..5cf70fe --- /dev/null +++ b/lib/common/widgets/throttledGesture_gesture_detector.dart @@ -0,0 +1,42 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; + +///带节流功能的GestureDetector +class ThrottledGestureDetector extends StatefulWidget { + final Widget child; + final VoidCallback onTap; + final int throttleTime; + + const ThrottledGestureDetector({ + super.key, + required this.child, + required this.onTap, + this.throttleTime = 500, // 默认节流时间为500毫秒 + }); + + @override + _ThrottledGestureDetectorState createState() => + _ThrottledGestureDetectorState(); +} + +class _ThrottledGestureDetectorState extends State { + bool _isThrottled = false; + + void _handleTap() { + if (!_isThrottled) { + widget.onTap(); + _isThrottled = true; + Timer(Duration(milliseconds: widget.throttleTime), () { + _isThrottled = false; + }); + } + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: _handleTap, + child: widget.child, + ); + } +} diff --git a/lib/pages/listen/widgets/listen_item_widget.dart b/lib/pages/listen/widgets/listen_item_widget.dart index bd896fd..1274d40 100644 --- a/lib/pages/listen/widgets/listen_item_widget.dart +++ b/lib/pages/listen/widgets/listen_item_widget.dart @@ -46,7 +46,7 @@ class ListenItemWidget extends StatelessWidget { Visibility( visible: entity?.lock??false, child: Image.asset( - 'listen_lock'.assetPng, + 'iv_lock'.assetPng, height: 36.h, width: 41.w, ), diff --git a/lib/pages/login/forgetpwd/forget_password_home_page.dart b/lib/pages/login/forgetpwd/forget_password_home_page.dart index a1af920..fc6d0f4 100644 --- a/lib/pages/login/forgetpwd/forget_password_home_page.dart +++ b/lib/pages/login/forgetpwd/forget_password_home_page.dart @@ -7,6 +7,7 @@ import 'package:wow_english/pages/login/loginpage/time_widget.dart'; import 'package:wow_english/pages/login/setpwd/set_pwd_page.dart'; import 'package:wow_english/utils/toast_util.dart'; +import '../../../common/widgets/we_app_bar.dart'; import 'bloc/forget_pwd_home_bloc.dart'; class ForgetPasswordHomePage extends StatelessWidget { @@ -50,136 +51,118 @@ class _ForgetPasswordHomePageView extends StatelessWidget { Widget _buildForgetPwdView() => BlocBuilder(builder: (context, state) { final bloc = BlocProvider.of(context); return Scaffold( + appBar: const WEAppBar(), body: Container( color: Colors.white, child: SafeArea( - child: Stack( - children: [ - SingleChildScrollView( - child: Padding( - padding: EdgeInsets.only(left: 49.w, right: 10.w), - child: Column( - children: [ - 34.verticalSpace, - Row( - children: [ - Image.asset( - 'wow_logo'.assetPng, - height: 49.w, - width: 83.5.h, - ), - 12.5.horizontalSpace, - Text( - '修改密码\n请输入您的手机号和验证码吧', - style: TextStyle(fontSize: 16.sp, color: const Color(0xFF666666)), - ) - ], - ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - children: [ - 44.5.verticalSpace, - Row( - children: [ - Image.asset( - 'phone'.assetPng, - height: 45.h, - width: 35.w, - ), - 15.horizontalSpace, - Expanded( - child: TextFieldCustomerWidget( - height: 50.h, - hitText: '请输入当前手机号', - textInputType: TextInputType.phone, - bgImageName: 'Input_layer_up', - onChangeValue: (String value) { - bloc.add(PhoneNumChangeEvent()); - }, - controller: bloc.phoneNumController, - )) - ], - ), - 11.5.verticalSpace, - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Image.asset( - 'lock'.assetPng, - height: 34.h, - width: 31.w, - ), - 18.5.horizontalSpace, - Expanded( - child: TextFieldCustomerWidget( - hitText: '请输入验证码', - bgImageName: 'Input_layer_down', - onChangeValue: (String value) { - bloc.add(CheckCodeChangeEvent()); - }, - textInputType: TextInputType.emailAddress, - controller: bloc.checkNumController, - )), - 16.5.horizontalSpace, - TimerWidget( - pageType: 1, - canSendSms: bloc.canSendSms, - sendSmsEvent: () => bloc.add(SendSmsCodeEvent()), - ) - ], - ) - ], - )), - 2.verticalSpace, - Image.asset( - 'steven_bride'.assetPng, - height: 173.h, - width: 157.w, - ) - ], - ), - GestureDetector( - onTap: () { - if (bloc.canSetPwd) { - bloc.add(SetPassWordEvent()); - } - }, - child: Container( - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage(bloc.canSetPwd ? 'login_enter'.assetPng : 'login_enter_dis'.assetPng), - fit: BoxFit.fill), - ), - padding: EdgeInsets.symmetric(horizontal: 28.w, vertical: 14.h), - child: Text( - '确定', - style: TextStyle(fontSize: 16.sp, color: Colors.white), - ), - ), - ) - ], - ), + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.only(left: 49.w, right: 10.w), + child: Column( + children: [ + Row( + children: [ + Image.asset( + 'wow_logo'.assetPng, + height: 49.w, + width: 83.5.h, + ), + 12.5.horizontalSpace, + Text( + '修改密码\n请输入您的手机号和验证码吧', + style: TextStyle(fontSize: 16.sp, color: const Color(0xFF666666)), + ) + ], ), - ), - Container( - padding: EdgeInsets.only(top: 16.h), - alignment: Alignment.topLeft, - child: IconButton( - onPressed: () { - Navigator.pop(context); - }, - icon: Image.asset( - 'back_around'.assetPng, - width: 40.w, - height: 40.h, - ) + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + children: [ + 44.5.verticalSpace, + Row( + children: [ + Image.asset( + 'phone'.assetPng, + height: 45.h, + width: 35.w, + ), + 15.horizontalSpace, + Expanded( + child: TextFieldCustomerWidget( + height: 50.h, + hitText: '请输入当前手机号', + textInputType: TextInputType.phone, + bgImageName: 'Input_layer_up', + onChangeValue: (String value) { + bloc.add(PhoneNumChangeEvent()); + }, + controller: bloc.phoneNumController, + )) + ], + ), + 11.5.verticalSpace, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Image.asset( + 'lock'.assetPng, + height: 34.h, + width: 31.w, + ), + 18.5.horizontalSpace, + Expanded( + child: TextFieldCustomerWidget( + hitText: '请输入验证码', + bgImageName: 'Input_layer_down', + onChangeValue: (String value) { + bloc.add(CheckCodeChangeEvent()); + }, + textInputType: TextInputType.emailAddress, + controller: bloc.checkNumController, + )), + 16.5.horizontalSpace, + TimerWidget( + pageType: 1, + canSendSms: bloc.canSendSms, + sendSmsEvent: () => bloc.add(SendSmsCodeEvent()), + ) + ], + ) + ], + )), + 2.verticalSpace, + Image.asset( + 'steven_bride'.assetPng, + height: 173.h, + width: 157.w, + ) + ], ), - ), - ] - ) + GestureDetector( + onTap: () { + if (bloc.canSetPwd) { + bloc.add(SetPassWordEvent()); + } + }, + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage(bloc.canSetPwd ? 'login_enter'.assetPng : 'login_enter_dis'.assetPng), + fit: BoxFit.fill), + ), + padding: EdgeInsets.symmetric(horizontal: 28.w, vertical: 14.h), + child: Text( + '确定', + style: TextStyle(fontSize: 16.sp, color: Colors.white), + ), + ), + ) + ], + ), + ), + ), ), ), ); diff --git a/lib/pages/module/module_page.dart b/lib/pages/module/course_module_page.dart index dc29413..d0ea049 100644 --- a/lib/pages/module/module_page.dart +++ b/lib/pages/module/course_module_page.dart @@ -9,9 +9,9 @@ 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}); +// 课程阶段(模块)列表页 +class CourseModulePage extends StatelessWidget { + const CourseModulePage({super.key, this.starPageIndex}); final int? starPageIndex; @@ -37,26 +37,7 @@ class _LessonPageView extends StatelessWidget { 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('购买'); - // }, - // ) - // ], - ), + appBar: const WEAppBar(), body: _lessViewWidget(), ), ); diff --git a/lib/pages/module/widgets/module_item_widget.dart b/lib/pages/module/widgets/module_item_widget.dart index ad7e76b..81e53f8 100644 --- a/lib/pages/module/widgets/module_item_widget.dart +++ b/lib/pages/module/widgets/module_item_widget.dart @@ -6,6 +6,7 @@ import 'package:wow_english/models/course_module_entity.dart'; import '../../section/courese_module_model.dart'; +///阶段(模块)item布局 class ModuleItemWidget extends StatelessWidget { const ModuleItemWidget({super.key, required this.isSelected, this.model, this.onClickEvent}); ///是否被选中 diff --git a/lib/pages/practice/bloc/topic_picture_bloc.dart b/lib/pages/practice/bloc/topic_picture_bloc.dart index d84f1ce..5c4e7ee 100644 --- a/lib/pages/practice/bloc/topic_picture_bloc.dart +++ b/lib/pages/practice/bloc/topic_picture_bloc.dart @@ -83,7 +83,7 @@ class TopicPictureBloc extends BaseSectionBloc(_initVoiceSdk); on(_selectItemLoad); on(_requestData); - on(_voiceXsTest); + on(_voiceXsStart); on(_voiceXsStop); on(_questionVoicePlay); on((event, emit) { @@ -231,7 +231,7 @@ class TopicPictureBloc extends BaseSectionBloc emitter) async { + void _voiceXsStart(XSVoiceStartEvent event,Emitter emitter) async { await audioPlayer.stop(); // 调用封装好的权限检查和请求方法 bool result = await permissionCheckAndRequest( diff --git a/lib/pages/practice/bloc/topic_picture_event.dart b/lib/pages/practice/bloc/topic_picture_event.dart index 4914c1b..c2e416c 100644 --- a/lib/pages/practice/bloc/topic_picture_event.dart +++ b/lib/pages/practice/bloc/topic_picture_event.dart @@ -14,11 +14,11 @@ class XSVoiceInitEvent extends TopicPictureEvent { } ///开始评测 -class XSVoiceTestEvent extends TopicPictureEvent { +class XSVoiceStartEvent extends TopicPictureEvent { final String testWord; final String type; final String userId; - XSVoiceTestEvent(this.testWord,this.type,this.userId); + XSVoiceStartEvent(this.testWord,this.type,this.userId); } ///终止评测 diff --git a/lib/pages/practice/topic_picture_page.dart b/lib/pages/practice/topic_picture_page.dart index 87ba70d..dd3cf43 100644 --- a/lib/pages/practice/topic_picture_page.dart +++ b/lib/pages/practice/topic_picture_page.dart @@ -10,6 +10,7 @@ import 'package:wow_english/pages/practice/topic_type.dart'; import 'package:wow_english/route/route.dart'; import 'package:wow_english/utils/toast_util.dart'; +import '../../common/widgets/throttledGesture_gesture_detector.dart'; import 'bloc/topic_picture_bloc.dart'; import 'widgets/practice_header_widget.dart'; @@ -479,20 +480,23 @@ class _TopicPicturePage extends StatelessWidget { ), ), 70.verticalSpace, - GestureDetector( + ThrottledGestureDetector( + throttleTime: 1000, onTap: () { if (bloc.voicePlayState == VoicePlayState.playing) { - showToast('正在播放音屏,不能终止'); + showToast('正在播放音频,不能终止'); return; } if (bloc.isVoicing) { + bloc.add(XSVoiceStopEvent()); return; } - if (topics?.type == 5 || topics?.type == 7) { - bloc.add(XSVoiceTestEvent(topics?.keyWord??'', '0',UserUtil.getUser()!.id.toString())); + if (topics?.type == TopicType.voiceQuestion.value || + topics?.type == TopicType.voiceWord.value) { + bloc.add(XSVoiceStartEvent(topics?.keyWord??'', '0',UserUtil.getUser()!.id.toString())); } else { - bloc.add(XSVoiceTestEvent(topics?.word??'', '0',UserUtil.getUser()!.id.toString())); + bloc.add(XSVoiceStartEvent(topics?.word??'', '0',UserUtil.getUser()!.id.toString())); } }, child: Image.asset( diff --git a/lib/pages/practice/topic_type.dart b/lib/pages/practice/topic_type.dart index 91ac9ac..bcda94c 100644 --- a/lib/pages/practice/topic_type.dart +++ b/lib/pages/practice/topic_type.dart @@ -13,7 +13,10 @@ enum TopicType { questionImageSelect, ///语音问答 - voiceQuestion + voiceQuestion, + + ///跟读单词(目前没实现,但是有一处判断,就先把类型定义出来) + voiceWord } extension TopicTypeExtension on TopicType { @@ -29,6 +32,8 @@ extension TopicTypeExtension on TopicType { return 4; case TopicType.voiceQuestion: return 5; + case TopicType.voiceWord: + return 7; default: throw ArgumentError('Unknown topic type'); } diff --git a/lib/pages/practice/widgets/practice_header_widget.dart b/lib/pages/practice/widgets/practice_header_widget.dart index 1d7a091..08e7d7e 100644 --- a/lib/pages/practice/widgets/practice_header_widget.dart +++ b/lib/pages/practice/widgets/practice_header_widget.dart @@ -3,7 +3,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:wow_english/common/extension/string_extension.dart'; class PracticeHeaderWidget extends StatelessWidget { - const PracticeHeaderWidget({super.key, required this.onTap,this.title = ''}); + const PracticeHeaderWidget({super.key, required this.onTap, this.title = ''}); final Function() onTap; @@ -12,24 +12,23 @@ class PracticeHeaderWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - color: Colors.white, - height: 60.h, - child: AppBar( - leading: IconButton( - icon: Image.asset( - 'back_around'.assetPng, - width: 40, - height: 40, + color: Colors.white, + height: kToolbarHeight, + child: AppBar( + leading: IconButton( + icon: Image.asset( + 'back_around'.assetPng, + width: 40, + height: 40, + ), + onPressed: () { + onTap(); + }, ), - onPressed: () { - onTap(); - }, - ), - centerTitle: true, - title: IntrinsicWidth( - child: Container( + centerTitle: true, + title: Container( height: 40.h, - padding: EdgeInsets.symmetric(horizontal: 27.w), + padding: EdgeInsets.symmetric(horizontal: 27.w, vertical: 6.h), decoration: BoxDecoration( color: const Color(0xFF00B6F1), borderRadius: BorderRadius.circular(20.r), @@ -38,18 +37,11 @@ class PracticeHeaderWidget extends StatelessWidget { color: const Color(0xFF333333), ), ), - child: Center( - child: Text( + child: Text( title, - style: TextStyle( - fontSize: 15.sp, - color: Colors.white - ), + style: TextStyle(fontSize: 15.sp, color: Colors.white), ), - ) - ), - ) - ) - ); + ), + )); } -} \ No newline at end of file +} diff --git a/lib/pages/reading/bloc/reading_bloc.dart b/lib/pages/reading/bloc/reading_bloc.dart index 3012b82..9be43e7 100644 --- a/lib/pages/reading/bloc/reading_bloc.dart +++ b/lib/pages/reading/bloc/reading_bloc.dart @@ -179,7 +179,9 @@ class ReadingPageBloc void _pageControllerChange(CurrentPageIndexChangeEvent event, Emitter emitter) async { _currentPage = event.pageIndex; + debugPrint("WQF _playOriginalAudioInner begin"); _playOriginalAudioInner(null); + debugPrint("WQF _playOriginalAudioInner end"); emitter(CurrentPageIndexState()); } @@ -227,6 +229,7 @@ class ReadingPageBloc audioPlayer.stop(); } else { _isOriginAudioPlaying = true; + debugPrint("WQF _playOriginalAudioInner _isOriginAudioPlaying: true"); audioUrl ??= currentPageData()?.audioUrl ?? ''; _playAudio(audioUrl); } diff --git a/lib/pages/reading/reading_page.dart b/lib/pages/reading/reading_page.dart index 5947b0d..8e1c60a 100644 --- a/lib/pages/reading/reading_page.dart +++ b/lib/pages/reading/reading_page.dart @@ -77,7 +77,7 @@ class _ReadingPage extends StatelessWidget { }), Container( color: Colors.transparent, - height: 60.h, + height: kToolbarHeight, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -96,8 +96,8 @@ class _ReadingPage extends StatelessWidget { }, icon: Image.asset( 'back_around'.assetPng, - width: 40, - height: 40, + width: 40.w, + height: 40.h, )), ), Container( diff --git a/lib/pages/reading/widgets/reading_header_widget.dart b/lib/pages/reading/widgets/reading_header_widget.dart index 48fe594..2f93315 100644 --- a/lib/pages/reading/widgets/reading_header_widget.dart +++ b/lib/pages/reading/widgets/reading_header_widget.dart @@ -14,7 +14,7 @@ class ReadingHeaderWidget extends StatelessWidget { Widget build(BuildContext context) { return Container( color: Colors.white, - height: 60.h, + height: kToolbarHeight, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -26,8 +26,8 @@ class ReadingHeaderWidget extends StatelessWidget { }, icon: Image.asset( 'back_around'.assetPng, - width: 40, - height: 40, + width: 40.w, + height: 40.h, )), ), Container( diff --git a/lib/pages/repeatafter/widgets/repeat_after_item.dart b/lib/pages/repeatafter/widgets/repeat_after_item.dart index b796929..d2735bd 100644 --- a/lib/pages/repeatafter/widgets/repeat_after_item.dart +++ b/lib/pages/repeatafter/widgets/repeat_after_item.dart @@ -130,7 +130,7 @@ class RepeatAfterItem extends StatelessWidget { ), alignment: Alignment.center, child: Image.asset( - 'listen_lock'.assetPng, + 'iv_lock'.assetPng, height: 36.h, width: 41.w, ), diff --git a/lib/pages/section/section_page.dart b/lib/pages/section/section_page.dart index 78fc39f..5febdc4 100644 --- a/lib/pages/section/section_page.dart +++ b/lib/pages/section/section_page.dart @@ -7,7 +7,7 @@ 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/section_type.dart'; -import 'package:wow_english/pages/section/widgets/home_video_item.dart'; +import 'package:wow_english/pages/section/widgets/section_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'; @@ -158,15 +158,19 @@ class _SectionPageView extends StatelessWidget { bloc.add(CurrentUnitIndexChangeEvent(index)); }, itemBuilder: (context, index) { - return ScrollConfiguration( - ///去掉 Android 上默认的边缘拖拽效果 - behavior: ScrollConfiguration.of(context) - .copyWith(overscroll: false), - child: _itemTransCard( - bloc.getCourseUnitDetail(pageIndex: index), - index, - context), - ); + // return ScrollConfiguration( + // ///去掉 Android 上默认的边缘拖拽效果 + // behavior: ScrollConfiguration.of(context) + // .copyWith(overscroll: false), + // child: _itemTransCard( + // bloc.getCourseUnitDetail(pageIndex: index), + // index, + // context), + // ); + return _itemTransCard( + bloc.getCourseUnitDetail(pageIndex: index), + index, + context); }), ), // 设置外部padding, )), @@ -286,8 +290,8 @@ Widget _itemTransCard( bloc.add(RequestEnterClassEvent( sectionData.id.toString(), sectionData.courseType)); }, - child: SectionVideoItem( - unitEntity: bloc.courseUnitEntity, + child: SectionItem( + courseModuleId: bloc.courseUnitEntity.courseModuleCode, lessons: sectionData, ), ); diff --git a/lib/pages/section/widgets/home_video_item.dart b/lib/pages/section/widgets/section_item.dart index 7542f42..1adb3f8 100644 --- a/lib/pages/section/widgets/home_video_item.dart +++ b/lib/pages/section/widgets/section_item.dart @@ -7,65 +7,99 @@ 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}); +///环节item布局 +class SectionItem extends StatelessWidget { + const SectionItem({super.key, this.lessons, this.courseModuleId}); - final CourseUnitEntity? unitEntity; + final String? courseModuleId; 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: Stack( + children: [ + _normalItem(), + _lockWidget(), + ], + ) + ); + } + + Widget _normalItem() { + return 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, - ), - ) + ), + 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(courseModuleId ?? 'Phase-1').color, + borderRadius: BorderRadius.circular(6) ), - 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) ), - padding: EdgeInsets.symmetric(horizontal: 10.w), - child: Text( - lessons?.name??'', - maxLines: 1, - style: TextStyle( - fontSize: 25.sp, - color: const Color(0xFF333333) + ), + ) + ], + ), + ); + } + + ///锁定状态下蒙层视图 + Widget _lockWidget() { + return Visibility( + visible: lessons?.lock ?? false, + child: Container( + width: 165.w, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + 'gendubeij_mengban'.assetPng ), - ), + fit: BoxFit.fill ) - ], ), + alignment: Alignment.center, + // child: Image.asset( + // 'iv_lock'.assetPng, + // height: 36.h, + // width: 41.w, + // ), ), ); } diff --git a/lib/pages/shop/exchane/exchange_lesson_page.dart b/lib/pages/shop/exchane/exchange_lesson_page.dart index e640eec..531c99f 100644 --- a/lib/pages/shop/exchane/exchange_lesson_page.dart +++ b/lib/pages/shop/exchane/exchange_lesson_page.dart @@ -6,6 +6,7 @@ import 'package:wow_english/common/widgets/textfield_customer_widget.dart'; import 'package:wow_english/pages/shop/exchane/widegts/exchange_result_dialog.dart'; import 'package:wow_english/route/route.dart'; +import '../../../common/widgets/we_app_bar.dart'; import 'bloc/exchange_lesson_bloc.dart'; class ExchangeLessonPage extends StatelessWidget { @@ -29,102 +30,102 @@ class _ExchangeLessonPage extends StatelessWidget { showDialog( context: context, barrierDismissible: !state.result, - builder: (context){ + builder: (context) { return ExChangeResultDialog( - resultType:state.result, - onTap:(){ + resultType: state.result, + onTap: () { popPage(); - } - ); - }); + }); + }); } }, child: _exchangeLessonPageView(), ); } - Widget _exchangeLessonPageView() => BlocBuilder(builder: (context, state) { + Widget _exchangeLessonPageView() => + BlocBuilder( + builder: (context, state) { final bloc = BlocProvider.of(context); return Scaffold( - resizeToAvoidBottomInset: false, - body: Container( - color: Colors.white, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, + resizeToAvoidBottomInset: false, + body: Stack( children: [ - 10.5.verticalSpace, - Padding( - padding: EdgeInsets.symmetric(horizontal: 15.w), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, + Container( + color: Colors.white, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, children: [ - IconButton( - icon: Image.asset( - 'back_around'.assetPng, - width: 40, - height: 40, + 10.5.verticalSpace, + Padding( + padding: EdgeInsets.symmetric(horizontal: 15.w), + child: Center( + child: Image.asset( + 'wow_ex_lesson'.assetPng, + width: 139.w, + height: 81.h, + ), + ), + ), + Expanded( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 135.w), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextFieldCustomerWidget( + height: 55.h, + hitText: '请输入兑换码', + bgImageName: 'Input_layer_up', + textInputType: TextInputType.emailAddress, + controller: bloc.codeNumberController, + onChangeValue: (String value) { + bloc.add(CodeNumberChangeEvent()); + }, + ), + 21.5.verticalSpace, + GestureDetector( + onTap: () { + if (bloc.checkCode) { + bloc.add(CheckCodeEvent()); + } + }, + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage(bloc.checkCode + ? 'ex_sure'.assetPng + : 'ex_dis'.assetPng), + fit: BoxFit.fill), + ), + padding: EdgeInsets.symmetric( + horizontal: 27.w, vertical: 14.h), + child: Text( + '兑换', + style: TextStyle( + fontSize: 16.sp, color: Colors.white), + ), + ), + ) + ], + ), ), - color: Colors.white, - onPressed: () { - Navigator.pop(context); - }, ), Image.asset( - 'wow_ex_lesson'.assetPng, - width: 139.w, - height: 81.h, + 'bottom_grass'.assetPng, ), - SizedBox.fromSize(size: const Size(40.0, 40.0)) ], ), ), - Expanded( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 135.w), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - TextFieldCustomerWidget( - height: 55.h, - hitText: '请输入兑换码', - bgImageName: 'Input_layer_up', - textInputType: TextInputType.emailAddress, - controller: bloc.codeNumberController, - onChangeValue: (String value) { - bloc.add(CodeNumberChangeEvent()); - }, - ), - 21.5.verticalSpace, - GestureDetector( - onTap: () { - if (bloc.checkCode) { - bloc.add(CheckCodeEvent()); - } - }, - child: Container( - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage(bloc.checkCode ? 'ex_sure'.assetPng : 'ex_dis'.assetPng), - fit: BoxFit.fill), - ), - padding: EdgeInsets.symmetric(horizontal: 27.w, vertical: 14.h), - child: Text( - '兑换', - style: TextStyle(fontSize: 16.sp, color: Colors.white), - ), - ), - ) - ], - ), + const Positioned( + top: 0, + left: 0, + right: 0, + child: WEAppBar( + backgroundColor: Colors.transparent, ), ), - Image.asset( - 'bottom_grass'.assetPng, - ), ], - ), - ), - ); + )); }); } diff --git a/lib/pages/tab/tab_page.dart b/lib/pages/tab/tab_page.dart index 70ad7e7..b547bff 100644 --- a/lib/pages/tab/tab_page.dart +++ b/lib/pages/tab/tab_page.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:wow_english/pages/module/module_page.dart'; +import 'package:wow_english/pages/module/course_module_page.dart'; import '../unit/view.dart'; import 'blocs/tab_bloc.dart'; @@ -10,7 +10,7 @@ class TabPage extends StatelessWidget { final _pages =const [ UnitPage(), - ModulePage() + CourseModulePage() ]; final _tabIcons = const [ diff --git a/lib/pages/unit/view.dart b/lib/pages/unit/view.dart index fc6971c..bf82ee3 100644 --- a/lib/pages/unit/view.dart +++ b/lib/pages/unit/view.dart @@ -12,7 +12,7 @@ import '../../utils/toast_util.dart'; import 'bloc.dart'; import 'event.dart'; -// 课程列表页(多unit,参考口语星球的框或分割标志) +// 课程(单元)列表页(多unit,参考口语星球的框或分割标志) class UnitPage extends StatelessWidget { const UnitPage({super.key, this.courseModuleEntity}); @@ -57,7 +57,7 @@ class UnitPage extends StatelessWidget { return GestureDetector( onTap: () { if (data.lock == true) { - showToast('当前unit暂未解锁'); + showToast('当前课程暂未解锁'); return; } diff --git a/lib/pages/unit/widget/course_unit_item.dart b/lib/pages/unit/widget/course_unit_item.dart index 5428fc1..e47a09a 100644 --- a/lib/pages/unit/widget/course_unit_item.dart +++ b/lib/pages/unit/widget/course_unit_item.dart @@ -1,3 +1,4 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:wow_english/common/extension/string_extension.dart'; @@ -5,6 +6,7 @@ import 'package:wow_english/common/widgets/ow_image_widget.dart'; import '../../../models/course_unit_entity.dart'; +///课程(单元)item布局 class CourseUnitItem extends StatelessWidget { const CourseUnitItem( {super.key, required this.unitEntity, required this.unitLesson}); @@ -16,41 +18,74 @@ class CourseUnitItem extends StatelessWidget { Widget build(BuildContext context) { return Padding( padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 24.h), + child: Stack( + children: [ + _normalItem(), + _lockWidget(), + ], + ) + ); + } + + Widget _normalItem() { + return Container( + width: 165.w, + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 24.h), + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('gendubeij'.assetPng), fit: BoxFit.fill), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + border: Border.all( + width: 2, + color: const Color(0xFF140C10), + ), + borderRadius: BorderRadius.circular(6)), + child: OwImageWidget( + name: unitLesson.coverUrl ?? '', + fit: BoxFit.fitHeight, + ), + )), + 20.verticalSpace, + SizedBox( + height: 40.h, + child: Text( + unitLesson.name ?? '', + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: + TextStyle(fontSize: 11.sp, color: const Color(0xFF140C10)), + ), + ) + ], + ), + ); + } + + ///锁定状态下蒙层视图 + Widget _lockWidget() { + return Visibility( + visible: unitLesson.lock ?? false, child: Container( width: 165.w, - padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 24.h), decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage('gendubeij'.assetPng), fit: BoxFit.fill), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Container( - decoration: BoxDecoration( - border: Border.all( - width: 2, - color: const Color(0xFF140C10), - ), - borderRadius: BorderRadius.circular(6)), - child: OwImageWidget( - name: unitLesson.coverUrl ?? '', - fit: BoxFit.fitHeight, - ), - )), - 20.verticalSpace, - SizedBox( - height: 40.h, - child: Text( - unitLesson.name ?? '', - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: - TextStyle(fontSize: 11.sp, color: const Color(0xFF140C10)), - ), + image: DecorationImage( + image: AssetImage( + 'gendubeij_mengban'.assetPng + ), + fit: BoxFit.fill ) - ], + ), + alignment: Alignment.center, + child: Image.asset( + 'iv_lock'.assetPng, + height: 54.h, + width: 61.5.w, ), ), ); diff --git a/lib/pages/video/lookvideo/widgets/video_opera_widget.dart b/lib/pages/video/lookvideo/widgets/video_opera_widget.dart index cea5464..085509e 100644 --- a/lib/pages/video/lookvideo/widgets/video_opera_widget.dart +++ b/lib/pages/video/lookvideo/widgets/video_opera_widget.dart @@ -74,8 +74,8 @@ class _VideoOperaWidgetState extends State { }, child: Image.asset( 'back_around'.assetPng, - height: 40, - width: 40 + height: 40.h, + width: 40.w ), ), 18.horizontalSpace, diff --git a/lib/route/route.dart b/lib/route/route.dart index eecdf7f..8fddf58 100644 --- a/lib/route/route.dart +++ b/lib/route/route.dart @@ -11,7 +11,7 @@ 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/module/module_page.dart'; +import 'package:wow_english/pages/module/course_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'; @@ -115,7 +115,7 @@ class AppRouter { return CupertinoPageRoute( builder: (_) => const ForgetPasswordHomePage()); case AppRouteName.courseModule: - return CupertinoPageRoute(builder: (_) => const ModulePage()); + return CupertinoPageRoute(builder: (_) => const CourseModulePage()); case AppRouteName.courseUnit: CourseModuleEntity courseModuleEntity = CourseModuleEntity(); if (settings.arguments != null) {