Commit 95e3448ceddfa0198073048461d7467e875572a3

Authored by liangchengyou
1 parent 7912b3f7

feat:听音选图/选字

assets/images/road_bg.png 0 → 100644

353 KB

assets/images/voice.png 0 → 100644

8.3 KB

lib/home/home_page.dart
... ... @@ -35,7 +35,9 @@ class _HomePageView extends StatelessWidget {
35 35 } else {
36 36 // Navigator.of(AppRouter.context).pushNamed(AppRouteName.topicPic);
37 37 // Navigator.of(AppRouter.context).pushNamed(AppRouteName.topicWord);
38   - Navigator.of(AppRouter.context).pushNamed(AppRouteName.lookVideo);
  38 + // Navigator.of(AppRouter.context).pushNamed(AppRouteName.lookVideo);
  39 + // Navigator.of(AppRouter.context).pushNamed(AppRouteName.voicePic);
  40 + Navigator.of(AppRouter.context).pushNamed(AppRouteName.voiceWord);
39 41 }
40 42 }
41 43  
... ...
lib/practice/voicetopic/voicepicture/bloc/voice_pic_bloc.dart 0 → 100644
  1 +import 'package:flutter/cupertino.dart';
  2 +import 'package:flutter_bloc/flutter_bloc.dart';
  3 +
  4 +part 'voice_pic_event.dart';
  5 +part 'voice_pic_state.dart';
  6 +
  7 +class VoicePicBloc extends Bloc<VoicePicEvent, VoicePicState> {
  8 + final PageController pageController;
  9 +
  10 + final int modelCount;
  11 +
  12 + int _currentPage = 0;
  13 +
  14 + int _selectItem = 0;
  15 +
  16 + int get currentPage => _currentPage + 1;
  17 +
  18 + int get selectItem => _selectItem;
  19 + VoicePicBloc(this.pageController, this.modelCount) : super(VoicePicInitial()) {
  20 + on<CurrentPageIndexChangeEvent>(_pageControllerChange);
  21 + on<SelectItemEvent>(_selectItemLoad);
  22 + }
  23 +
  24 + @override
  25 + Future<void> close() {
  26 + pageController.dispose();
  27 + return super.close();
  28 + }
  29 +
  30 + void _pageControllerChange(CurrentPageIndexChangeEvent event,Emitter<VoicePicState> emitter) async {
  31 + _currentPage = event.pageIndex;
  32 + emitter(CurrentPageIndexState());
  33 + }
  34 +
  35 + void _selectItemLoad(SelectItemEvent event,Emitter<VoicePicState> emitter) async {
  36 + _selectItem = event.selectIndex;
  37 + emitter(SelectItemChangeState());
  38 + }
  39 +}
... ...
lib/practice/voicetopic/voicepicture/bloc/voice_pic_event.dart 0 → 100644
  1 +part of 'voice_pic_bloc.dart';
  2 +
  3 +@immutable
  4 +abstract class VoicePicEvent {}
  5 +
  6 +class CurrentPageIndexChangeEvent extends VoicePicEvent {
  7 + final int pageIndex;
  8 + CurrentPageIndexChangeEvent(this.pageIndex);
  9 +}
  10 +
  11 +class SelectItemEvent extends VoicePicEvent {
  12 + final int selectIndex;
  13 + SelectItemEvent(this.selectIndex);
  14 +}
0 15 \ No newline at end of file
... ...
lib/practice/voicetopic/voicepicture/bloc/voice_pic_state.dart 0 → 100644
  1 +part of 'voice_pic_bloc.dart';
  2 +
  3 +@immutable
  4 +abstract class VoicePicState {}
  5 +
  6 +class VoicePicInitial extends VoicePicState {}
  7 +
  8 +class CurrentPageIndexState extends VoicePicState {}
  9 +
  10 +class SelectItemChangeState extends VoicePicState {}
0 11 \ No newline at end of file
... ...
lib/practice/voicetopic/voicepicture/voice_pic_page.dart 0 → 100644
  1 +import 'package:flutter/material.dart';
  2 +import 'package:flutter_bloc/flutter_bloc.dart';
  3 +import 'package:flutter_screenutil/flutter_screenutil.dart';
  4 +import 'package:wow_english/common/extension/string_extension.dart';
  5 +import 'package:wow_english/practice/voicetopic/voicepicture/bloc/voice_pic_bloc.dart';
  6 +import 'package:wow_english/practice/widgets/practice_header_widget.dart';
  7 +
  8 +class VoicePicPage extends StatelessWidget {
  9 + const VoicePicPage({super.key});
  10 +
  11 + @override
  12 + Widget build(BuildContext context) {
  13 + return BlocProvider(
  14 + create: (context) => VoicePicBloc(PageController(),4),
  15 + child: _VoicePicPage(),
  16 + );
  17 + }
  18 +}
  19 +
  20 +class _VoicePicPage extends StatelessWidget {
  21 + @override
  22 + Widget build(BuildContext context) {
  23 + return BlocListener<VoicePicBloc, VoicePicState>(
  24 + listener: (context, state){},
  25 + child: _voicePicView(),
  26 + );
  27 + }
  28 +
  29 + Widget _voicePicView() => BlocBuilder<VoicePicBloc, VoicePicState>(
  30 + builder: (context, state){
  31 + return _voicePictureView();
  32 + });
  33 +
  34 + Widget _voicePictureView() => BlocBuilder<VoicePicBloc, VoicePicState>(
  35 + buildWhen: (_,s) => s is CurrentPageIndexState,
  36 + builder: (context,state){
  37 + final bloc = BlocProvider.of<VoicePicBloc>(context);
  38 + return Container(
  39 + color: Colors.white,
  40 + child: Stack(
  41 + children: [
  42 + Image.asset(
  43 + 'road_bg'.assetPng,
  44 + height: double.infinity,
  45 + width: double.infinity
  46 + ),
  47 + Column(
  48 + children: [
  49 + PracticeHeaderWidget(
  50 + title: '${bloc.currentPage}/8',
  51 + onTap: (){Navigator.pop(context);},
  52 + ),
  53 + Row(
  54 + mainAxisAlignment: MainAxisAlignment.center,
  55 + children: [
  56 + Image.asset('voice'.assetPng,height: 33.h,width: 30.w,),
  57 + 10.horizontalSpace,
  58 + Text(
  59 + 'yellow',
  60 + style: TextStyle(
  61 + fontSize: 20.sp,
  62 + color: const Color(0xFF333333)
  63 + )
  64 + )
  65 + ],
  66 + ),
  67 + 26.verticalSpace,
  68 + Expanded(
  69 + child: PageView.builder(
  70 + itemCount: 8,
  71 + scrollDirection: Axis.horizontal,
  72 + controller: bloc.pageController,
  73 + onPageChanged: (int index) {
  74 + bloc.add(CurrentPageIndexChangeEvent(index));
  75 + },
  76 + itemBuilder: (BuildContext context,int index){
  77 + return _pageViewItemWidget();
  78 + }),
  79 + )
  80 + ],
  81 + )
  82 + ],
  83 + ),
  84 + );
  85 + });
  86 +
  87 + Widget _pageViewItemWidget() => BlocBuilder<VoicePicBloc, VoicePicState>(
  88 + builder: (context, state){
  89 + final bloc = BlocProvider.of<VoicePicBloc>(context);
  90 + return SafeArea(
  91 + child: Column(
  92 + children: [
  93 + Row(
  94 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
  95 + children: [
  96 + Offstage(
  97 + offstage: (bloc.modelCount < 1),
  98 + child: _decodeImageWidget(1),
  99 + ),
  100 + Offstage(
  101 + offstage: (bloc.modelCount < 2),
  102 + child: _decodeImageWidget(2),
  103 + ),
  104 + Offstage(
  105 + offstage: (bloc.modelCount < 3),
  106 + child: _decodeImageWidget(3),
  107 + ),
  108 + Offstage(
  109 + offstage: (bloc.modelCount < 4),
  110 + child: _decodeImageWidget(4),
  111 + )
  112 + ],
  113 + )
  114 + ],
  115 + ),
  116 + );
  117 + });
  118 +
  119 + Widget _decodeImageWidget(int index) => BlocBuilder<VoicePicBloc, VoicePicState>(
  120 + buildWhen: (_, s) => s is SelectItemChangeState,
  121 + builder: (context,state){
  122 + final bloc = BlocProvider.of<VoicePicBloc>(context);
  123 + return GestureDetector(
  124 + onTap: () => bloc.add(SelectItemEvent(index)),
  125 + child: Container(
  126 + padding: const EdgeInsets.all(4.5),
  127 + decoration: BoxDecoration(
  128 + color: bloc.selectItem == index?const Color(0xFF00B6F1):Colors.white,
  129 + borderRadius: BorderRadius.circular(15),
  130 + ),
  131 + height: 143.h,
  132 + width: 143.w,
  133 + child: Container(
  134 + decoration: BoxDecoration(
  135 + color: Colors.white,
  136 + borderRadius: BorderRadius.circular(15),
  137 + border: Border.all(
  138 + width: 1.0,
  139 + color: const Color(0xFF140C10)
  140 + ),
  141 + image: const DecorationImage(
  142 + fit: BoxFit.fitWidth,
  143 + image: NetworkImage('https://img1.baidu.com/it/u=3392591833,1640391553&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=714')
  144 + )
  145 + ),
  146 + ),
  147 + ),
  148 + );
  149 + });
  150 +}
0 151 \ No newline at end of file
... ...
lib/practice/voicetopic/voiceword/bloc/voice_word_bloc.dart 0 → 100644
  1 +
  2 +import 'package:flutter/cupertino.dart';
  3 +import 'package:flutter_bloc/flutter_bloc.dart';
  4 +
  5 +part 'voice_word_event.dart';
  6 +part 'voice_word_state.dart';
  7 +
  8 +class VoiceWordBloc extends Bloc<VoiceWordEvent, VoiceWordState> {
  9 + final PageController pageController;
  10 +
  11 + final int modelCount;
  12 +
  13 + int _currentPage = 0;
  14 +
  15 + int _selectItem = 0;
  16 +
  17 + int get currentPage => _currentPage + 1;
  18 +
  19 + int get selectItem => _selectItem;
  20 + VoiceWordBloc(this.pageController, this.modelCount) : super(VoiceWordInitial()) {
  21 + on<CurrentPageIndexChangeEvent>(_pageControllerChange);
  22 + on<SelectItemEvent>(_selectItemLoad);
  23 + }
  24 +
  25 + @override
  26 + Future<void> close() {
  27 + pageController.dispose();
  28 + return super.close();
  29 + }
  30 +
  31 + void _pageControllerChange(CurrentPageIndexChangeEvent event,Emitter<VoiceWordState> emitter) async {
  32 + _currentPage = event.pageIndex;
  33 + emitter(CurrentPageIndexState());
  34 + }
  35 +
  36 + void _selectItemLoad(SelectItemEvent event,Emitter<VoiceWordState> emitter) async {
  37 + _selectItem = event.selectIndex;
  38 + emitter(SelectItemChangeState());
  39 + }
  40 +}
  41 +
... ...
lib/practice/voicetopic/voiceword/bloc/voice_word_event.dart 0 → 100644
  1 +part of 'voice_word_bloc.dart';
  2 +
  3 +@immutable
  4 +abstract class VoiceWordEvent {}
  5 +
  6 +class CurrentPageIndexChangeEvent extends VoiceWordEvent {
  7 + final int pageIndex;
  8 + CurrentPageIndexChangeEvent(this.pageIndex);
  9 +}
  10 +
  11 +class SelectItemEvent extends VoiceWordEvent {
  12 + final int selectIndex;
  13 + SelectItemEvent(this.selectIndex);
  14 +}
0 15 \ No newline at end of file
... ...
lib/practice/voicetopic/voiceword/bloc/voice_word_state.dart 0 → 100644
  1 +part of 'voice_word_bloc.dart';
  2 +
  3 +@immutable
  4 +abstract class VoiceWordState {}
  5 +
  6 +class VoiceWordInitial extends VoiceWordState {}
  7 +
  8 +class CurrentPageIndexState extends VoiceWordState {}
  9 +
  10 +class SelectItemChangeState extends VoiceWordState {}
... ...
lib/practice/voicetopic/voiceword/voice_word_page.dart 0 → 100644
  1 +import 'package:flutter/material.dart';
  2 +import 'package:flutter_bloc/flutter_bloc.dart';
  3 +import 'package:flutter_screenutil/flutter_screenutil.dart';
  4 +import 'package:wow_english/common/extension/string_extension.dart';
  5 +import 'package:wow_english/practice/voicetopic/voiceword/bloc/voice_word_bloc.dart';
  6 +import 'package:wow_english/practice/widgets/practice_header_widget.dart';
  7 +
  8 +class VoiceWordPage extends StatelessWidget {
  9 + const VoiceWordPage({super.key});
  10 +
  11 +
  12 + @override
  13 + Widget build(BuildContext context) {
  14 + return BlocProvider(
  15 + create: (context) => VoiceWordBloc(PageController(),4),
  16 + child: _VoiceWordPage(),
  17 + );
  18 + }
  19 +}
  20 +
  21 +class _VoiceWordPage extends StatelessWidget {
  22 + @override
  23 + Widget build(BuildContext context) {
  24 + return BlocListener<VoiceWordBloc, VoiceWordState>(
  25 + listener: (context, state){},
  26 + child: _voiceWorView(),
  27 + );
  28 + }
  29 +
  30 + Widget _voiceWorView() => BlocBuilder<VoiceWordBloc, VoiceWordState>(
  31 + builder: (context, state){
  32 + return _voiceWordView();
  33 + });
  34 +
  35 + Widget _voiceWordView() => BlocBuilder<VoiceWordBloc, VoiceWordState>(
  36 + buildWhen: (_,s) => s is CurrentPageIndexState,
  37 + builder: (context,state){
  38 + final bloc = BlocProvider.of<VoiceWordBloc>(context);
  39 + return Container(
  40 + color: Colors.white,
  41 + child: Stack(
  42 + children: [
  43 + Image.asset(
  44 + 'road_bg'.assetPng,
  45 + height: double.infinity,
  46 + width: double.infinity
  47 + ),
  48 + Column(
  49 + children: [
  50 + PracticeHeaderWidget(
  51 + title: '${bloc.currentPage}/8',
  52 + onTap: (){Navigator.pop(context);},
  53 + ),
  54 + Image.asset('voice'.assetPng,height: 33.h,width: 30.w,),
  55 + 26.verticalSpace,
  56 + Expanded(
  57 + child: PageView.builder(
  58 + itemCount: 8,
  59 + scrollDirection: Axis.horizontal,
  60 + controller: bloc.pageController,
  61 + onPageChanged: (int index) {
  62 + bloc.add(CurrentPageIndexChangeEvent(index));
  63 + },
  64 + itemBuilder: (BuildContext context,int index){
  65 + return _pageViewItemWidget();
  66 + }),
  67 + )
  68 + ],
  69 + )
  70 + ],
  71 + ),
  72 + );
  73 + });
  74 +
  75 + Widget _pageViewItemWidget() => BlocBuilder<VoiceWordBloc, VoiceWordState>(
  76 + builder: (context, state){
  77 + final bloc = BlocProvider.of<VoiceWordBloc>(context);
  78 + return SafeArea(
  79 + child: Column(
  80 + children: [
  81 + Row(
  82 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
  83 + children: [
  84 + Offstage(
  85 + offstage: (bloc.modelCount < 1),
  86 + child: _decodeImageWidget(1),
  87 + ),
  88 + Offstage(
  89 + offstage: (bloc.modelCount < 2),
  90 + child: _decodeImageWidget(2),
  91 + ),
  92 + Offstage(
  93 + offstage: (bloc.modelCount < 3),
  94 + child: _decodeImageWidget(3),
  95 + ),
  96 + Offstage(
  97 + offstage: (bloc.modelCount < 4),
  98 + child: _decodeImageWidget(4),
  99 + )
  100 + ],
  101 + )
  102 + ],
  103 + ),
  104 + );
  105 + });
  106 +
  107 + Widget _decodeImageWidget(int index) => BlocBuilder<VoiceWordBloc,VoiceWordState>(
  108 + buildWhen: (_, s) => s is SelectItemChangeState,
  109 + builder: (context,state){
  110 + final bloc = BlocProvider.of<VoiceWordBloc>(context);
  111 + return GestureDetector(
  112 + onTap: () => bloc.add(SelectItemEvent(index)),
  113 + child: Container(
  114 + width: 143.w,
  115 + height: 143.h,
  116 + padding: EdgeInsets.only(left: 13.w,right: 13.w,top: 13.h,bottom: 13.h),
  117 + decoration: BoxDecoration(
  118 + color: Colors.white,
  119 + borderRadius: BorderRadius.circular(15),
  120 + border: Border.all(
  121 + width: 1.0,
  122 + color: const Color(0xFF140C10)
  123 + ),
  124 + ),
  125 + child: Column(
  126 + mainAxisAlignment: MainAxisAlignment.end,
  127 + children: [
  128 + Expanded(
  129 + child: Container(
  130 + alignment: Alignment.center,
  131 + child: Text(
  132 + 'yellow',
  133 + style: TextStyle(
  134 + fontSize: 20.sp,
  135 + color: const Color(0xFF333333)
  136 + )
  137 + ),
  138 + ),
  139 + ),
  140 + Container(
  141 + height: 30.h,
  142 + width: double.infinity,
  143 + decoration: BoxDecoration(
  144 + color: bloc.selectItem == index?const Color(0xFF00B6F1):Colors.white,
  145 + borderRadius: BorderRadius.circular(15.r),
  146 + border: Border.all(
  147 + width: 1.5,
  148 + color: const Color(0xFF140C10)
  149 + ),
  150 + ),
  151 + alignment: Alignment.center,
  152 + child: Image.asset('choose'.assetPng),
  153 + )
  154 + ],
  155 + ),
  156 + ),
  157 + );
  158 + });
  159 +}
0 160 \ No newline at end of file
... ...
lib/route/route.dart
... ... @@ -10,6 +10,8 @@ import &#39;package:wow_english/login/loginpage/login_page.dart&#39;;
10 10 import 'package:wow_english/login/setpwd/set_pwd_page.dart';
11 11 import 'package:wow_english/practice/chosetopic/topicpicture/topic_picture_page.dart';
12 12 import 'package:wow_english/practice/chosetopic/topicword/topic_word_page.dart';
  13 +import 'package:wow_english/practice/voicetopic/voicepicture/voice_pic_page.dart';
  14 +import 'package:wow_english/practice/voicetopic/voiceword/voice_word_page.dart';
13 15 import 'package:wow_english/repeatafter/repeat_after_page.dart';
14 16 import 'package:wow_english/shop/exchane/exchange_lesson_page.dart';
15 17 import 'package:wow_english/shop/exchangelist/exchange_lesson_list_page.dart';
... ... @@ -34,6 +36,8 @@ class AppRouteName {
34 36 static const String reAfter = 'reAfter';
35 37 static const String topicPic = 'topicPic';
36 38 static const String topicWord = 'topicWord';
  39 + static const String voicePic = 'voicePic';
  40 + static const String voiceWord = 'voiceWord';
37 41 static const String user = 'user';
38 42 static const String lookVideo = 'lookVideo';
39 43 static const String tab = '/';
... ... @@ -76,6 +80,10 @@ class AppRouter {
76 80 return CupertinoPageRoute(builder: (_) => const TopicPicturePage());
77 81 case AppRouteName.topicWord:
78 82 return CupertinoPageRoute(builder: (_) => const TopicWordPage());
  83 + case AppRouteName.voicePic:
  84 + return CupertinoPageRoute(builder: (_) => const VoicePicPage());
  85 + case AppRouteName.voiceWord:
  86 + return CupertinoPageRoute(builder: (_) => const VoiceWordPage());
79 87 case AppRouteName.lookVideo:
80 88 return CupertinoPageRoute(builder: (_) => const LookVideoPage());
81 89 case AppRouteName.setPwd:
... ...
lib/video/lookvideo/widgets/video_opera_widget.dart
... ... @@ -19,6 +19,7 @@ class VideoOperaWidget extends StatefulWidget {
19 19 this.totalTime = '00:00',
20 20 this.degree = 0.0,
21 21 this.actionEvent,
  22 + this.sliderChangeEvent,
22 23 this.isPlay = true
23 24 });
24 25 //当前播放时间
... ... @@ -28,6 +29,7 @@ class VideoOperaWidget extends StatefulWidget {
28 29 final double degree;
29 30 final bool isPlay;
30 31 final Function(OperationType type)? actionEvent;
  32 + final Function(double degree)? sliderChangeEvent;
31 33  
32 34 @override
33 35 State<StatefulWidget> createState() {
... ... @@ -154,6 +156,7 @@ class _VideoOperaWidgetState extends State&lt;VideoOperaWidget&gt; {
154 156 setState(() {
155 157 isSlider = false;
156 158 });
  159 + widget.sliderChangeEvent?.call(value);
157 160 },
158 161 onChanged: (value) {
159 162 setState(() {
... ...
lib/video/lookvideo/widgets/video_widget.dart
... ... @@ -154,6 +154,11 @@ class _VideoWidgetState extends State&lt;VideoWidget&gt; {
154 154 actionEvent: (OperationType type) {
155 155 actionType(type);
156 156 },
  157 + sliderChangeEvent: (double degree) {
  158 + int totalSecond = _controller!.value.duration.inMinutes.remainder(60)*60+_controller!.value.duration.inSeconds.remainder(60);
  159 + int positionSecond = (totalSecond * degree).toInt();
  160 + _controller!.seekTo(Duration(seconds: positionSecond));
  161 + },
157 162 ),
158 163 ),
159 164 Offstage(
... ... @@ -171,7 +176,7 @@ class _VideoWidgetState extends State&lt;VideoWidget&gt; {
171 176 )
172 177 ],
173 178 ): Container(
174   - color: Colors.black,
  179 + color: Colors.white,
175 180 ),
176 181 ),
177 182 );
... ...