diff --git a/assets/images/bottom_grass.png b/assets/images/bottom_grass.png new file mode 100644 index 0000000..bf99063 --- /dev/null +++ b/assets/images/bottom_grass.png diff --git a/assets/images/check_lesson.png b/assets/images/check_lesson.png new file mode 100644 index 0000000..3d0c081 --- /dev/null +++ b/assets/images/check_lesson.png diff --git a/assets/images/checked_logo.png b/assets/images/checked_logo.png new file mode 100644 index 0000000..16d9214 --- /dev/null +++ b/assets/images/checked_logo.png diff --git a/assets/images/ex_dis.png b/assets/images/ex_dis.png new file mode 100644 index 0000000..e33c94a --- /dev/null +++ b/assets/images/ex_dis.png diff --git a/assets/images/ex_sure.png b/assets/images/ex_sure.png new file mode 100644 index 0000000..9395734 --- /dev/null +++ b/assets/images/ex_sure.png diff --git a/assets/images/listback.png b/assets/images/listback.png new file mode 100644 index 0000000..06da2a6 --- /dev/null +++ b/assets/images/listback.png diff --git a/assets/images/wow_ex_lesson.png b/assets/images/wow_ex_lesson.png new file mode 100644 index 0000000..2c2541b --- /dev/null +++ b/assets/images/wow_ex_lesson.png diff --git a/lib/common/widgets/we_app_bar.dart b/lib/common/widgets/we_app_bar.dart index 4401879..4b5f43b 100644 --- a/lib/common/widgets/we_app_bar.dart +++ b/lib/common/widgets/we_app_bar.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:wow_english/common/extension/string_extension.dart'; class WEAppBar extends StatelessWidget implements PreferredSizeWidget { diff --git a/lib/home/home_page.dart b/lib/home/home_page.dart index d68e357..5b07eb4 100644 --- a/lib/home/home_page.dart +++ b/lib/home/home_page.dart @@ -31,7 +31,7 @@ class _HomePageView extends StatelessWidget { } else if (type == HeaderActionType.listen) { Navigator.of(AppRouter.context).pushNamed(AppRouteName.listen); } else if (type == HeaderActionType.shop) { - + Navigator.of(AppRouter.context).pushNamed(AppRouteName.shop); } else { } diff --git a/lib/lessons/lesson_page.dart b/lib/lessons/lesson_page.dart index 03814f7..73766dd 100644 --- a/lib/lessons/lesson_page.dart +++ b/lib/lessons/lesson_page.dart @@ -12,7 +12,6 @@ class LessonPage extends StatelessWidget { final int? starPageIndex; - @override Widget build(BuildContext context) { return BlocProvider( diff --git a/lib/route/route.dart b/lib/route/route.dart index 8a93fd8..6a75dcd 100644 --- a/lib/route/route.dart +++ b/lib/route/route.dart @@ -8,6 +8,9 @@ import 'package:wow_english/listen/listen_page.dart'; import 'package:wow_english/login/forgetpwd/forget_password_home_page.dart'; import 'package:wow_english/login/loginpage/login_page.dart'; import 'package:wow_english/login/setpwd/set_pwd_page.dart'; +import 'package:wow_english/shop/exchane/exchange_lesson_page.dart'; +import 'package:wow_english/shop/exchangelist/exchange_lesson_list_page.dart'; +import 'package:wow_english/shop/home/shop_home_page.dart'; import 'package:wow_english/tab/tab_page.dart'; @@ -20,6 +23,9 @@ class AppRouteName { static const String webView = 'webView'; static const String lesson = 'lesson'; static const String listen = 'listen'; + static const String shop = 'shop'; + static const String exLesson = 'exLesson'; + static const String exList = 'exList'; static const String tab = '/'; } @@ -46,6 +52,12 @@ class AppRouter { return CupertinoPageRoute(builder: (_) => const LessonPage()); case AppRouteName.listen: return CupertinoPageRoute(builder: (_) => const ListenPage()); + case AppRouteName.shop: + return CupertinoPageRoute(builder: (_) => const ShopHomePage()); + case AppRouteName.exLesson: + return CupertinoPageRoute(builder: (_) => const ExchangeLessonPage()); + case AppRouteName.exList: + return CupertinoPageRoute(builder: (_) => const ExchangeLessonListPage()); case AppRouteName.setPwd: final phoneNum = (settings.arguments as Map)['phoneNumber'] as String; return CupertinoPageRoute(builder: (_) => SetPassWordPage(phoneNum: phoneNum)); diff --git a/lib/shop/exchane/bloc/exchange_lesson_bloc.dart b/lib/shop/exchane/bloc/exchange_lesson_bloc.dart new file mode 100644 index 0000000..27dc483 --- /dev/null +++ b/lib/shop/exchane/bloc/exchange_lesson_bloc.dart @@ -0,0 +1,37 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +part 'exchange_lesson_event.dart'; +part 'exchange_lesson_state.dart'; + +class ExchangeLessonBloc extends Bloc { + + final TextEditingController codeNumberController = TextEditingController(); + + bool _checkCode = false; + + bool get checkCode => _checkCode; + + ExchangeLessonBloc() : super(ExchangeLessonInitial()) { + on(_codeNumberChange); + on(_requestCheckCode); + } + + _codeNumberChange(CodeNumberChangeEvent event,Emitter emitter) async { + if(codeNumberController.text.isNotEmpty) { + if (!_checkCode) { + _checkCode = true; + emitter(CheckCodeTypeChangeState()); + } + } else { + if (_checkCode) { + _checkCode = false; + emitter(CheckCodeTypeChangeState()); + } + } + } + + _requestCheckCode(CheckCodeEvent event, Emitter emitter) async { + emitter(CheckCodeResultState(false)); + } +} diff --git a/lib/shop/exchane/bloc/exchange_lesson_event.dart b/lib/shop/exchane/bloc/exchange_lesson_event.dart new file mode 100644 index 0000000..7a5d7d9 --- /dev/null +++ b/lib/shop/exchane/bloc/exchange_lesson_event.dart @@ -0,0 +1,8 @@ +part of 'exchange_lesson_bloc.dart'; + +@immutable +abstract class ExchangeLessonEvent {} +//输入兑换码 +class CodeNumberChangeEvent extends ExchangeLessonEvent {} +//验证兑换码 +class CheckCodeEvent extends ExchangeLessonEvent {} diff --git a/lib/shop/exchane/bloc/exchange_lesson_state.dart b/lib/shop/exchane/bloc/exchange_lesson_state.dart new file mode 100644 index 0000000..71ddfe1 --- /dev/null +++ b/lib/shop/exchane/bloc/exchange_lesson_state.dart @@ -0,0 +1,13 @@ +part of 'exchange_lesson_bloc.dart'; + +@immutable +abstract class ExchangeLessonState {} + +class ExchangeLessonInitial extends ExchangeLessonState {} +//输入兑换码状态 +class CheckCodeTypeChangeState extends ExchangeLessonState {} +//验证兑换码结果 +class CheckCodeResultState extends ExchangeLessonState { + final bool result; + CheckCodeResultState(this.result); +} diff --git a/lib/shop/exchane/exchange_lesson_page.dart b/lib/shop/exchane/exchange_lesson_page.dart new file mode 100644 index 0000000..e026b83 --- /dev/null +++ b/lib/shop/exchane/exchange_lesson_page.dart @@ -0,0 +1,133 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:wow_english/common/extension/string_extension.dart'; +import 'package:wow_english/common/widgets/textfield_customer_widget.dart'; +import 'package:wow_english/route/route.dart'; + +import 'bloc/exchange_lesson_bloc.dart'; + +class ExchangeLessonPage extends StatelessWidget { + const ExchangeLessonPage({super.key}); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => ExchangeLessonBloc(), + child: _ExchangeLessonPage(), + ); + } +} + +class _ExchangeLessonPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return BlocListener( + listener: (context, state){ + if (state is CheckCodeResultState) { + String title = state.result?'兑换成功':'兑换失败'; + EasyLoading.showToast(title); + Navigator.of(context).pushNamed(AppRouteName.exList); + } + }, + child: _exchangeLessonPageView(), + ); + } + + Widget _exchangeLessonPageView() => BlocBuilder( + builder: (context, state){ + final bloc = BlocProvider.of(context); + return Scaffold( + resizeToAvoidBottomInset: false, + body: Container( + color: Colors.white, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + 10.5.verticalSpace, + Padding( + padding: EdgeInsets.symmetric( + horizontal: 15.w + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + IconButton( + icon: Image.asset( + 'back_around'.assetPng, + width: 40, + height: 40, + ), + color: Colors.white, + onPressed: () { + Navigator.pop(context); + }, + ), + Image.asset( + 'wow_ex_lesson'.assetPng, + width: 139.w, + height: 81.h, + ), + SizedBox.fromSize( + size: const Size(40.0, 40.0) + ) + ], + ), + ), + Expanded( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 135.w), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextFieldCustomerWidget( + height: 55.h, + hitText: '请输入兑换码', + bgImageName: 'Input_layer_up', + textInputType: TextInputType.emailAddress, + controller: bloc.codeNumberController, + onChangeValue: (String value) { + bloc.add(CodeNumberChangeEvent()); + }, + ), + 21.5.verticalSpace, + GestureDetector( + onTap: () { + if (bloc.checkCode) { + bloc.add(CheckCodeEvent()); + } + }, + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + bloc.checkCode ? 'ex_sure'.assetPng:'ex_dis'.assetPng + ), + fit: BoxFit.fill + ), + ), + padding: EdgeInsets.symmetric(horizontal:27.w,vertical: 14.h), + child: Text( + '兑换', + style: TextStyle( + fontSize: 16.sp, + color: Colors.white + ), + ), + ), + ) + ], + ), + ), + ), + Image.asset( + 'bottom_grass'.assetPng, + ), + ], + ), + ), + ); + }); +} \ No newline at end of file diff --git a/lib/shop/exchangelist/bloc/exchange_list_bloc.dart b/lib/shop/exchangelist/bloc/exchange_list_bloc.dart new file mode 100644 index 0000000..bccf206 --- /dev/null +++ b/lib/shop/exchangelist/bloc/exchange_list_bloc.dart @@ -0,0 +1,15 @@ +import 'dart:async'; + +import 'package:bloc/bloc.dart'; +import 'package:meta/meta.dart'; + +part 'exchange_list_event.dart'; +part 'exchange_list_state.dart'; + +class ExchangeListBloc extends Bloc { + ExchangeListBloc() : super(ExchangeListInitial()) { + on((event, emit) { + // TODO: implement event handler + }); + } +} diff --git a/lib/shop/exchangelist/bloc/exchange_list_event.dart b/lib/shop/exchangelist/bloc/exchange_list_event.dart new file mode 100644 index 0000000..ae28d88 --- /dev/null +++ b/lib/shop/exchangelist/bloc/exchange_list_event.dart @@ -0,0 +1,4 @@ +part of 'exchange_list_bloc.dart'; + +@immutable +abstract class ExchangeListEvent {} diff --git a/lib/shop/exchangelist/bloc/exchange_list_state.dart b/lib/shop/exchangelist/bloc/exchange_list_state.dart new file mode 100644 index 0000000..80e9f94 --- /dev/null +++ b/lib/shop/exchangelist/bloc/exchange_list_state.dart @@ -0,0 +1,6 @@ +part of 'exchange_list_bloc.dart'; + +@immutable +abstract class ExchangeListState {} + +class ExchangeListInitial extends ExchangeListState {} diff --git a/lib/shop/exchangelist/exchange_lesson_list_page.dart b/lib/shop/exchangelist/exchange_lesson_list_page.dart new file mode 100644 index 0000000..deb6035 --- /dev/null +++ b/lib/shop/exchangelist/exchange_lesson_list_page.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wow_english/common/widgets/we_app_bar.dart'; +import 'package:wow_english/shop/exchangelist/widgets/exchange_list_item.dart'; + +import 'bloc/exchange_list_bloc.dart'; + +class ExchangeLessonListPage extends StatelessWidget { + const ExchangeLessonListPage({super.key}); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => ExchangeListBloc(), + child: _ExchangeLessonListPageView(), + ); + } +} + +class _ExchangeLessonListPageView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return BlocListener( + listener: (context,state){}, + child: _exchangeLessonListView(), + ); + } + + Widget _exchangeLessonListView() => BlocBuilder( + builder: (context, state){ + return Scaffold( + appBar: const WEAppBar( + titleText: '购买记录', + ), + body: SafeArea( + child: ListView.builder( + itemCount: 10, + itemBuilder: (BuildContext context,int index){ + return ExchangeListItem( + isCheck: index%3==0, + ); + }), + ), + ); + } + ); +} \ No newline at end of file diff --git a/lib/shop/exchangelist/widgets/exchange_list_item.dart b/lib/shop/exchangelist/widgets/exchange_list_item.dart new file mode 100644 index 0000000..f8cc6d9 --- /dev/null +++ b/lib/shop/exchangelist/widgets/exchange_list_item.dart @@ -0,0 +1,124 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:wow_english/common/extension/string_extension.dart'; + +class ExchangeListItem extends StatelessWidget { + const ExchangeListItem({super.key, required this.isCheck}); + + final bool isCheck; + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 127.h, + width: double.infinity, + child: Padding( + padding: EdgeInsets.only(left: 32.w,right: 32.w,bottom:13.h), + child: GestureDetector( + onTap: () { + + }, + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + 'listback'.assetPng, + ), + fit: BoxFit.fill + ) + ), + padding: EdgeInsets.symmetric(horizontal: 12.w), + child: Row( + children: [ + Container( + width: 70, + height: 70, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5.r), + border: Border.all( + width: 1.0, + color: const Color(0xFF333333), + ), + image: const DecorationImage( + image: NetworkImage('https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2Faa1c2213-820a-4223-8757-5f8cee318a28%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1688713226&t=192b18a613683bcdc5bd76f65c9ff032'), + ), + ), + ), + 17.horizontalSpace, + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + children: [ + Expanded( + child: Text( + '标题:wow english课程永久使用卡', + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 20.sp, + color: const Color(0xFF333333) + ), + ), + ), + Offstage( + offstage: isCheck, + child: Image.asset( + 'checked_logo'.assetPng, + width: 33.w, + height: 35.h + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(right: 35.w), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: Text( + '兑换日期:2022-03-08 12:22:33', + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 12.sp, + color: const Color(0xFF333333) + ), + ), + ), + Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '生效日期:2023-01-03', + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 12.sp, + color: const Color(0xFF333333) + ), + ), + Text( + '有效期至:永久有效', + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 12.sp, + color: const Color(0xFF333333) + ), + ) + ], + ) + ], + ), + ) + ], + ), + ) + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/shop/home/bloc/shop_home_bloc.dart b/lib/shop/home/bloc/shop_home_bloc.dart new file mode 100644 index 0000000..bd765c2 --- /dev/null +++ b/lib/shop/home/bloc/shop_home_bloc.dart @@ -0,0 +1,15 @@ +import 'dart:async'; + +import 'package:bloc/bloc.dart'; +import 'package:meta/meta.dart'; + +part 'shop_home_event.dart'; +part 'shop_home_state.dart'; + +class ShopHomeBloc extends Bloc { + ShopHomeBloc() : super(ShopHomeInitial()) { + on((event, emit) { + // TODO: implement event handler + }); + } +} diff --git a/lib/shop/home/bloc/shop_home_event.dart b/lib/shop/home/bloc/shop_home_event.dart new file mode 100644 index 0000000..f35f8fd --- /dev/null +++ b/lib/shop/home/bloc/shop_home_event.dart @@ -0,0 +1,4 @@ +part of 'shop_home_bloc.dart'; + +@immutable +abstract class ShopHomeEvent {} diff --git a/lib/shop/home/bloc/shop_home_state.dart b/lib/shop/home/bloc/shop_home_state.dart new file mode 100644 index 0000000..d0b3c17 --- /dev/null +++ b/lib/shop/home/bloc/shop_home_state.dart @@ -0,0 +1,6 @@ +part of 'shop_home_bloc.dart'; + +@immutable +abstract class ShopHomeState {} + +class ShopHomeInitial extends ShopHomeState {} diff --git a/lib/shop/home/shop_home_page.dart b/lib/shop/home/shop_home_page.dart new file mode 100644 index 0000000..aed24b6 --- /dev/null +++ b/lib/shop/home/shop_home_page.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:wow_english/common/extension/string_extension.dart'; +import 'package:wow_english/common/widgets/we_app_bar.dart'; +import 'package:wow_english/route/route.dart'; +import 'package:wow_english/shop/home/bloc/shop_home_bloc.dart'; + +class ShopHomePage extends StatelessWidget { + const ShopHomePage({super.key}); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => ShopHomeBloc(), + child: _ShopHomeView(), + ); + } +} + +class _ShopHomeView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return BlocListener( + listener: (context, state) {}, + child: _shopHomeWidget(), + ); + } + + Widget _shopHomeWidget() => BlocBuilder(builder: (context, state){ + return Scaffold( + appBar: WEAppBar( + actions: [ + IconButton( + icon: Image.asset( + 'check_lesson'.assetPng, + width: 40, + height: 40, + ), + color: Colors.white, + onPressed: () { + Navigator.of(context).pushNamed(AppRouteName.exLesson); + }, + ), + IconButton( + icon: Image.asset( + 'shop'.assetPng, + width: 40, + height: 40, + ), + color: Colors.white, + onPressed: () { + EasyLoading.showToast('购前须知'); + }, + ) + ], + ), + ); + }); +} \ No newline at end of file