From 2a427e12162f9bc5c394a9feb826a5f4379cd83e Mon Sep 17 00:00:00 2001 From: wuqifeng <540416539@qq.com> Date: Tue, 27 Jun 2023 09:04:35 +0800 Subject: [PATCH] feat:绘本静态ui基本完成 --- assets/images/bg_reading_mode.png | Bin 0 -> 16417 bytes assets/images/record_pause.webp | Bin 0 -> 8040 bytes assets/images/record_play.webp | Bin 0 -> 8282 bytes lib/common/extension/string_extension.dart | 2 ++ lib/pages/reading/bloc/reading_bloc.dart | 44 ++++++++++++++++++++++++++++++++++++++++---- lib/pages/reading/bloc/reading_event.dart | 7 +++++++ lib/pages/reading/bloc/reading_state.dart | 5 +++++ lib/pages/reading/reading_page.dart | 195 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------ lib/pages/reading/widgets/ReadingModeType.dart | 6 ++++++ lib/pages/reading/widgets/reading_header_widget.dart | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/route/route.dart | 5 +++++ 11 files changed, 261 insertions(+), 58 deletions(-) create mode 100644 assets/images/bg_reading_mode.png create mode 100644 assets/images/record_pause.webp create mode 100644 assets/images/record_play.webp create mode 100644 lib/pages/reading/widgets/ReadingModeType.dart create mode 100644 lib/pages/reading/widgets/reading_header_widget.dart diff --git a/assets/images/bg_reading_mode.png b/assets/images/bg_reading_mode.png new file mode 100644 index 0000000..5e21af8 Binary files /dev/null and b/assets/images/bg_reading_mode.png differ diff --git a/assets/images/record_pause.webp b/assets/images/record_pause.webp new file mode 100644 index 0000000..041cb73 Binary files /dev/null and b/assets/images/record_pause.webp differ diff --git a/assets/images/record_play.webp b/assets/images/record_play.webp new file mode 100644 index 0000000..67bf635 Binary files /dev/null and b/assets/images/record_play.webp differ diff --git a/lib/common/extension/string_extension.dart b/lib/common/extension/string_extension.dart index a84f5dd..d5462e0 100644 --- a/lib/common/extension/string_extension.dart +++ b/lib/common/extension/string_extension.dart @@ -7,6 +7,8 @@ extension AssetExtension on String { String get assetPng => '$assetImg.png'; + String get assetWebp => '$assetImg.webp'; + String get assetGif => '$assetImg.gif'; } diff --git a/lib/pages/reading/bloc/reading_bloc.dart b/lib/pages/reading/bloc/reading_bloc.dart index 245d8e3..79530f2 100644 --- a/lib/pages/reading/bloc/reading_bloc.dart +++ b/lib/pages/reading/bloc/reading_bloc.dart @@ -1,13 +1,49 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wow_english/pages/reading/widgets/ReadingModeType.dart'; part 'reading_event.dart'; part 'reading_state.dart'; class ReadingPageBloc extends Bloc { - ReadingPageBloc() : super(ReadingPageInitial()) { - on((event, emit) { - // TODO: implement event handler - }); + + final PageController pageController; + + ///当前页索引 + int _currentPage = 0; + + ///当前播放模式 + ReadingModeType _currentMode = ReadingModeType.auto; + + int get currentPage => _currentPage + 1; + + ReadingModeType get currentMode => _currentMode; + + ReadingPageBloc(this.pageController) : super(ReadingPageInitial()) { + on(_pageControllerChange); + on(_selectItemLoad); + // pageController.addListener(() { + // _currentPage = pageController.page!.round(); + // }); + } + + @override + Future close() { + pageController.dispose(); + return super.close(); + } + + void _pageControllerChange(CurrentPageIndexChangeEvent event, Emitter emitter) async { + _currentPage = event.pageIndex; + emitter(CurrentPageIndexState()); + } + + void _selectItemLoad(CurrentModeChangeEvent event, Emitter emitter) async { + if (_currentMode == ReadingModeType.auto) { + _currentMode = ReadingModeType.manual; + } else { + _currentMode = ReadingModeType.auto; + } + emitter(CurrentModeState()); } } diff --git a/lib/pages/reading/bloc/reading_event.dart b/lib/pages/reading/bloc/reading_event.dart index aac9518..2e71909 100644 --- a/lib/pages/reading/bloc/reading_event.dart +++ b/lib/pages/reading/bloc/reading_event.dart @@ -2,3 +2,10 @@ part of 'reading_bloc.dart'; @immutable abstract class ReadingPageEvent {} + +class CurrentPageIndexChangeEvent extends ReadingPageEvent { + final int pageIndex; + CurrentPageIndexChangeEvent(this.pageIndex); +} + +class CurrentModeChangeEvent extends ReadingPageEvent {} \ No newline at end of file diff --git a/lib/pages/reading/bloc/reading_state.dart b/lib/pages/reading/bloc/reading_state.dart index 0de574a..d3e0411 100644 --- a/lib/pages/reading/bloc/reading_state.dart +++ b/lib/pages/reading/bloc/reading_state.dart @@ -4,3 +4,8 @@ part of 'reading_bloc.dart'; abstract class ReadingPageState {} class ReadingPageInitial extends ReadingPageState {} + +class CurrentPageIndexState extends ReadingPageState {} + +/// 手动or自动播放 +class CurrentModeState extends ReadingPageState {} diff --git a/lib/pages/reading/reading_page.dart b/lib/pages/reading/reading_page.dart index ad68fb5..4bf868c 100644 --- a/lib/pages/reading/reading_page.dart +++ b/lib/pages/reading/reading_page.dart @@ -2,17 +2,17 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:wow_english/common/extension/string_extension.dart'; -import 'package:wow_english/pages/practice/widgets/practice_header_widget.dart'; +import 'package:wow_english/pages/reading/widgets/ReadingModeType.dart'; import 'bloc/reading_bloc.dart'; -class ReadingItemPage extends StatelessWidget { - const ReadingItemPage({super.key}); +class ReadingPage extends StatelessWidget { + const ReadingPage({super.key}); @override Widget build(BuildContext context) { return BlocProvider( - create: (_) => ReadingPageBloc(), + create: (_) => ReadingPageBloc(PageController()), child: _ReadingPage(), ); } @@ -23,73 +23,160 @@ class _ReadingPage extends StatelessWidget { Widget build(BuildContext context) { return BlocListener( listener: (context, state) {}, - child: _voiceAnswerView(), + child: _readingPageView(), ); } - Widget _voiceAnswerView() => - BlocBuilder(builder: (context, state) { + Widget _readingPageView() => BlocBuilder( + buildWhen: (_, s) => s is CurrentPageIndexState, + builder: (context, state) { final bloc = BlocProvider.of(context); return Container( color: Colors.white, child: Stack( children: [ - Positioned( - left: 0, - right: 0, - bottom: 0, - child: Image.asset( - 'bottom_grass'.assetPng, - fit: BoxFit.fitWidth, - )), - Column( - children: [ - PracticeHeaderWidget( - title: '1/8', - onTap: () { - Navigator.pop(context); - }, + PageView.builder( + itemCount: 10, + controller: bloc.pageController, + onPageChanged: (int index) { + bloc.add(CurrentPageIndexChangeEvent(index)); + }, + itemBuilder: (context, int index) { + return _readingPagerItem(); + }), + Container( + color: Colors.transparent, + height: 60.h, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: + EdgeInsets.only(left: ScreenUtil().bottomBarHeight), + child: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: Image.asset( + 'back_around'.assetPng, + width: 40, + height: 40, + )), + ), + Container( + height: 32.h, + padding: EdgeInsets.symmetric(horizontal: 27.w), + decoration: BoxDecoration( + color: const Color(0xFF00B6F1), + borderRadius: BorderRadius.circular(15.r), + border: Border.all( + width: 1.0, + color: const Color(0xFF140C10), + ), + ), + alignment: Alignment.center, + child: Text( + '${bloc.currentPage}/10', + + ///todo 分母需要替换成数据数组长度 + style: TextStyle(fontSize: 20.sp, color: Colors.white), + ), + ), + + Padding( + padding: EdgeInsets.only(right: 15.w + ScreenUtil().bottomBarHeight), + child: GestureDetector( + onTap: () { + bloc.add(CurrentModeChangeEvent()); + }, + child: SizedBox( + height: 40.h, + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('bg_reading_mode'.assetPng), + fit: BoxFit.fill), + ), + alignment: Alignment.center, + padding: EdgeInsets.symmetric(horizontal: 10.w), + child: Text( + bloc.currentMode == ReadingModeType.auto + ? '设为手动' + : '设为自动', + style: TextStyle(fontSize: 14.5.sp), + ), + ), + ), + ), + ), + + // ScreenUtil().bottomBarHeight.horizontalSpace, + ], + ), + ), + Align( + alignment: Alignment.bottomLeft, + child: Container( + color: const Color(0x4DFFFFFF), + margin: EdgeInsets.symmetric(horizontal: 10.w), + child: Row( + children: [ + Image.asset( + 'voice'.assetPng, + height: 40.h, + width: 45.w, + ), + SizedBox( + width: 10.w, + ), + Expanded( + child: Text( + "HelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorld", + style: TextStyle( + color: const Color(0xFF333333), fontSize: 21.sp), + maxLines: 2, + overflow: TextOverflow.ellipsis, + )), + SizedBox( + width: 10.w, + ), + Image.asset( + 'micro_phone'.assetPng, + height: 47.h, + width: 47.w, + ), + SizedBox( + width: 10.w, + ), + Visibility( + visible: false, + + ///todo 依据是否录过音 + child: Image.asset( + 'record_pause'.assetWebp, + + ///todo 根据播放状态切换图片 + height: 33.h, + width: 33.w, + ), + ) + ], ), - Expanded( - child: PageView.builder( - itemCount: 10, - itemBuilder: (context, int index) { - return _voiceAnswerItem(); - })) - ], + ), ) ], ), ); }); - Widget _voiceAnswerItem() => - BlocBuilder(builder: (context, state) { - return Row( - mainAxisAlignment: MainAxisAlignment.center, + Widget _readingPagerItem() => + BlocBuilder(builder: (context, state) { + return Stack( children: [ Image.network( - 'https://img.liblibai.com/web/648331d5a2cb5.png?image_process=format,webp&x-oss-process=image/resize,w_2980,m_lfit/format,webp', - height: 186.h, - width: 186.w, - ), - 160.horizontalSpace, - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset( - 'voice'.assetPng, - height: 52.h, - width: 46.w, - ), - 70.verticalSpace, - Image.asset( - 'micro_phone'.assetPng, - height: 75.w, - width: 75.w, - ) - ], - ) + 'https://img.liblibai.com/web/648331d5a2cb5.png?image_process=format,webp&x-oss-process=image/resize,w_2980,m_lfit/format,webp', + height: double.infinity, + width: double.infinity), ], ); }); diff --git a/lib/pages/reading/widgets/ReadingModeType.dart b/lib/pages/reading/widgets/ReadingModeType.dart new file mode 100644 index 0000000..e0e983e --- /dev/null +++ b/lib/pages/reading/widgets/ReadingModeType.dart @@ -0,0 +1,6 @@ + +/// Enum for reading mode type +enum ReadingModeType { + auto, + manual +} \ No newline at end of file diff --git a/lib/pages/reading/widgets/reading_header_widget.dart b/lib/pages/reading/widgets/reading_header_widget.dart new file mode 100644 index 0000000..48fe594 --- /dev/null +++ b/lib/pages/reading/widgets/reading_header_widget.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:wow_english/common/extension/string_extension.dart'; + +/// 绘本页面的头部组件 +class ReadingHeaderWidget extends StatelessWidget { + const ReadingHeaderWidget({super.key, required this.onTap, this.title = ''}); + + final Function() onTap; + + final String title; + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.white, + height: 60.h, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: EdgeInsets.only(left: ScreenUtil().bottomBarHeight), + child: IconButton( + onPressed: () { + onTap(); + }, + icon: Image.asset( + 'back_around'.assetPng, + width: 40, + height: 40, + )), + ), + Container( + height: 32.h, + padding: EdgeInsets.symmetric(horizontal: 27.w), + decoration: BoxDecoration( + color: const Color(0xFF00B6F1), + borderRadius: BorderRadius.circular(15.r), + border: Border.all( + width: 1.0, + color: const Color(0xFF140C10), + ), + ), + alignment: Alignment.center, + child: Text( + title, + style: TextStyle(fontSize: 20.sp, color: Colors.white), + ), + ), + ScreenUtil().bottomBarHeight.horizontalSpace, + ], + ), + ); + } +} diff --git a/lib/route/route.dart b/lib/route/route.dart index e8ffe60..6e1ec33 100644 --- a/lib/route/route.dart +++ b/lib/route/route.dart @@ -21,6 +21,8 @@ import 'package:wow_english/pages/user/user_page.dart'; import 'package:wow_english/pages/video/lookvideo/look_video_page.dart'; import 'package:wow_english/pages/voiceanswer/voice_answer_page.dart'; +import '../pages/reading/reading_page.dart'; + class AppRouteName { static const String splash = 'splash'; static const String login = 'login'; @@ -41,6 +43,7 @@ class AppRouteName { static const String voiceAnswer = 'voiceAnswer'; static const String user = 'user'; static const String lookVideo = 'lookVideo'; + static const String reading = 'reading'; ///绘本 static const String tab = '/'; } @@ -113,6 +116,8 @@ class AppRouter { transitionDuration: Duration.zero, pageBuilder: (_, __, ___) => const TabPage(), transitionsBuilder: (_, __, ___, child) => child); + case AppRouteName.reading: + return CupertinoPageRoute(builder: (_) => const ReadingPage()); default: return CupertinoPageRoute( builder: (_) => Scaffold(body: Center(child: Text('No route defined for ${settings.name}')))); -- libgit2 0.22.2