Commit 934e2b4731a8a7fc1da8ab39782f5ac7707a07a4

Authored by liangchengyou
1 parent a63404a0

feat:权限调整+课程进度接口对接

lib/common/dialogs/customer_dialog.dart
@@ -20,12 +20,12 @@ class CustomerTwoActionDialog extends Dialog { @@ -20,12 +20,12 @@ class CustomerTwoActionDialog extends Dialog {
20 Widget build(BuildContext context) { 20 Widget build(BuildContext context) {
21 super.build(context); 21 super.build(context);
22 return Container( 22 return Container(
23 - height: 238.h, 23 + height: 208.h,
24 alignment: Alignment.center, 24 alignment: Alignment.center,
25 child: ConstrainedBox( 25 child: ConstrainedBox(
26 constraints: BoxConstraints( 26 constraints: BoxConstraints(
27 - maxHeight: 238.h,  
28 - maxWidth: 407.w 27 + maxHeight: 208.h,
  28 + maxWidth: 247.w
29 ), 29 ),
30 child: Container( 30 child: Container(
31 padding: EdgeInsets.symmetric(horizontal: 24.w,vertical: 15.h), 31 padding: EdgeInsets.symmetric(horizontal: 24.w,vertical: 15.h),
@@ -48,13 +48,16 @@ class CustomerTwoActionDialog extends Dialog { @@ -48,13 +48,16 @@ class CustomerTwoActionDialog extends Dialog {
48 ), 48 ),
49 ), 49 ),
50 Expanded( 50 Expanded(
51 - child: Text(  
52 - content,  
53 - textAlign: TextAlign.left,  
54 - style: TextStyle(  
55 - color: const Color(0xFF333333),  
56 - fontSize: 13.sp  
57 - ) 51 + child: Container(
  52 + alignment: Alignment.center,
  53 + child: Text(
  54 + content,
  55 + textAlign: TextAlign.left,
  56 + style: TextStyle(
  57 + color: const Color(0xFF333333),
  58 + fontSize: 13.sp
  59 + )
  60 + ),
58 ), 61 ),
59 ), 62 ),
60 Row( 63 Row(
@@ -63,9 +66,8 @@ class CustomerTwoActionDialog extends Dialog { @@ -63,9 +66,8 @@ class CustomerTwoActionDialog extends Dialog {
63 TextButton( 66 TextButton(
64 onPressed: leftTap, 67 onPressed: leftTap,
65 child: Container( 68 child: Container(
66 - height: 31.h,  
67 padding: EdgeInsets.symmetric( 69 padding: EdgeInsets.symmetric(
68 - horizontal: 6.w 70 + horizontal: 6.w,vertical: 2.h
69 ), 71 ),
70 decoration: BoxDecoration( 72 decoration: BoxDecoration(
71 color: const Color(0xFFFBB661), 73 color: const Color(0xFFFBB661),
@@ -87,7 +89,6 @@ class CustomerTwoActionDialog extends Dialog { @@ -87,7 +89,6 @@ class CustomerTwoActionDialog extends Dialog {
87 TextButton( 89 TextButton(
88 onPressed: rightTap, 90 onPressed: rightTap,
89 child: Container( 91 child: Container(
90 - height: 31.h,  
91 decoration: BoxDecoration( 92 decoration: BoxDecoration(
92 color: Colors.white, 93 color: Colors.white,
93 border: Border.all( 94 border: Border.all(
@@ -97,8 +98,9 @@ class CustomerTwoActionDialog extends Dialog { @@ -97,8 +98,9 @@ class CustomerTwoActionDialog extends Dialog {
97 borderRadius: BorderRadius.circular(10.r) 98 borderRadius: BorderRadius.circular(10.r)
98 ), 99 ),
99 padding: EdgeInsets.symmetric( 100 padding: EdgeInsets.symmetric(
100 - horizontal: 6.w 101 + horizontal: 6.w,vertical: 2.h
101 ), 102 ),
  103 + alignment: Alignment.center,
102 child: Text( 104 child: Text(
103 rightTitle, 105 rightTitle,
104 textAlign: TextAlign.center, 106 textAlign: TextAlign.center,
@@ -131,8 +133,8 @@ class CustomerOneActionDialog extends Dialog { @@ -131,8 +133,8 @@ class CustomerOneActionDialog extends Dialog {
131 alignment: Alignment.center, 133 alignment: Alignment.center,
132 child: ConstrainedBox( 134 child: ConstrainedBox(
133 constraints: BoxConstraints( 135 constraints: BoxConstraints(
134 - maxHeight: 238.h,  
135 - maxWidth: 407.w 136 + maxHeight: 208.h,
  137 + maxWidth: 247.w
136 ), 138 ),
137 child: Container( 139 child: Container(
138 padding: EdgeInsets.symmetric(horizontal: 24.w,vertical: 15.h), 140 padding: EdgeInsets.symmetric(horizontal: 24.w,vertical: 15.h),
lib/common/request/apis.dart
@@ -76,4 +76,10 @@ class Apis { @@ -76,4 +76,10 @@ class Apis {
76 76
77 /// 获取阿里云oss鉴权信息 77 /// 获取阿里云oss鉴权信息
78 static const String aliyunOssSts = 'oss/sts/upload'; 78 static const String aliyunOssSts = 'oss/sts/upload';
  79 +
  80 + /// 进入课堂
  81 + static const String enterClass = 'course/enter/class';
  82 +
  83 + /// 退出课堂
  84 + static const String exitClass = 'course/exit/class';
79 } 85 }
lib/common/request/dao/listen_dao.dart
@@ -35,4 +35,16 @@ class ListenDao { @@ -35,4 +35,16 @@ class ListenDao {
35 var data = await requestClient.post(Apis.followResult,data: {'frequency':frequency,'videoFollowReadId':videoFollowReadId}); 35 var data = await requestClient.post(Apis.followResult,data: {'frequency':frequency,'videoFollowReadId':videoFollowReadId});
36 return data; 36 return data;
37 } 37 }
  38 +
  39 + ///进入课堂
  40 + static Future enterClass(courseLessonId) async {
  41 + var data = await requestClient.post(Apis.enterClass,data: {'courseLessonId':courseLessonId});
  42 + return data;
  43 + }
  44 +
  45 + ///退出课堂
  46 + static Future exitClass(courseLessonId,currentStep,currentTime) async {
  47 + var data = await requestClient.post(Apis.exitClass,data: {'courseLessonId':courseLessonId,'currentStep':currentStep,'currentTime':currentTime});
  48 + return data;
  49 + }
38 } 50 }
lib/common/request/request_client.dart
@@ -45,10 +45,10 @@ class RequestClient { @@ -45,10 +45,10 @@ class RequestClient {
45 data = _convertRequestData(data); 45 data = _convertRequestData(data);
46 46
47 Response response = await _dio.request(url, queryParameters: queryParameters, data: data, options: options); 47 Response response = await _dio.request(url, queryParameters: queryParameters, data: data, options: options);
48 - print("response.body type=${response.data.runtimeType}"); 48 + debugPrint("response.body type=${response.data.runtimeType}");
49 return _handleResponse<T>(response, onResponse); 49 return _handleResponse<T>(response, onResponse);
50 } catch (e) { 50 } catch (e) {
51 - print("e type=${e.runtimeType}"); 51 + debugPrint("e type=${e.runtimeType}");
52 if (e is ApiException && e.code == 405) { 52 if (e is ApiException && e.code == 405) {
53 showToast('登录已失效,请重新登录!', duration: const Duration(seconds: 3)); 53 showToast('登录已失效,请重新登录!', duration: const Duration(seconds: 3));
54 UserUtil.logout(); 54 UserUtil.logout();
@@ -166,7 +166,7 @@ class RequestClient { @@ -166,7 +166,7 @@ class RequestClient {
166 } 166 }
167 } else { 167 } else {
168 ApiException exception = ApiException(response.statusCode, ApiException.unknownException); 168 ApiException exception = ApiException(response.statusCode, ApiException.unknownException);
169 - print("_handleResponse exception type=${exception.runtimeType}"); 169 + debugPrint("_handleResponse exception type=${exception.runtimeType}");
170 throw exception; 170 throw exception;
171 } 171 }
172 } 172 }
@@ -177,7 +177,7 @@ class RequestClient { @@ -177,7 +177,7 @@ class RequestClient {
177 return response.data; 177 return response.data;
178 } else { 178 } else {
179 ApiException exception = ApiException(response.code, response.msg); 179 ApiException exception = ApiException(response.code, response.msg);
180 - print("_handleBusinessResponse exception type=${exception.runtimeType}"); 180 + debugPrint("_handleBusinessResponse exception type=${exception.runtimeType}");
181 throw exception; 181 throw exception;
182 } 182 }
183 } 183 }
lib/common/request/token_interceptor.dart
1 import 'package:dio/dio.dart'; 1 import 'package:dio/dio.dart';
  2 +import 'package:package_info_plus/package_info_plus.dart';
2 import 'package:wow_english/common/core/user_util.dart'; 3 import 'package:wow_english/common/core/user_util.dart';
  4 +import 'package:wow_english/common/request/basic_config.dart';
3 5
4 class TokenInterceptor extends Interceptor { 6 class TokenInterceptor extends Interceptor {
5 @override 7 @override
lib/pages/home/bloc/home_bloc.dart
@@ -26,6 +26,8 @@ class HomeBloc extends Bloc&lt;HomeEvent, HomeState&gt; { @@ -26,6 +26,8 @@ class HomeBloc extends Bloc&lt;HomeEvent, HomeState&gt; {
26 26
27 HomeBloc(this.moduleId) : super(HomeInitial()) { 27 HomeBloc(this.moduleId) : super(HomeInitial()) {
28 on<RequestDataEvent>(_requestData); 28 on<RequestDataEvent>(_requestData);
  29 + on<RequestExitClassEvent>(_requestExitClass);
  30 + on<RequestEnterClassEvent>(_requestEnterClass);
29 on<RequestVideoLessonEvent>(_requestVideoLesson); 31 on<RequestVideoLessonEvent>(_requestVideoLesson);
30 } 32 }
31 33
@@ -46,7 +48,7 @@ class HomeBloc extends Bloc&lt;HomeEvent, HomeState&gt; { @@ -46,7 +48,7 @@ class HomeBloc extends Bloc&lt;HomeEvent, HomeState&gt; {
46 try { 48 try {
47 await loading(() async { 49 await loading(() async {
48 _processEntity = await ListenDao.process(event.courseLessonId); 50 _processEntity = await ListenDao.process(event.courseLessonId);
49 - emitter(RequestVideoLessonState(event.courseType)); 51 + emitter(RequestVideoLessonState(event.courseLessonId,event.courseType));
50 }); 52 });
51 } catch (e) { 53 } catch (e) {
52 if (e is ApiException) { 54 if (e is ApiException) {
@@ -54,4 +56,22 @@ class HomeBloc extends Bloc&lt;HomeEvent, HomeState&gt; { @@ -54,4 +56,22 @@ class HomeBloc extends Bloc&lt;HomeEvent, HomeState&gt; {
54 } 56 }
55 } 57 }
56 } 58 }
  59 +
  60 +
  61 + void _requestEnterClass(RequestEnterClassEvent event,Emitter<HomeState> emitter) async {
  62 + try {
  63 + await loading(() async {
  64 + await ListenDao.enterClass(event.courseLessonId);
  65 + emitter(RequestEnterClassState(event.courseLessonId,event.courseType));
  66 + });
  67 + } catch (e) {
  68 + if (e is ApiException) {
  69 + showToast(e.message??'请求失败,请检查网络连接');
  70 + }
  71 + }
  72 + }
  73 +
  74 + void _requestExitClass(RequestExitClassEvent event,Emitter<HomeState> emitter) async {
  75 + await ListenDao.exitClass(event.courseLessonId,event.currentStep,event.currentTime);
  76 + }
57 } 77 }
lib/pages/home/bloc/home_event.dart
@@ -11,3 +11,18 @@ class RequestVideoLessonEvent extends HomeEvent { @@ -11,3 +11,18 @@ class RequestVideoLessonEvent extends HomeEvent {
11 final int courseType; 11 final int courseType;
12 RequestVideoLessonEvent(this.courseLessonId, this.courseType); 12 RequestVideoLessonEvent(this.courseLessonId, this.courseType);
13 } 13 }
  14 +
  15 +///进入课堂
  16 +class RequestEnterClassEvent extends HomeEvent {
  17 + final String courseLessonId;
  18 + final int courseType;
  19 + RequestEnterClassEvent(this.courseLessonId,this.courseType);
  20 +}
  21 +
  22 +///退出课堂
  23 +class RequestExitClassEvent extends HomeEvent {
  24 + final String courseLessonId;
  25 + final String currentStep;
  26 + final String currentTime;
  27 + RequestExitClassEvent(this.courseLessonId,this.currentStep,this.currentTime);
  28 +}
lib/pages/home/bloc/home_state.dart
@@ -8,6 +8,13 @@ class HomeInitial extends HomeState {} @@ -8,6 +8,13 @@ class HomeInitial extends HomeState {}
8 class HomeDataLoadState extends HomeState {} 8 class HomeDataLoadState extends HomeState {}
9 9
10 class RequestVideoLessonState extends HomeState { 10 class RequestVideoLessonState extends HomeState {
  11 + final String courseLessonId;
11 final int type; 12 final int type;
12 - RequestVideoLessonState(this.type); 13 + RequestVideoLessonState(this.courseLessonId,this.type);
  14 +}
  15 +
  16 +class RequestEnterClassState extends HomeState{
  17 + final String courseLessonId;
  18 + final int courseType;
  19 + RequestEnterClassState(this.courseLessonId,this.courseType);
13 } 20 }
lib/pages/home/home_page.dart
@@ -73,10 +73,56 @@ class _HomePageView extends StatelessWidget { @@ -73,10 +73,56 @@ class _HomePageView extends StatelessWidget {
73 title = 'bonus'; 73 title = 'bonus';
74 } 74 }
75 75
76 - if (videoUrl.isEmpty && !videoUrl.contains('http')) { 76 + if (videoUrl.isEmpty || !videoUrl.contains('http')) {
  77 + return;
  78 + }
  79 + pushNamed(AppRouteName.lookVideo,arguments: {'videoUrl':videoUrl,'title':title,'courseLessonId':state.courseLessonId}).then((value) {
  80 + if (value != null) {
  81 + Map<String,String> dataMap = value as Map<String,String>;
  82 + bloc.add(RequestExitClassEvent(
  83 + dataMap['courseLessonId']!,
  84 + '0',
  85 + dataMap['currentTime']!,
  86 + ));
  87 + }
  88 + });
  89 + return;
  90 + }
  91 +
  92 + if (state is RequestEnterClassState) {
  93 + if (state.courseType != 3 && state.courseType != 4) {///视频类型
  94 + ///获取视频课程内容
  95 + bloc.add(RequestVideoLessonEvent(state.courseLessonId,state.courseType));
  96 + return;
  97 + }
  98 +
  99 + if (state.courseType == 4) {//绘本
  100 + pushNamed(AppRouteName.reading, arguments: {'courseLessonId':state.courseLessonId}).then((value) {
  101 + if (value != null) {
  102 + Map<String,String> dataMap = value as Map<String,String>;
  103 + bloc.add(RequestExitClassEvent(
  104 + dataMap['courseLessonId']!,
  105 + dataMap['currentStep']!,
  106 + '0'
  107 + ));
  108 + }
  109 + });
  110 + return;
  111 + }
  112 +
  113 + if (state.courseType == 3) {//练习
  114 + pushNamed(AppRouteName.topicPic,arguments: {'courseLessonId':state.courseLessonId}).then((value) {
  115 + if (value != null) {
  116 + Map<String,String> dataMap = value as Map<String,String>;
  117 + bloc.add(RequestExitClassEvent(
  118 + dataMap['courseLessonId']!,
  119 + dataMap['currentStep']!,
  120 + '0'
  121 + ));
  122 + }
  123 + });
77 return; 124 return;
78 } 125 }
79 - pushNamed(AppRouteName.lookVideo,arguments: {'videoUrl':videoUrl,'title':title});  
80 } 126 }
81 }, 127 },
82 child: _homeView(), 128 child: _homeView(),
@@ -116,7 +162,8 @@ class _HomePageView extends StatelessWidget { @@ -116,7 +162,8 @@ class _HomePageView extends StatelessWidget {
116 showToast('当前课程暂未解锁'); 162 showToast('当前课程暂未解锁');
117 return; 163 return;
118 } 164 }
119 - bloc.add(RequestVideoLessonEvent(data.id!,data.courseType!)); 165 + ///进入课堂
  166 + bloc.add(RequestEnterClassEvent(data.id!,data.courseType!));
120 }, 167 },
121 child: HomeBoundsItem( 168 child: HomeBoundsItem(
122 imageUrl: data?.coverUrl, 169 imageUrl: data?.coverUrl,
@@ -133,18 +180,8 @@ class _HomePageView extends StatelessWidget { @@ -133,18 +180,8 @@ class _HomePageView extends StatelessWidget {
133 showToast('当前课程暂未解锁'); 180 showToast('当前课程暂未解锁');
134 return; 181 return;
135 } 182 }
136 - if (data.courseType == 4) {//绘本  
137 - Navigator.of(context).pushNamed(AppRouteName.reading, arguments: {'courseLessonId':data.id!});  
138 - return;  
139 - }  
140 -  
141 - if (data.courseType == 3) {//练习  
142 - Navigator.of(context).pushNamed(AppRouteName.topicPic,arguments: {'courseLessonId':data.id!});  
143 - return;  
144 - }  
145 -  
146 - //儿歌/看视频  
147 - bloc.add(RequestVideoLessonEvent(data.id!,data.courseType!)); 183 + ///进入课堂
  184 + bloc.add(RequestEnterClassEvent(data.id!,data.courseType!));
148 }, 185 },
149 child: HomeVideoItem( 186 child: HomeVideoItem(
150 themColor: bloc.modelData?.courseModuleThemeColor, 187 themColor: bloc.modelData?.courseModuleThemeColor,
lib/pages/practice/topic_picture_page.dart
@@ -6,6 +6,7 @@ import &#39;package:wow_english/common/core/user_util.dart&#39;; @@ -6,6 +6,7 @@ import &#39;package:wow_english/common/core/user_util.dart&#39;;
6 import 'package:wow_english/common/extension/string_extension.dart'; 6 import 'package:wow_english/common/extension/string_extension.dart';
7 import 'package:wow_english/common/widgets/ow_image_widget.dart'; 7 import 'package:wow_english/common/widgets/ow_image_widget.dart';
8 import 'package:wow_english/models/course_process_entity.dart'; 8 import 'package:wow_english/models/course_process_entity.dart';
  9 +import 'package:wow_english/route/route.dart';
9 import 'package:wow_english/utils/toast_util.dart'; 10 import 'package:wow_english/utils/toast_util.dart';
10 11
11 import 'bloc/topic_picture_bloc.dart'; 12 import 'bloc/topic_picture_bloc.dart';
@@ -46,7 +47,6 @@ class _TopicPicturePage extends StatelessWidget { @@ -46,7 +47,6 @@ class _TopicPicturePage extends StatelessWidget {
46 if (state is RequestDataState) { 47 if (state is RequestDataState) {
47 context.read<TopicPictureBloc>().add(CurrentPageIndexChangeEvent(0)); 48 context.read<TopicPictureBloc>().add(CurrentPageIndexChangeEvent(0));
48 } 49 }
49 -  
50 if (state is XSVoiceTestState) { 50 if (state is XSVoiceTestState) {
51 51
52 } 52 }
@@ -67,7 +67,12 @@ class _TopicPicturePage extends StatelessWidget { @@ -67,7 +67,12 @@ class _TopicPicturePage extends StatelessWidget {
67 PracticeHeaderWidget( 67 PracticeHeaderWidget(
68 title: '${bloc.currentPage}/${bloc.entity?.topics?.length}', 68 title: '${bloc.currentPage}/${bloc.entity?.topics?.length}',
69 onTap: () { 69 onTap: () {
70 - Navigator.pop(context); 70 + popPage(
  71 + data:{
  72 + 'currentStep':bloc.currentPage.toString(),
  73 + 'courseLessonId':(int.parse(bloc.courseLessonId)+1).toString()
  74 + });
  75 + // Navigator.pop(context);
71 }, 76 },
72 ), 77 ),
73 Expanded( 78 Expanded(
lib/pages/repeataftercontent/bloc/repeat_after_content_bloc.dart
@@ -9,6 +9,8 @@ import &#39;package:flutter_sound/flutter_sound.dart&#39;; @@ -9,6 +9,8 @@ import &#39;package:flutter_sound/flutter_sound.dart&#39;;
9 import 'package:path_provider/path_provider.dart'; 9 import 'package:path_provider/path_provider.dart';
10 import 'package:permission_handler/permission_handler.dart'; 10 import 'package:permission_handler/permission_handler.dart';
11 import 'package:wow_english/common/request/dao/listen_dao.dart'; 11 import 'package:wow_english/common/request/dao/listen_dao.dart';
  12 +import 'package:wow_english/route/route.dart';
  13 +import '../../../common/dialogs/show_dialog.dart';
12 import '../../../common/request/exception.dart'; 14 import '../../../common/request/exception.dart';
13 import '../../../models/read_content_entity.dart'; 15 import '../../../models/read_content_entity.dart';
14 import '../../../utils/loading.dart'; 16 import '../../../utils/loading.dart';
@@ -80,7 +82,7 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo @@ -80,7 +82,7 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo
80 ///录音 82 ///录音
81 late FlutterSoundRecorder _soundRecorder; 83 late FlutterSoundRecorder _soundRecorder;
82 late FlutterSoundPlayer _soundPlayer; 84 late FlutterSoundPlayer _soundPlayer;
83 - StreamSubscription? _soundPlayerListen; 85 + // StreamSubscription? _soundPlayerListen;
84 86
85 RepeatAfterContentBloc(this.courseLessonId) : super(RepeatAfterContentInitial()) { 87 RepeatAfterContentBloc(this.courseLessonId) : super(RepeatAfterContentInitial()) {
86 on<VoiceRecordStateChangeEvent>(_voiceRecordStateChange); 88 on<VoiceRecordStateChangeEvent>(_voiceRecordStateChange);
@@ -123,13 +125,14 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo @@ -123,13 +125,14 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo
123 125
124 //录音 126 //录音
125 _soundRecorder = FlutterSoundRecorder(); 127 _soundRecorder = FlutterSoundRecorder();
126 -  
127 -  
128 - await _soundRecorder.openRecorder();  
129 - // await _soundRecorder.setSubscriptionDuration(const Duration(milliseconds: 10));  
130 -  
131 //音屏 128 //音屏
132 _soundPlayer = FlutterSoundPlayer(); 129 _soundPlayer = FlutterSoundPlayer();
  130 + _init();
  131 + }
  132 +
  133 + void _init() async {
  134 + await _soundRecorder.openRecorder();
  135 + await _soundRecorder.setSubscriptionDuration(const Duration(milliseconds: 10));
133 //设置音频 136 //设置音频
134 final session = await AudioSession.instance; 137 final session = await AudioSession.instance;
135 await session.configure(AudioSessionConfiguration( 138 await session.configure(AudioSessionConfiguration(
@@ -151,7 +154,7 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo @@ -151,7 +154,7 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo
151 )); 154 ));
152 await _soundPlayer.closePlayer(); 155 await _soundPlayer.closePlayer();
153 await _soundPlayer.openPlayer(); 156 await _soundPlayer.openPlayer();
154 - // await _soundPlayer.setSubscriptionDuration(const Duration(milliseconds: 10)); 157 + await _soundPlayer.setSubscriptionDuration(const Duration(milliseconds: 10));
155 } 158 }
156 159
157 ///请求数据 160 ///请求数据
@@ -171,9 +174,7 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo @@ -171,9 +174,7 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo
171 ///跟读结果 174 ///跟读结果
172 void _postFollowReadContent(PostFollowReadContentEvent event,Emitter<RepeatAfterContentState> emitter) async { 175 void _postFollowReadContent(PostFollowReadContentEvent event,Emitter<RepeatAfterContentState> emitter) async {
173 try { 176 try {
174 - await loading(() async {  
175 - _entityList = await ListenDao.followResult(_recordNumber.toString(),courseLessonId);  
176 - }); 177 + await ListenDao.followResult(_recordNumber.toString(),courseLessonId);
177 } catch (e) { 178 } catch (e) {
178 if (e is ApiException) { 179 if (e is ApiException) {
179 180
@@ -203,6 +204,9 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo @@ -203,6 +204,9 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo
203 204
204 ///先声测试 205 ///先声测试
205 void _voiceXsTest(XSVoiceTestEvent event,Emitter<RepeatAfterContentState> emitter) async { 206 void _voiceXsTest(XSVoiceTestEvent event,Emitter<RepeatAfterContentState> emitter) async {
  207 + _recordNumber += 1;
  208 + _xSCheckState = XSVoiceCheckState.start;
  209 + emitter(XSVoiceTestState());
206 await methodChannel.invokeMethod( 210 await methodChannel.invokeMethod(
207 'startLocalVoice', 211 'startLocalVoice',
208 { 212 {
@@ -212,9 +216,6 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo @@ -212,9 +216,6 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo
212 'userId':event.userId.toString() 216 'userId':event.userId.toString()
213 } 217 }
214 ); 218 );
215 - _recordNumber++;  
216 - _xSCheckState = XSVoiceCheckState.start;  
217 - emitter(XSVoiceTestState());  
218 } 219 }
219 220
220 ///终止评测 221 ///终止评测
@@ -246,8 +247,7 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo @@ -246,8 +247,7 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo
246 247
247 await _soundPlayer.startPlayer( 248 await _soundPlayer.startPlayer(
248 fromURI: path, 249 fromURI: path,
249 - codec: Codec.aacADTS,  
250 - sampleRate: 44000, 250 + codec: Codec.pcm16WAV,
251 whenFinished: (){ 251 whenFinished: (){
252 252
253 } 253 }
@@ -292,6 +292,7 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo @@ -292,6 +292,7 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo
292 ); 292 );
293 debugPrint('=====> 开始录音'); 293 debugPrint('=====> 开始录音');
294 _voiceRecordState = VoiceRecordState.voiceRecording; 294 _voiceRecordState = VoiceRecordState.voiceRecording;
  295 + _xSCheckState = XSVoiceCheckState.unKnow;
295 emitter(VoiceRecordStateChange()); 296 emitter(VoiceRecordStateChange());
296 }); 297 });
297 } catch (error) { 298 } catch (error) {
@@ -321,7 +322,7 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo @@ -321,7 +322,7 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo
321 } else if (status.isDenied) { 322 } else if (status.isDenied) {
322 requestPermission(permission); 323 requestPermission(permission);
323 } else if (status.isPermanentlyDenied) { 324 } else if (status.isPermanentlyDenied) {
324 - openAppSettings(); 325 + showDialog();
325 } else if (status.isRestricted) { 326 } else if (status.isRestricted) {
326 requestPermission(permission); 327 requestPermission(permission);
327 } else { 328 } else {
@@ -339,7 +340,16 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo @@ -339,7 +340,16 @@ class RepeatAfterContentBloc extends Bloc&lt;RepeatAfterContentEvent, RepeatAfterCo
339 void requestPermission(Permission permission) async { 340 void requestPermission(Permission permission) async {
340 PermissionStatus status = await permission.request(); 341 PermissionStatus status = await permission.request();
341 if (status.isPermanentlyDenied) { 342 if (status.isPermanentlyDenied) {
342 - openAppSettings(); 343 + showDialog();
343 } 344 }
344 } 345 }
  346 +
  347 + void showDialog() async {
  348 + showTwoActionDialog('提示', '取消', '去设置', '请进入设置页打开麦克风权限', () {
  349 + popPage();
  350 + }, () {
  351 + popPage();
  352 + openAppSettings();
  353 + });
  354 + }
345 } 355 }
lib/pages/repeataftercontent/widgets/repeat_video_widget.dart
@@ -152,17 +152,20 @@ class _RepeatVideoWidgetState extends State&lt;RepeatVideoWidget&gt; { @@ -152,17 +152,20 @@ class _RepeatVideoWidgetState extends State&lt;RepeatVideoWidget&gt; {
152 } 152 }
153 153
154 void _initVideo(String videoUrl) { 154 void _initVideo(String videoUrl) {
155 - _controller = VideoPlayerController.network(widget.videoUrl??'')  
156 - ..initialize().then((_){  
157 - setState(() {  
158 - _currentTime = formatDuration(_controller!.value.position);  
159 - _totalTime = formatDuration(_controller!.value.duration);  
160 - _controller!.setLooping(false);  
161 - _controller!.setVolume(100);  
162 - _controller!.play(); 155 + if(videoUrl.isNotEmpty) {
  156 + Uri uri = Uri.parse(videoUrl);
  157 + _controller = VideoPlayerController.networkUrl(uri)
  158 + ..initialize().then((_){
  159 + setState(() {
  160 + _currentTime = formatDuration(_controller!.value.position);
  161 + _totalTime = formatDuration(_controller!.value.duration);
  162 + _controller!.setLooping(false);
  163 + _controller!.setVolume(100);
  164 + _controller!.play();
  165 + });
  166 + _addListener();
163 }); 167 });
164 - _addListener();  
165 - }); 168 + }
166 } 169 }
167 170
168 void _destroyVideo() { 171 void _destroyVideo() {
lib/pages/user/modify/user_avatar_bloc/user_avatar_bloc.dart
@@ -3,12 +3,12 @@ import &#39;dart:io&#39;; @@ -3,12 +3,12 @@ import &#39;dart:io&#39;;
3 import 'package:device_info_plus/device_info_plus.dart'; 3 import 'package:device_info_plus/device_info_plus.dart';
4 import 'package:flutter/cupertino.dart'; 4 import 'package:flutter/cupertino.dart';
5 import 'package:flutter_bloc/flutter_bloc.dart'; 5 import 'package:flutter_bloc/flutter_bloc.dart';
6 -import 'package:flutter_easyloading/flutter_easyloading.dart';  
7 import 'package:image_picker/image_picker.dart'; 6 import 'package:image_picker/image_picker.dart';
8 import 'package:permission_handler/permission_handler.dart'; 7 import 'package:permission_handler/permission_handler.dart';
9 import 'package:wow_english/common/core/assets_const.dart'; 8 import 'package:wow_english/common/core/assets_const.dart';
10 import 'package:wow_english/common/core/user_util.dart'; 9 import 'package:wow_english/common/core/user_util.dart';
11 -import 'package:wow_english/common/request/dao/user_dao.dart'; 10 +import 'package:wow_english/common/dialogs/show_dialog.dart';
  11 +import 'package:wow_english/route/route.dart';
12 import 'package:wow_english/utils/aliyun_oss_util.dart'; 12 import 'package:wow_english/utils/aliyun_oss_util.dart';
13 import 'package:wow_english/utils/log_util.dart'; 13 import 'package:wow_english/utils/log_util.dart';
14 14
@@ -46,7 +46,18 @@ class UserAvatarBloc extends Bloc&lt;UserAvatarEvent, UserAvatarState&gt; { @@ -46,7 +46,18 @@ class UserAvatarBloc extends Bloc&lt;UserAvatarEvent, UserAvatarState&gt; {
46 } 46 }
47 47
48 void _getImageFromPhoto(GetImageFromPhotoEvent event, Emitter<UserAvatarState> emitter) async { 48 void _getImageFromPhoto(GetImageFromPhotoEvent event, Emitter<UserAvatarState> emitter) async {
49 - await getPhotoPermissionStatus().then((value) async { 49 + Permission permission;
  50 + if (Platform.isAndroid) {
  51 + final androidInfo = await DeviceInfoPlugin().androidInfo;
  52 + if (androidInfo.version.sdkInt <= 32) {
  53 + permission = Permission.storage;
  54 + } else {
  55 + permission = Permission.photos;
  56 + }
  57 + } else {
  58 + permission = Permission.photos;
  59 + }
  60 + await getPermissionStatus(permission).then((value) async {
50 if (!value) { 61 if (!value) {
51 debugPrint('失败$value'); 62 debugPrint('失败$value');
52 return; 63 return;
@@ -62,7 +73,7 @@ class UserAvatarBloc extends Bloc&lt;UserAvatarEvent, UserAvatarState&gt; { @@ -62,7 +73,7 @@ class UserAvatarBloc extends Bloc&lt;UserAvatarEvent, UserAvatarState&gt; {
62 } 73 }
63 74
64 void _getImageFromCamera(GetImageFromCameraEvent event, Emitter<UserAvatarState> emitter) async { 75 void _getImageFromCamera(GetImageFromCameraEvent event, Emitter<UserAvatarState> emitter) async {
65 - await getCameraPermissionStatus().then((value) async { 76 + await getPermissionStatus(Permission.camera).then((value) async {
66 if (!value) { 77 if (!value) {
67 debugPrint('失败$value'); 78 debugPrint('失败$value');
68 return; 79 return;
@@ -83,46 +94,19 @@ class UserAvatarBloc extends Bloc&lt;UserAvatarEvent, UserAvatarState&gt; { @@ -83,46 +94,19 @@ class UserAvatarBloc extends Bloc&lt;UserAvatarEvent, UserAvatarState&gt; {
83 emitter(ChangeUserEnterAppState()); 94 emitter(ChangeUserEnterAppState());
84 } 95 }
85 96
86 - ///获取相机权限  
87 - Future<bool> getCameraPermissionStatus() async {  
88 - Permission permission = Permission.camera;  
89 - //granted 通过,denied 被拒绝,permanentlyDenied 拒绝且不在提示 97 + Future<bool> getPermissionStatus(Permission permission) async {
90 PermissionStatus status = await permission.status; 98 PermissionStatus status = await permission.status;
91 if (status.isGranted) { 99 if (status.isGranted) {
92 return true; 100 return true;
93 } else if (status.isDenied) { 101 } else if (status.isDenied) {
94 _requestPermission(permission); 102 _requestPermission(permission);
95 } else if (status.isPermanentlyDenied) { 103 } else if (status.isPermanentlyDenied) {
96 - openAppSettings(); 104 + showDialog(permission);
97 } else if (status.isRestricted) { 105 } else if (status.isRestricted) {
98 _requestPermission(permission); 106 _requestPermission(permission);
99 - } else {}  
100 - return false;  
101 - }  
102 -  
103 - ///获取相册权限  
104 - Future<bool> getPhotoPermissionStatus() async {  
105 - Permission permission;  
106 - if (Platform.isAndroid) {  
107 - final androidInfo = await DeviceInfoPlugin().androidInfo;  
108 - if (androidInfo.version.sdkInt <= 32) {  
109 - permission = Permission.storage;  
110 - } else {  
111 - permission = Permission.photos;  
112 - }  
113 } else { 107 } else {
114 - permission = Permission.photos; 108 +
115 } 109 }
116 - PermissionStatus status = await permission.status;  
117 - if (status.isGranted) {  
118 - return true;  
119 - } else if (status.isDenied) {  
120 - _requestPermission(permission);  
121 - } else if (status.isPermanentlyDenied) {  
122 - openAppSettings();  
123 - } else if (status.isRestricted) {  
124 - _requestPermission(permission);  
125 - } else {}  
126 return false; 110 return false;
127 } 111 }
128 112
@@ -130,7 +114,17 @@ class UserAvatarBloc extends Bloc&lt;UserAvatarEvent, UserAvatarState&gt; { @@ -130,7 +114,17 @@ class UserAvatarBloc extends Bloc&lt;UserAvatarEvent, UserAvatarState&gt; {
130 void _requestPermission(Permission permission) async { 114 void _requestPermission(Permission permission) async {
131 PermissionStatus status = await permission.request(); 115 PermissionStatus status = await permission.request();
132 if (status.isPermanentlyDenied) { 116 if (status.isPermanentlyDenied) {
133 - openAppSettings(); 117 + showDialog(permission);
134 } 118 }
135 } 119 }
  120 +
  121 + void showDialog(Permission permission) {
  122 + final contentStr = permission == Permission.camera ? '相机权限未开启,请到设置中打开' : '相册权限未开启,请到设置中打开';
  123 + showTwoActionDialog('提示', '取消', '去设置', contentStr, () {
  124 + popPage();
  125 + }, () {
  126 + popPage();
  127 + openAppSettings();
  128 + });
  129 + }
136 } 130 }
lib/pages/video/lookvideo/look_video_page.dart
@@ -2,10 +2,11 @@ import &#39;package:flutter/material.dart&#39;; @@ -2,10 +2,11 @@ import &#39;package:flutter/material.dart&#39;;
2 import 'package:wow_english/pages/video/lookvideo/widgets/video_widget.dart'; 2 import 'package:wow_english/pages/video/lookvideo/widgets/video_widget.dart';
3 3
4 class LookVideoPage extends StatefulWidget { 4 class LookVideoPage extends StatefulWidget {
5 - const LookVideoPage({super.key, this.videoUrl, this.typeTitle}); 5 + const LookVideoPage({super.key, this.videoUrl, this.typeTitle, this.courseLessonId});
6 6
7 final String? videoUrl; 7 final String? videoUrl;
8 final String? typeTitle; 8 final String? typeTitle;
  9 + final String? courseLessonId;
9 10
10 @override 11 @override
11 State<StatefulWidget> createState() { 12 State<StatefulWidget> createState() {
@@ -21,6 +22,7 @@ class _LookVideoPageState extends State&lt;LookVideoPage&gt; { @@ -21,6 +22,7 @@ class _LookVideoPageState extends State&lt;LookVideoPage&gt; {
21 child: VideoWidget( 22 child: VideoWidget(
22 videoUrl: widget.videoUrl??'', 23 videoUrl: widget.videoUrl??'',
23 typeTitle: widget.typeTitle, 24 typeTitle: widget.typeTitle,
  25 + courseLessonId: widget.courseLessonId??'',
24 ), 26 ),
25 ); 27 );
26 } 28 }
lib/pages/video/lookvideo/widgets/video_widget.dart
@@ -3,14 +3,16 @@ import &#39;package:flutter/material.dart&#39;; @@ -3,14 +3,16 @@ import &#39;package:flutter/material.dart&#39;;
3 import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 import 'package:flutter_screenutil/flutter_screenutil.dart';
4 import 'package:video_player/video_player.dart'; 4 import 'package:video_player/video_player.dart';
5 import 'package:wow_english/common/extension/string_extension.dart'; 5 import 'package:wow_english/common/extension/string_extension.dart';
  6 +import 'package:wow_english/route/route.dart';
6 7
7 import 'video_opera_widget.dart'; 8 import 'video_opera_widget.dart';
8 9
9 class VideoWidget extends StatefulWidget { 10 class VideoWidget extends StatefulWidget {
10 - const VideoWidget({super.key, this.videoUrl = '',this.typeTitle}); 11 + const VideoWidget({super.key, this.videoUrl = '',this.typeTitle, this.courseLessonId = ''});
11 12
12 final String videoUrl; 13 final String videoUrl;
13 final String? typeTitle; 14 final String? typeTitle;
  15 + final String courseLessonId;
14 16
15 @override 17 @override
16 State<StatefulWidget> createState() { 18 State<StatefulWidget> createState() {
@@ -74,7 +76,16 @@ class _VideoWidgetState extends State&lt;VideoWidget&gt; { @@ -74,7 +76,16 @@ class _VideoWidgetState extends State&lt;VideoWidget&gt; {
74 76
75 void actionType(OperationType type) async { 77 void actionType(OperationType type) async {
76 if (type == OperationType.back) { 78 if (type == OperationType.back) {
77 - Navigator.pop(context); 79 + if (widget.courseLessonId.isEmpty) {
  80 + popPage();
  81 + } else {
  82 + if (_controller == null) {
  83 + popPage();
  84 + return;
  85 + }
  86 + String currentTime = (_controller!.value.position.inMinutes.remainder(60)*60+_controller!.value.position.inSeconds.remainder(60)).toString();
  87 + popPage(data:{'courseLessonId':widget.courseLessonId,'currentTime':currentTime});
  88 + }
78 } else if (type == OperationType.playState) { 89 } else if (type == OperationType.playState) {
79 if (_controller!.value.isPlaying) { 90 if (_controller!.value.isPlaying) {
80 _controller!.pause(); 91 _controller!.pause();
@@ -90,7 +101,8 @@ class _VideoWidgetState extends State&lt;VideoWidget&gt; { @@ -90,7 +101,8 @@ class _VideoWidgetState extends State&lt;VideoWidget&gt; {
90 @override 101 @override
91 void initState() { 102 void initState() {
92 super.initState(); 103 super.initState();
93 - _controller = VideoPlayerController.network(widget.videoUrl) 104 + Uri uri = Uri.parse(widget.videoUrl);
  105 + _controller = VideoPlayerController.networkUrl(uri)
94 ..initialize().then((_){ 106 ..initialize().then((_){
95 startTimer(); 107 startTimer();
96 setState(() { 108 setState(() {
lib/route/route.dart
@@ -107,7 +107,7 @@ class AppRouter { @@ -107,7 +107,7 @@ class AppRouter {
107 case AppRouteName.userAvatar: 107 case AppRouteName.userAvatar:
108 var pageType = 0; 108 var pageType = 0;
109 if (settings.arguments != null) { 109 if (settings.arguments != null) {
110 - final content = (settings.arguments as Map)['pageType'] as String ?? '0'; 110 + final content = (settings.arguments as Map)['pageType'] as String;
111 pageType = int.parse(content); 111 pageType = int.parse(content);
112 } 112 }
113 return CupertinoPageRoute( 113 return CupertinoPageRoute(
@@ -125,17 +125,19 @@ class AppRouter { @@ -125,17 +125,19 @@ class AppRouter {
125 case AppRouteName.topicPic: 125 case AppRouteName.topicPic:
126 var courseLessonId = ''; 126 var courseLessonId = '';
127 if (settings.arguments != null) { 127 if (settings.arguments != null) {
128 - courseLessonId = (settings.arguments as Map)['courseLessonId'] as String ?? ''; 128 + courseLessonId = (settings.arguments as Map)['courseLessonId'] as String;
129 } 129 }
130 return CupertinoPageRoute(builder: (_) => TopicPicturePage(courseLessonId: courseLessonId)); 130 return CupertinoPageRoute(builder: (_) => TopicPicturePage(courseLessonId: courseLessonId));
131 case AppRouteName.lookVideo: 131 case AppRouteName.lookVideo:
132 final videoUrl = (settings.arguments as Map)['videoUrl'] as String; 132 final videoUrl = (settings.arguments as Map)['videoUrl'] as String;
133 final title = (settings.arguments as Map)['title'] as String?; 133 final title = (settings.arguments as Map)['title'] as String?;
  134 + final courseLessonId = (settings.arguments as Map)['courseLessonId'] as String?;
134 return CupertinoPageRoute( 135 return CupertinoPageRoute(
135 builder: (_) => LookVideoPage( 136 builder: (_) => LookVideoPage(
136 - videoUrl: videoUrl,  
137 - typeTitle: title,  
138 - )); 137 + videoUrl: videoUrl,
  138 + typeTitle: title,
  139 + courseLessonId: courseLessonId,
  140 + ));
139 /*case AppRouteName.setPwd: 141 /*case AppRouteName.setPwd:
140 case AppRouteName.setPwd: 142 case AppRouteName.setPwd:
141 phoneNum: phoneNum, 143 phoneNum: phoneNum,
@@ -153,7 +155,7 @@ class AppRouter { @@ -153,7 +155,7 @@ class AppRouter {
153 case AppRouteName.readAfterContent: 155 case AppRouteName.readAfterContent:
154 var videoFollowReadId = ''; 156 var videoFollowReadId = '';
155 if (settings.arguments != null) { 157 if (settings.arguments != null) {
156 - videoFollowReadId = (settings.arguments as Map)['videoFollowReadId'] as String ?? ''; 158 + videoFollowReadId = (settings.arguments as Map)['videoFollowReadId'] as String;
157 } 159 }
158 return CupertinoPageRoute(builder: (_) => RepeatAfterContentPage(videoFollowReadId: videoFollowReadId)); 160 return CupertinoPageRoute(builder: (_) => RepeatAfterContentPage(videoFollowReadId: videoFollowReadId));
159 case AppRouteName.tab: 161 case AppRouteName.tab:
@@ -166,7 +168,7 @@ class AppRouter { @@ -166,7 +168,7 @@ class AppRouter {
166 case AppRouteName.reading: 168 case AppRouteName.reading:
167 var courseLessonId = ''; 169 var courseLessonId = '';
168 if (settings.arguments != null) { 170 if (settings.arguments != null) {
169 - courseLessonId = (settings.arguments as Map)['courseLessonId'] as String ?? ''; 171 + courseLessonId = (settings.arguments as Map)['courseLessonId'] as String;
170 } 172 }
171 return CupertinoPageRoute(builder: (_) => ReadingPage(courseLessonId: courseLessonId)); 173 return CupertinoPageRoute(builder: (_) => ReadingPage(courseLessonId: courseLessonId));
172 default: 174 default:
@@ -176,14 +178,16 @@ class AppRouter { @@ -176,14 +178,16 @@ class AppRouter {
176 } 178 }
177 } 179 }
178 180
179 -void pushNamed(String routeName, {Object? arguments}) {  
180 - Navigator.of(AppRouter.context).pushNamed(routeName, arguments: arguments); 181 +Future pushNamed(String routeName, {Object? arguments}) {
  182 + return Navigator.of(AppRouter.context).pushNamed(routeName, arguments: arguments).then((value) {
  183 + return value;
  184 + });
181 } 185 }
182 186
183 -void pushNamedAndRemoveUntil(String routeName, RoutePredicate predicate, {Object? arguments}) {  
184 - Navigator.of(AppRouter.context).pushNamedAndRemoveUntil(routeName, predicate, arguments: arguments); 187 +Future pushNamedAndRemoveUntil(String routeName, RoutePredicate predicate, {Object? arguments}) {
  188 + return Navigator.of(AppRouter.context).pushNamedAndRemoveUntil(routeName, predicate, arguments: arguments);
185 } 189 }
186 190
187 -void popPage() {  
188 - Navigator.pop(AppRouter.context); 191 +void popPage({dynamic data}) {
  192 + Navigator.of(AppRouter.context).pop(data);
189 } 193 }
pubspec.yaml
@@ -101,6 +101,8 @@ dependencies: @@ -101,6 +101,8 @@ dependencies:
101 path_provider: ^2.0.15 101 path_provider: ^2.0.15
102 # 阿里云oss https://pub.dev/packages/flutter_oss_aliyun 102 # 阿里云oss https://pub.dev/packages/flutter_oss_aliyun
103 flutter_oss_aliyun: ^6.2.7 103 flutter_oss_aliyun: ^6.2.7
  104 + # App信息 https://pub.dev/packages/package_info_plus
  105 + package_info_plus: ^4.0.2
104 106
105 dev_dependencies: 107 dev_dependencies:
106 build_runner: ^2.4.4 108 build_runner: ^2.4.4