Commit 02fc03661445f4e8d453fcd2a7416100b53162b0

Authored by xiaoyu
2 parents 11f39602 ae77d87f

Merge remote-tracking branch 'origin/feat-wqf-payment' into ios_umeng

.fvm/flutter_sdk 0 → 120000
  1 +/Users/stay/fvm/versions/3.19.2
0 2 \ No newline at end of file
... ...
.fvm/fvm_config.json 0 → 100644
  1 +{
  2 + "flutterSdkVersion": "3.19.2",
  3 + "flavors": {}
  4 +}
0 5 \ No newline at end of file
... ...
assets/images/listen_lock.png renamed to assets/images/iv_lock.png

3.79 KB

lib/common/widgets/throttledGesture_gesture_detector.dart 0 → 100644
  1 +import 'dart:async';
  2 +import 'package:flutter/material.dart';
  3 +
  4 +///带节流功能的GestureDetector
  5 +class ThrottledGestureDetector extends StatefulWidget {
  6 + final Widget child;
  7 + final VoidCallback onTap;
  8 + final int throttleTime;
  9 +
  10 + const ThrottledGestureDetector({
  11 + super.key,
  12 + required this.child,
  13 + required this.onTap,
  14 + this.throttleTime = 500, // 默认节流时间为500毫秒
  15 + });
  16 +
  17 + @override
  18 + _ThrottledGestureDetectorState createState() =>
  19 + _ThrottledGestureDetectorState();
  20 +}
  21 +
  22 +class _ThrottledGestureDetectorState extends State<ThrottledGestureDetector> {
  23 + bool _isThrottled = false;
  24 +
  25 + void _handleTap() {
  26 + if (!_isThrottled) {
  27 + widget.onTap();
  28 + _isThrottled = true;
  29 + Timer(Duration(milliseconds: widget.throttleTime), () {
  30 + _isThrottled = false;
  31 + });
  32 + }
  33 + }
  34 +
  35 + @override
  36 + Widget build(BuildContext context) {
  37 + return GestureDetector(
  38 + onTap: _handleTap,
  39 + child: widget.child,
  40 + );
  41 + }
  42 +}
... ...
lib/pages/listen/widgets/listen_item_widget.dart
... ... @@ -46,7 +46,7 @@ class ListenItemWidget extends StatelessWidget {
46 46 Visibility(
47 47 visible: entity?.lock??false,
48 48 child: Image.asset(
49   - 'listen_lock'.assetPng,
  49 + 'iv_lock'.assetPng,
50 50 height: 36.h,
51 51 width: 41.w,
52 52 ),
... ...
lib/pages/login/forgetpwd/forget_password_home_page.dart
... ... @@ -7,6 +7,7 @@ import &#39;package:wow_english/pages/login/loginpage/time_widget.dart&#39;;
7 7 import 'package:wow_english/pages/login/setpwd/set_pwd_page.dart';
8 8 import 'package:wow_english/utils/toast_util.dart';
9 9  
  10 +import '../../../common/widgets/we_app_bar.dart';
10 11 import 'bloc/forget_pwd_home_bloc.dart';
11 12  
12 13 class ForgetPasswordHomePage extends StatelessWidget {
... ... @@ -50,136 +51,118 @@ class _ForgetPasswordHomePageView extends StatelessWidget {
50 51 Widget _buildForgetPwdView() => BlocBuilder<ForgetPwdHomeBloc, ForgetPwdHomeState>(builder: (context, state) {
51 52 final bloc = BlocProvider.of<ForgetPwdHomeBloc>(context);
52 53 return Scaffold(
  54 + appBar: const WEAppBar(),
53 55 body: Container(
54 56 color: Colors.white,
55 57 child: SafeArea(
56   - child: Stack(
57   - children: [
58   - SingleChildScrollView(
59   - child: Padding(
60   - padding: EdgeInsets.only(left: 49.w, right: 10.w),
61   - child: Column(
62   - children: [
63   - 34.verticalSpace,
64   - Row(
65   - children: [
66   - Image.asset(
67   - 'wow_logo'.assetPng,
68   - height: 49.w,
69   - width: 83.5.h,
70   - ),
71   - 12.5.horizontalSpace,
72   - Text(
73   - '修改密码\n请输入您的手机号和验证码吧',
74   - style: TextStyle(fontSize: 16.sp, color: const Color(0xFF666666)),
75   - )
76   - ],
77   - ),
78   - Row(
79   - crossAxisAlignment: CrossAxisAlignment.start,
80   - children: [
81   - Expanded(
82   - child: Column(
83   - children: [
84   - 44.5.verticalSpace,
85   - Row(
86   - children: [
87   - Image.asset(
88   - 'phone'.assetPng,
89   - height: 45.h,
90   - width: 35.w,
91   - ),
92   - 15.horizontalSpace,
93   - Expanded(
94   - child: TextFieldCustomerWidget(
95   - height: 50.h,
96   - hitText: '请输入当前手机号',
97   - textInputType: TextInputType.phone,
98   - bgImageName: 'Input_layer_up',
99   - onChangeValue: (String value) {
100   - bloc.add(PhoneNumChangeEvent());
101   - },
102   - controller: bloc.phoneNumController,
103   - ))
104   - ],
105   - ),
106   - 11.5.verticalSpace,
107   - Row(
108   - mainAxisAlignment: MainAxisAlignment.spaceBetween,
109   - children: [
110   - Image.asset(
111   - 'lock'.assetPng,
112   - height: 34.h,
113   - width: 31.w,
114   - ),
115   - 18.5.horizontalSpace,
116   - Expanded(
117   - child: TextFieldCustomerWidget(
118   - hitText: '请输入验证码',
119   - bgImageName: 'Input_layer_down',
120   - onChangeValue: (String value) {
121   - bloc.add(CheckCodeChangeEvent());
122   - },
123   - textInputType: TextInputType.emailAddress,
124   - controller: bloc.checkNumController,
125   - )),
126   - 16.5.horizontalSpace,
127   - TimerWidget(
128   - pageType: 1,
129   - canSendSms: bloc.canSendSms,
130   - sendSmsEvent: () => bloc.add(SendSmsCodeEvent()),
131   - )
132   - ],
133   - )
134   - ],
135   - )),
136   - 2.verticalSpace,
137   - Image.asset(
138   - 'steven_bride'.assetPng,
139   - height: 173.h,
140   - width: 157.w,
141   - )
142   - ],
143   - ),
144   - GestureDetector(
145   - onTap: () {
146   - if (bloc.canSetPwd) {
147   - bloc.add(SetPassWordEvent());
148   - }
149   - },
150   - child: Container(
151   - decoration: BoxDecoration(
152   - image: DecorationImage(
153   - image: AssetImage(bloc.canSetPwd ? 'login_enter'.assetPng : 'login_enter_dis'.assetPng),
154   - fit: BoxFit.fill),
155   - ),
156   - padding: EdgeInsets.symmetric(horizontal: 28.w, vertical: 14.h),
157   - child: Text(
158   - '确定',
159   - style: TextStyle(fontSize: 16.sp, color: Colors.white),
160   - ),
161   - ),
162   - )
163   - ],
164   - ),
  58 + child: SingleChildScrollView(
  59 + child: Padding(
  60 + padding: EdgeInsets.only(left: 49.w, right: 10.w),
  61 + child: Column(
  62 + children: [
  63 + Row(
  64 + children: [
  65 + Image.asset(
  66 + 'wow_logo'.assetPng,
  67 + height: 49.w,
  68 + width: 83.5.h,
  69 + ),
  70 + 12.5.horizontalSpace,
  71 + Text(
  72 + '修改密码\n请输入您的手机号和验证码吧',
  73 + style: TextStyle(fontSize: 16.sp, color: const Color(0xFF666666)),
  74 + )
  75 + ],
165 76 ),
166   - ),
167   - Container(
168   - padding: EdgeInsets.only(top: 16.h),
169   - alignment: Alignment.topLeft,
170   - child: IconButton(
171   - onPressed: () {
172   - Navigator.pop(context);
173   - },
174   - icon: Image.asset(
175   - 'back_around'.assetPng,
176   - width: 40.w,
177   - height: 40.h,
178   - )
  77 + Row(
  78 + crossAxisAlignment: CrossAxisAlignment.start,
  79 + children: [
  80 + Expanded(
  81 + child: Column(
  82 + children: [
  83 + 44.5.verticalSpace,
  84 + Row(
  85 + children: [
  86 + Image.asset(
  87 + 'phone'.assetPng,
  88 + height: 45.h,
  89 + width: 35.w,
  90 + ),
  91 + 15.horizontalSpace,
  92 + Expanded(
  93 + child: TextFieldCustomerWidget(
  94 + height: 50.h,
  95 + hitText: '请输入当前手机号',
  96 + textInputType: TextInputType.phone,
  97 + bgImageName: 'Input_layer_up',
  98 + onChangeValue: (String value) {
  99 + bloc.add(PhoneNumChangeEvent());
  100 + },
  101 + controller: bloc.phoneNumController,
  102 + ))
  103 + ],
  104 + ),
  105 + 11.5.verticalSpace,
  106 + Row(
  107 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
  108 + children: [
  109 + Image.asset(
  110 + 'lock'.assetPng,
  111 + height: 34.h,
  112 + width: 31.w,
  113 + ),
  114 + 18.5.horizontalSpace,
  115 + Expanded(
  116 + child: TextFieldCustomerWidget(
  117 + hitText: '请输入验证码',
  118 + bgImageName: 'Input_layer_down',
  119 + onChangeValue: (String value) {
  120 + bloc.add(CheckCodeChangeEvent());
  121 + },
  122 + textInputType: TextInputType.emailAddress,
  123 + controller: bloc.checkNumController,
  124 + )),
  125 + 16.5.horizontalSpace,
  126 + TimerWidget(
  127 + pageType: 1,
  128 + canSendSms: bloc.canSendSms,
  129 + sendSmsEvent: () => bloc.add(SendSmsCodeEvent()),
  130 + )
  131 + ],
  132 + )
  133 + ],
  134 + )),
  135 + 2.verticalSpace,
  136 + Image.asset(
  137 + 'steven_bride'.assetPng,
  138 + height: 173.h,
  139 + width: 157.w,
  140 + )
  141 + ],
179 142 ),
180   - ),
181   - ]
182   - )
  143 + GestureDetector(
  144 + onTap: () {
  145 + if (bloc.canSetPwd) {
  146 + bloc.add(SetPassWordEvent());
  147 + }
  148 + },
  149 + child: Container(
  150 + decoration: BoxDecoration(
  151 + image: DecorationImage(
  152 + image: AssetImage(bloc.canSetPwd ? 'login_enter'.assetPng : 'login_enter_dis'.assetPng),
  153 + fit: BoxFit.fill),
  154 + ),
  155 + padding: EdgeInsets.symmetric(horizontal: 28.w, vertical: 14.h),
  156 + child: Text(
  157 + '确定',
  158 + style: TextStyle(fontSize: 16.sp, color: Colors.white),
  159 + ),
  160 + ),
  161 + )
  162 + ],
  163 + ),
  164 + ),
  165 + ),
183 166 ),
184 167 ),
185 168 );
... ...
lib/pages/module/module_page.dart renamed to lib/pages/module/course_module_page.dart
... ... @@ -9,9 +9,9 @@ import &#39;package:wow_english/route/route.dart&#39;;
9 9 import 'bloc/module_bloc.dart';
10 10 import 'widgets/module_item_widget.dart';
11 11  
12   -// 阶段(模块)列表页
13   -class ModulePage extends StatelessWidget {
14   - const ModulePage({super.key, this.starPageIndex});
  12 +// 课程阶段(模块)列表页
  13 +class CourseModulePage extends StatelessWidget {
  14 + const CourseModulePage({super.key, this.starPageIndex});
15 15  
16 16 final int? starPageIndex;
17 17  
... ... @@ -37,26 +37,7 @@ class _LessonPageView extends StatelessWidget {
37 37 return BlocListener<ModuleBloc, ModuleState>(
38 38 listener: (context, state) {},
39 39 child: Scaffold(
40   - appBar: WEAppBar(
41   - leading: IconButton(
42   - onPressed: () {
43   - popPage();
44   - },
45   - icon: Image.asset(
46   - 'back'.assetPng,
47   - height: 43,
48   - width: 43,
49   - )),
50   - // actions: <Widget>[
51   - // IconButton(
52   - // icon: Image.asset('shop'.assetPng),
53   - // color: Colors.white,
54   - // onPressed: () {
55   - // showToast('购买');
56   - // },
57   - // )
58   - // ],
59   - ),
  40 + appBar: const WEAppBar(),
60 41 body: _lessViewWidget(),
61 42 ),
62 43 );
... ...
lib/pages/module/widgets/module_item_widget.dart
... ... @@ -6,6 +6,7 @@ import &#39;package:wow_english/models/course_module_entity.dart&#39;;
6 6  
7 7 import '../../section/courese_module_model.dart';
8 8  
  9 +///阶段(模块)item布局
9 10 class ModuleItemWidget extends StatelessWidget {
10 11 const ModuleItemWidget({super.key, required this.isSelected, this.model, this.onClickEvent});
11 12 ///是否被选中
... ...
lib/pages/practice/bloc/topic_picture_bloc.dart
... ... @@ -83,7 +83,7 @@ class TopicPictureBloc extends BaseSectionBloc&lt;TopicPictureEvent, TopicPictureSt
83 83 on<XSVoiceInitEvent>(_initVoiceSdk);
84 84 on<SelectItemEvent>(_selectItemLoad);
85 85 on<RequestDataEvent>(_requestData);
86   - on<XSVoiceTestEvent>(_voiceXsTest);
  86 + on<XSVoiceStartEvent>(_voiceXsStart);
87 87 on<XSVoiceStopEvent>(_voiceXsStop);
88 88 on<VoicePlayEvent>(_questionVoicePlay);
89 89 on<InitBlocEvent>((event, emit) {
... ... @@ -231,7 +231,7 @@ class TopicPictureBloc extends BaseSectionBloc&lt;TopicPictureEvent, TopicPictureSt
231 231 }
232 232  
233 233 ///先声测试
234   - void _voiceXsTest(XSVoiceTestEvent event,Emitter<TopicPictureState> emitter) async {
  234 + void _voiceXsStart(XSVoiceStartEvent event,Emitter<TopicPictureState> emitter) async {
235 235 await audioPlayer.stop();
236 236 // 调用封装好的权限检查和请求方法
237 237 bool result = await permissionCheckAndRequest(
... ...
lib/pages/practice/bloc/topic_picture_event.dart
... ... @@ -14,11 +14,11 @@ class XSVoiceInitEvent extends TopicPictureEvent {
14 14 }
15 15  
16 16 ///开始评测
17   -class XSVoiceTestEvent extends TopicPictureEvent {
  17 +class XSVoiceStartEvent extends TopicPictureEvent {
18 18 final String testWord;
19 19 final String type;
20 20 final String userId;
21   - XSVoiceTestEvent(this.testWord,this.type,this.userId);
  21 + XSVoiceStartEvent(this.testWord,this.type,this.userId);
22 22 }
23 23  
24 24 ///终止评测
... ...
lib/pages/practice/topic_picture_page.dart
... ... @@ -10,6 +10,7 @@ import &#39;package:wow_english/pages/practice/topic_type.dart&#39;;
10 10 import 'package:wow_english/route/route.dart';
11 11 import 'package:wow_english/utils/toast_util.dart';
12 12  
  13 +import '../../common/widgets/throttledGesture_gesture_detector.dart';
13 14 import 'bloc/topic_picture_bloc.dart';
14 15 import 'widgets/practice_header_widget.dart';
15 16  
... ... @@ -479,20 +480,23 @@ class _TopicPicturePage extends StatelessWidget {
479 480 ),
480 481 ),
481 482 70.verticalSpace,
482   - GestureDetector(
  483 + ThrottledGestureDetector(
  484 + throttleTime: 1000,
483 485 onTap: () {
484 486 if (bloc.voicePlayState == VoicePlayState.playing) {
485   - showToast('正在播放音,不能终止');
  487 + showToast('正在播放音,不能终止');
486 488 return;
487 489 }
488 490  
489 491 if (bloc.isVoicing) {
  492 + bloc.add(XSVoiceStopEvent());
490 493 return;
491 494 }
492   - if (topics?.type == 5 || topics?.type == 7) {
493   - bloc.add(XSVoiceTestEvent(topics?.keyWord??'', '0',UserUtil.getUser()!.id.toString()));
  495 + if (topics?.type == TopicType.voiceQuestion.value ||
  496 + topics?.type == TopicType.voiceWord.value) {
  497 + bloc.add(XSVoiceStartEvent(topics?.keyWord??'', '0',UserUtil.getUser()!.id.toString()));
494 498 } else {
495   - bloc.add(XSVoiceTestEvent(topics?.word??'', '0',UserUtil.getUser()!.id.toString()));
  499 + bloc.add(XSVoiceStartEvent(topics?.word??'', '0',UserUtil.getUser()!.id.toString()));
496 500 }
497 501 },
498 502 child: Image.asset(
... ...
lib/pages/practice/topic_type.dart
... ... @@ -13,7 +13,10 @@ enum TopicType {
13 13 questionImageSelect,
14 14  
15 15 ///语音问答
16   - voiceQuestion
  16 + voiceQuestion,
  17 +
  18 + ///跟读单词(目前没实现,但是有一处判断,就先把类型定义出来)
  19 + voiceWord
17 20 }
18 21  
19 22 extension TopicTypeExtension on TopicType {
... ... @@ -29,6 +32,8 @@ extension TopicTypeExtension on TopicType {
29 32 return 4;
30 33 case TopicType.voiceQuestion:
31 34 return 5;
  35 + case TopicType.voiceWord:
  36 + return 7;
32 37 default:
33 38 throw ArgumentError('Unknown topic type');
34 39 }
... ...
lib/pages/practice/widgets/practice_header_widget.dart
... ... @@ -3,7 +3,7 @@ import &#39;package:flutter_screenutil/flutter_screenutil.dart&#39;;
3 3 import 'package:wow_english/common/extension/string_extension.dart';
4 4  
5 5 class PracticeHeaderWidget extends StatelessWidget {
6   - const PracticeHeaderWidget({super.key, required this.onTap,this.title = ''});
  6 + const PracticeHeaderWidget({super.key, required this.onTap, this.title = ''});
7 7  
8 8 final Function() onTap;
9 9  
... ... @@ -12,24 +12,23 @@ class PracticeHeaderWidget extends StatelessWidget {
12 12 @override
13 13 Widget build(BuildContext context) {
14 14 return Container(
15   - color: Colors.white,
16   - height: 60.h,
17   - child: AppBar(
18   - leading: IconButton(
19   - icon: Image.asset(
20   - 'back_around'.assetPng,
21   - width: 40,
22   - height: 40,
  15 + color: Colors.white,
  16 + height: kToolbarHeight,
  17 + child: AppBar(
  18 + leading: IconButton(
  19 + icon: Image.asset(
  20 + 'back_around'.assetPng,
  21 + width: 40,
  22 + height: 40,
  23 + ),
  24 + onPressed: () {
  25 + onTap();
  26 + },
23 27 ),
24   - onPressed: () {
25   - onTap();
26   - },
27   - ),
28   - centerTitle: true,
29   - title: IntrinsicWidth(
30   - child: Container(
  28 + centerTitle: true,
  29 + title: Container(
31 30 height: 40.h,
32   - padding: EdgeInsets.symmetric(horizontal: 27.w),
  31 + padding: EdgeInsets.symmetric(horizontal: 27.w, vertical: 6.h),
33 32 decoration: BoxDecoration(
34 33 color: const Color(0xFF00B6F1),
35 34 borderRadius: BorderRadius.circular(20.r),
... ... @@ -38,18 +37,11 @@ class PracticeHeaderWidget extends StatelessWidget {
38 37 color: const Color(0xFF333333),
39 38 ),
40 39 ),
41   - child: Center(
42   - child: Text(
  40 + child: Text(
43 41 title,
44   - style: TextStyle(
45   - fontSize: 15.sp,
46   - color: Colors.white
47   - ),
  42 + style: TextStyle(fontSize: 15.sp, color: Colors.white),
48 43 ),
49   - )
50   - ),
51   - )
52   - )
53   - );
  44 + ),
  45 + ));
54 46 }
55   -}
56 47 \ No newline at end of file
  48 +}
... ...
lib/pages/reading/bloc/reading_bloc.dart
... ... @@ -179,7 +179,9 @@ class ReadingPageBloc
179 179 void _pageControllerChange(CurrentPageIndexChangeEvent event,
180 180 Emitter<ReadingPageState> emitter) async {
181 181 _currentPage = event.pageIndex;
  182 + debugPrint("WQF _playOriginalAudioInner begin");
182 183 _playOriginalAudioInner(null);
  184 + debugPrint("WQF _playOriginalAudioInner end");
183 185 emitter(CurrentPageIndexState());
184 186 }
185 187  
... ... @@ -227,6 +229,7 @@ class ReadingPageBloc
227 229 audioPlayer.stop();
228 230 } else {
229 231 _isOriginAudioPlaying = true;
  232 + debugPrint("WQF _playOriginalAudioInner _isOriginAudioPlaying: true");
230 233 audioUrl ??= currentPageData()?.audioUrl ?? '';
231 234 _playAudio(audioUrl);
232 235 }
... ...
lib/pages/reading/reading_page.dart
... ... @@ -77,7 +77,7 @@ class _ReadingPage extends StatelessWidget {
77 77 }),
78 78 Container(
79 79 color: Colors.transparent,
80   - height: 60.h,
  80 + height: kToolbarHeight,
81 81 child: Row(
82 82 mainAxisAlignment: MainAxisAlignment.spaceBetween,
83 83 children: [
... ... @@ -96,8 +96,8 @@ class _ReadingPage extends StatelessWidget {
96 96 },
97 97 icon: Image.asset(
98 98 'back_around'.assetPng,
99   - width: 40,
100   - height: 40,
  99 + width: 40.w,
  100 + height: 40.h,
101 101 )),
102 102 ),
103 103 Container(
... ...
lib/pages/reading/widgets/reading_header_widget.dart
... ... @@ -14,7 +14,7 @@ class ReadingHeaderWidget extends StatelessWidget {
14 14 Widget build(BuildContext context) {
15 15 return Container(
16 16 color: Colors.white,
17   - height: 60.h,
  17 + height: kToolbarHeight,
18 18 child: Row(
19 19 mainAxisAlignment: MainAxisAlignment.spaceBetween,
20 20 children: [
... ... @@ -26,8 +26,8 @@ class ReadingHeaderWidget extends StatelessWidget {
26 26 },
27 27 icon: Image.asset(
28 28 'back_around'.assetPng,
29   - width: 40,
30   - height: 40,
  29 + width: 40.w,
  30 + height: 40.h,
31 31 )),
32 32 ),
33 33 Container(
... ...
lib/pages/repeatafter/widgets/repeat_after_item.dart
... ... @@ -130,7 +130,7 @@ class RepeatAfterItem extends StatelessWidget {
130 130 ),
131 131 alignment: Alignment.center,
132 132 child: Image.asset(
133   - 'listen_lock'.assetPng,
  133 + 'iv_lock'.assetPng,
134 134 height: 36.h,
135 135 width: 41.w,
136 136 ),
... ...
lib/pages/section/section_page.dart
... ... @@ -7,7 +7,7 @@ import &#39;package:wow_english/common/core/user_util.dart&#39;;
7 7 import 'package:wow_english/common/extension/string_extension.dart';
8 8 import 'package:wow_english/models/course_unit_entity.dart';
9 9 import 'package:wow_english/pages/section/section_type.dart';
10   -import 'package:wow_english/pages/section/widgets/home_video_item.dart';
  10 +import 'package:wow_english/pages/section/widgets/section_item.dart';
11 11 import 'package:wow_english/pages/section/widgets/section_bouns_item.dart';
12 12 import 'package:wow_english/pages/section/widgets/section_header_widget.dart';
13 13 import 'package:wow_english/route/route.dart';
... ... @@ -158,15 +158,19 @@ class _SectionPageView extends StatelessWidget {
158 158 bloc.add(CurrentUnitIndexChangeEvent(index));
159 159 },
160 160 itemBuilder: (context, index) {
161   - return ScrollConfiguration(
162   - ///去掉 Android 上默认的边缘拖拽效果
163   - behavior: ScrollConfiguration.of(context)
164   - .copyWith(overscroll: false),
165   - child: _itemTransCard(
166   - bloc.getCourseUnitDetail(pageIndex: index),
167   - index,
168   - context),
169   - );
  161 + // return ScrollConfiguration(
  162 + // ///去掉 Android 上默认的边缘拖拽效果
  163 + // behavior: ScrollConfiguration.of(context)
  164 + // .copyWith(overscroll: false),
  165 + // child: _itemTransCard(
  166 + // bloc.getCourseUnitDetail(pageIndex: index),
  167 + // index,
  168 + // context),
  169 + // );
  170 + return _itemTransCard(
  171 + bloc.getCourseUnitDetail(pageIndex: index),
  172 + index,
  173 + context);
170 174 }),
171 175 ), // 设置外部padding,
172 176 )),
... ... @@ -286,8 +290,8 @@ Widget _itemTransCard(
286 290 bloc.add(RequestEnterClassEvent(
287 291 sectionData.id.toString(), sectionData.courseType));
288 292 },
289   - child: SectionVideoItem(
290   - unitEntity: bloc.courseUnitEntity,
  293 + child: SectionItem(
  294 + courseModuleId: bloc.courseUnitEntity.courseModuleCode,
291 295 lessons: sectionData,
292 296 ),
293 297 );
... ...
lib/pages/section/widgets/home_video_item.dart renamed to lib/pages/section/widgets/section_item.dart
... ... @@ -7,65 +7,99 @@ import &#39;../../../models/course_section_entity.dart&#39;;
7 7 import '../../../models/course_unit_entity.dart';
8 8 import '../courese_module_model.dart';
9 9  
10   -class SectionVideoItem extends StatelessWidget {
11   - const SectionVideoItem({super.key, this.lessons, this.unitEntity});
  10 +///环节item布局
  11 +class SectionItem extends StatelessWidget {
  12 + const SectionItem({super.key, this.lessons, this.courseModuleId});
12 13  
13   - final CourseUnitEntity? unitEntity;
  14 + final String? courseModuleId;
14 15 final CourseSectionEntity? lessons;
15 16  
16 17 @override
17 18 Widget build(BuildContext context) {
18 19 return Padding(
19 20 padding: EdgeInsets.symmetric(horizontal: 12.w,vertical: 24.h),
20   - child: Container(
21   - width: 165.w,
22   - padding: EdgeInsets.symmetric(horizontal: 16.w,vertical: 24.h),
23   - decoration: BoxDecoration(
24   - image: DecorationImage(
25   - image: AssetImage('gendubeij'.assetPng),
26   - fit: BoxFit.fill
27   - ),
  21 + child: Stack(
  22 + children: [
  23 + _normalItem(),
  24 + _lockWidget(),
  25 + ],
  26 + )
  27 + );
  28 + }
  29 +
  30 + Widget _normalItem() {
  31 + return Container(
  32 + width: 165.w,
  33 + padding: EdgeInsets.symmetric(horizontal: 16.w,vertical: 24.h),
  34 + decoration: BoxDecoration(
  35 + image: DecorationImage(
  36 + image: AssetImage('gendubeij'.assetPng),
  37 + fit: BoxFit.fill
28 38 ),
29   - child: Column(
30   - mainAxisAlignment: MainAxisAlignment.spaceBetween,
31   - children: [
32   - Expanded(
33   - child: Container(
34   - decoration: BoxDecoration(
35   - border: Border.all(
36   - width: 2,
37   - color: const Color(0xFF140C10),
38   - ),
39   - borderRadius: BorderRadius.circular(6)
40   - ),
41   - child: OwImageWidget(
42   - name: lessons?.coverUrl??'',
43   - fit: BoxFit.fitHeight,
44   - ),
45   - )
  39 + ),
  40 + child: Column(
  41 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
  42 + children: [
  43 + Expanded(
  44 + child: Container(
  45 + decoration: BoxDecoration(
  46 + border: Border.all(
  47 + width: 2,
  48 + color: const Color(0xFF140C10),
  49 + ),
  50 + borderRadius: BorderRadius.circular(6)
  51 + ),
  52 + child: OwImageWidget(
  53 + name: lessons?.coverUrl??'',
  54 + fit: BoxFit.fitHeight,
  55 + ),
  56 + )
  57 + ),
  58 + 24.verticalSpace,
  59 + Container(
  60 + decoration: BoxDecoration(
  61 + border: Border.all(
  62 + width: 2,
  63 + color: const Color(0xFF140C10),
  64 + ),
  65 + color: CourseModuleModel(courseModuleId ?? 'Phase-1').color,
  66 + borderRadius: BorderRadius.circular(6)
46 67 ),
47   - 24.verticalSpace,
48   - Container(
49   - decoration: BoxDecoration(
50   - border: Border.all(
51   - width: 2,
52   - color: const Color(0xFF140C10),
53   - ),
54   - color: CourseModuleModel(unitEntity?.courseModuleCode??'Phase-1').color,
55   - borderRadius: BorderRadius.circular(6)
  68 + padding: EdgeInsets.symmetric(horizontal: 10.w),
  69 + child: Text(
  70 + lessons?.name??'',
  71 + maxLines: 1,
  72 + style: TextStyle(
  73 + fontSize: 25.sp,
  74 + color: const Color(0xFF333333)
56 75 ),
57   - padding: EdgeInsets.symmetric(horizontal: 10.w),
58   - child: Text(
59   - lessons?.name??'',
60   - maxLines: 1,
61   - style: TextStyle(
62   - fontSize: 25.sp,
63   - color: const Color(0xFF333333)
  76 + ),
  77 + )
  78 + ],
  79 + ),
  80 + );
  81 + }
  82 +
  83 + ///锁定状态下蒙层视图
  84 + Widget _lockWidget() {
  85 + return Visibility(
  86 + visible: lessons?.lock ?? false,
  87 + child: Container(
  88 + width: 165.w,
  89 + decoration: BoxDecoration(
  90 + image: DecorationImage(
  91 + image: AssetImage(
  92 + 'gendubeij_mengban'.assetPng
64 93 ),
65   - ),
  94 + fit: BoxFit.fill
66 95 )
67   - ],
68 96 ),
  97 + alignment: Alignment.center,
  98 + // child: Image.asset(
  99 + // 'iv_lock'.assetPng,
  100 + // height: 36.h,
  101 + // width: 41.w,
  102 + // ),
69 103 ),
70 104 );
71 105 }
... ...
lib/pages/shop/exchane/exchange_lesson_page.dart
... ... @@ -6,6 +6,7 @@ import &#39;package:wow_english/common/widgets/textfield_customer_widget.dart&#39;;
6 6 import 'package:wow_english/pages/shop/exchane/widegts/exchange_result_dialog.dart';
7 7 import 'package:wow_english/route/route.dart';
8 8  
  9 +import '../../../common/widgets/we_app_bar.dart';
9 10 import 'bloc/exchange_lesson_bloc.dart';
10 11  
11 12 class ExchangeLessonPage extends StatelessWidget {
... ... @@ -29,102 +30,102 @@ class _ExchangeLessonPage extends StatelessWidget {
29 30 showDialog<ExChangeResultDialog>(
30 31 context: context,
31 32 barrierDismissible: !state.result,
32   - builder: (context){
  33 + builder: (context) {
33 34 return ExChangeResultDialog(
34   - resultType:state.result,
35   - onTap:(){
  35 + resultType: state.result,
  36 + onTap: () {
36 37 popPage();
37   - }
38   - );
39   - });
  38 + });
  39 + });
40 40 }
41 41 },
42 42 child: _exchangeLessonPageView(),
43 43 );
44 44 }
45 45  
46   - Widget _exchangeLessonPageView() => BlocBuilder<ExchangeLessonBloc, ExchangeLessonState>(builder: (context, state) {
  46 + Widget _exchangeLessonPageView() =>
  47 + BlocBuilder<ExchangeLessonBloc, ExchangeLessonState>(
  48 + builder: (context, state) {
47 49 final bloc = BlocProvider.of<ExchangeLessonBloc>(context);
48 50 return Scaffold(
49   - resizeToAvoidBottomInset: false,
50   - body: Container(
51   - color: Colors.white,
52   - child: Column(
53   - mainAxisAlignment: MainAxisAlignment.center,
  51 + resizeToAvoidBottomInset: false,
  52 + body: Stack(
54 53 children: [
55   - 10.5.verticalSpace,
56   - Padding(
57   - padding: EdgeInsets.symmetric(horizontal: 15.w),
58   - child: Row(
59   - mainAxisAlignment: MainAxisAlignment.spaceBetween,
60   - crossAxisAlignment: CrossAxisAlignment.start,
  54 + Container(
  55 + color: Colors.white,
  56 + child: Column(
  57 + mainAxisAlignment: MainAxisAlignment.center,
61 58 children: [
62   - IconButton(
63   - icon: Image.asset(
64   - 'back_around'.assetPng,
65   - width: 40,
66   - height: 40,
  59 + 10.5.verticalSpace,
  60 + Padding(
  61 + padding: EdgeInsets.symmetric(horizontal: 15.w),
  62 + child: Center(
  63 + child: Image.asset(
  64 + 'wow_ex_lesson'.assetPng,
  65 + width: 139.w,
  66 + height: 81.h,
  67 + ),
  68 + ),
  69 + ),
  70 + Expanded(
  71 + child: Padding(
  72 + padding: EdgeInsets.symmetric(horizontal: 135.w),
  73 + child: Column(
  74 + mainAxisAlignment: MainAxisAlignment.center,
  75 + children: [
  76 + TextFieldCustomerWidget(
  77 + height: 55.h,
  78 + hitText: '请输入兑换码',
  79 + bgImageName: 'Input_layer_up',
  80 + textInputType: TextInputType.emailAddress,
  81 + controller: bloc.codeNumberController,
  82 + onChangeValue: (String value) {
  83 + bloc.add(CodeNumberChangeEvent());
  84 + },
  85 + ),
  86 + 21.5.verticalSpace,
  87 + GestureDetector(
  88 + onTap: () {
  89 + if (bloc.checkCode) {
  90 + bloc.add(CheckCodeEvent());
  91 + }
  92 + },
  93 + child: Container(
  94 + decoration: BoxDecoration(
  95 + image: DecorationImage(
  96 + image: AssetImage(bloc.checkCode
  97 + ? 'ex_sure'.assetPng
  98 + : 'ex_dis'.assetPng),
  99 + fit: BoxFit.fill),
  100 + ),
  101 + padding: EdgeInsets.symmetric(
  102 + horizontal: 27.w, vertical: 14.h),
  103 + child: Text(
  104 + '兑换',
  105 + style: TextStyle(
  106 + fontSize: 16.sp, color: Colors.white),
  107 + ),
  108 + ),
  109 + )
  110 + ],
  111 + ),
67 112 ),
68   - color: Colors.white,
69   - onPressed: () {
70   - Navigator.pop(context);
71   - },
72 113 ),
73 114 Image.asset(
74   - 'wow_ex_lesson'.assetPng,
75   - width: 139.w,
76   - height: 81.h,
  115 + 'bottom_grass'.assetPng,
77 116 ),
78   - SizedBox.fromSize(size: const Size(40.0, 40.0))
79 117 ],
80 118 ),
81 119 ),
82   - Expanded(
83   - child: Padding(
84   - padding: EdgeInsets.symmetric(horizontal: 135.w),
85   - child: Column(
86   - mainAxisAlignment: MainAxisAlignment.center,
87   - children: [
88   - TextFieldCustomerWidget(
89   - height: 55.h,
90   - hitText: '请输入兑换码',
91   - bgImageName: 'Input_layer_up',
92   - textInputType: TextInputType.emailAddress,
93   - controller: bloc.codeNumberController,
94   - onChangeValue: (String value) {
95   - bloc.add(CodeNumberChangeEvent());
96   - },
97   - ),
98   - 21.5.verticalSpace,
99   - GestureDetector(
100   - onTap: () {
101   - if (bloc.checkCode) {
102   - bloc.add(CheckCodeEvent());
103   - }
104   - },
105   - child: Container(
106   - decoration: BoxDecoration(
107   - image: DecorationImage(
108   - image: AssetImage(bloc.checkCode ? 'ex_sure'.assetPng : 'ex_dis'.assetPng),
109   - fit: BoxFit.fill),
110   - ),
111   - padding: EdgeInsets.symmetric(horizontal: 27.w, vertical: 14.h),
112   - child: Text(
113   - '兑换',
114   - style: TextStyle(fontSize: 16.sp, color: Colors.white),
115   - ),
116   - ),
117   - )
118   - ],
119   - ),
  120 + const Positioned(
  121 + top: 0,
  122 + left: 0,
  123 + right: 0,
  124 + child: WEAppBar(
  125 + backgroundColor: Colors.transparent,
120 126 ),
121 127 ),
122   - Image.asset(
123   - 'bottom_grass'.assetPng,
124   - ),
125 128 ],
126   - ),
127   - ),
128   - );
  129 + ));
129 130 });
130 131 }
... ...
lib/pages/tab/tab_page.dart
1 1 import 'package:flutter/material.dart';
2 2 import 'package:flutter_bloc/flutter_bloc.dart';
3   -import 'package:wow_english/pages/module/module_page.dart';
  3 +import 'package:wow_english/pages/module/course_module_page.dart';
4 4  
5 5 import '../unit/view.dart';
6 6 import 'blocs/tab_bloc.dart';
... ... @@ -10,7 +10,7 @@ class TabPage extends StatelessWidget {
10 10  
11 11 final _pages =const <Widget>[
12 12 UnitPage(),
13   - ModulePage()
  13 + CourseModulePage()
14 14 ];
15 15  
16 16 final _tabIcons = const <Icon>[
... ...
lib/pages/unit/view.dart
... ... @@ -12,7 +12,7 @@ import &#39;../../utils/toast_util.dart&#39;;
12 12 import 'bloc.dart';
13 13 import 'event.dart';
14 14  
15   -// 课程列表页(多unit,参考口语星球的框或分割标志)
  15 +// 课程(单元)列表页(多unit,参考口语星球的框或分割标志)
16 16 class UnitPage extends StatelessWidget {
17 17 const UnitPage({super.key, this.courseModuleEntity});
18 18  
... ... @@ -57,7 +57,7 @@ class UnitPage extends StatelessWidget {
57 57 return GestureDetector(
58 58 onTap: () {
59 59 if (data.lock == true) {
60   - showToast('当前unit暂未解锁');
  60 + showToast('当前课程暂未解锁');
61 61 return;
62 62 }
63 63  
... ...
lib/pages/unit/widget/course_unit_item.dart
  1 +import 'package:flutter/cupertino.dart';
1 2 import 'package:flutter/material.dart';
2 3 import 'package:flutter_screenutil/flutter_screenutil.dart';
3 4 import 'package:wow_english/common/extension/string_extension.dart';
... ... @@ -5,6 +6,7 @@ import &#39;package:wow_english/common/widgets/ow_image_widget.dart&#39;;
5 6  
6 7 import '../../../models/course_unit_entity.dart';
7 8  
  9 +///课程(单元)item布局
8 10 class CourseUnitItem extends StatelessWidget {
9 11 const CourseUnitItem(
10 12 {super.key, required this.unitEntity, required this.unitLesson});
... ... @@ -16,41 +18,74 @@ class CourseUnitItem extends StatelessWidget {
16 18 Widget build(BuildContext context) {
17 19 return Padding(
18 20 padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 24.h),
  21 + child: Stack(
  22 + children: [
  23 + _normalItem(),
  24 + _lockWidget(),
  25 + ],
  26 + )
  27 + );
  28 + }
  29 +
  30 + Widget _normalItem() {
  31 + return Container(
  32 + width: 165.w,
  33 + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 24.h),
  34 + decoration: BoxDecoration(
  35 + image: DecorationImage(
  36 + image: AssetImage('gendubeij'.assetPng), fit: BoxFit.fill),
  37 + ),
  38 + child: Column(
  39 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
  40 + children: [
  41 + Expanded(
  42 + child: Container(
  43 + decoration: BoxDecoration(
  44 + border: Border.all(
  45 + width: 2,
  46 + color: const Color(0xFF140C10),
  47 + ),
  48 + borderRadius: BorderRadius.circular(6)),
  49 + child: OwImageWidget(
  50 + name: unitLesson.coverUrl ?? '',
  51 + fit: BoxFit.fitHeight,
  52 + ),
  53 + )),
  54 + 20.verticalSpace,
  55 + SizedBox(
  56 + height: 40.h,
  57 + child: Text(
  58 + unitLesson.name ?? '',
  59 + maxLines: 2,
  60 + overflow: TextOverflow.ellipsis,
  61 + style:
  62 + TextStyle(fontSize: 11.sp, color: const Color(0xFF140C10)),
  63 + ),
  64 + )
  65 + ],
  66 + ),
  67 + );
  68 + }
  69 +
  70 + ///锁定状态下蒙层视图
  71 + Widget _lockWidget() {
  72 + return Visibility(
  73 + visible: unitLesson.lock ?? false,
19 74 child: Container(
20 75 width: 165.w,
21   - padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 24.h),
22 76 decoration: BoxDecoration(
23   - image: DecorationImage(
24   - image: AssetImage('gendubeij'.assetPng), fit: BoxFit.fill),
25   - ),
26   - child: Column(
27   - mainAxisAlignment: MainAxisAlignment.spaceBetween,
28   - children: [
29   - Expanded(
30   - child: Container(
31   - decoration: BoxDecoration(
32   - border: Border.all(
33   - width: 2,
34   - color: const Color(0xFF140C10),
35   - ),
36   - borderRadius: BorderRadius.circular(6)),
37   - child: OwImageWidget(
38   - name: unitLesson.coverUrl ?? '',
39   - fit: BoxFit.fitHeight,
40   - ),
41   - )),
42   - 20.verticalSpace,
43   - SizedBox(
44   - height: 40.h,
45   - child: Text(
46   - unitLesson.name ?? '',
47   - maxLines: 2,
48   - overflow: TextOverflow.ellipsis,
49   - style:
50   - TextStyle(fontSize: 11.sp, color: const Color(0xFF140C10)),
51   - ),
  77 + image: DecorationImage(
  78 + image: AssetImage(
  79 + 'gendubeij_mengban'.assetPng
  80 + ),
  81 + fit: BoxFit.fill
52 82 )
53   - ],
  83 + ),
  84 + alignment: Alignment.center,
  85 + child: Image.asset(
  86 + 'iv_lock'.assetPng,
  87 + height: 54.h,
  88 + width: 61.5.w,
54 89 ),
55 90 ),
56 91 );
... ...
lib/pages/video/lookvideo/widgets/video_opera_widget.dart
... ... @@ -74,8 +74,8 @@ class _VideoOperaWidgetState extends State&lt;VideoOperaWidget&gt; {
74 74 },
75 75 child: Image.asset(
76 76 'back_around'.assetPng,
77   - height: 40,
78   - width: 40
  77 + height: 40.h,
  78 + width: 40.w
79 79 ),
80 80 ),
81 81 18.horizontalSpace,
... ...
lib/route/route.dart
... ... @@ -11,7 +11,7 @@ import &#39;package:wow_english/pages/listen/listen_page.dart&#39;;
11 11 import 'package:wow_english/pages/login/forgetpwd/forget_password_home_page.dart';
12 12 import 'package:wow_english/pages/login/loginpage/login_page.dart';
13 13 import 'package:wow_english/pages/login/setpwd/set_pwd_page.dart';
14   -import 'package:wow_english/pages/module/module_page.dart';
  14 +import 'package:wow_english/pages/module/course_module_page.dart';
15 15 import 'package:wow_english/pages/practice/topic_picture_page.dart';
16 16 import 'package:wow_english/pages/repeatafter/repeat_after_page.dart';
17 17 import 'package:wow_english/pages/repeataftercontent/repeat_after_content_page.dart';
... ... @@ -115,7 +115,7 @@ class AppRouter {
115 115 return CupertinoPageRoute(
116 116 builder: (_) => const ForgetPasswordHomePage());
117 117 case AppRouteName.courseModule:
118   - return CupertinoPageRoute(builder: (_) => const ModulePage());
  118 + return CupertinoPageRoute(builder: (_) => const CourseModulePage());
119 119 case AppRouteName.courseUnit:
120 120 CourseModuleEntity courseModuleEntity = CourseModuleEntity();
121 121 if (settings.arguments != null) {
... ...