diff --git a/assets/images/Input_layer_down.png b/assets/images/Input_layer_down.png new file mode 100644 index 0000000..790948b --- /dev/null +++ b/assets/images/Input_layer_down.png diff --git a/assets/images/Input_layer_up.png b/assets/images/Input_layer_up.png new file mode 100644 index 0000000..13e6473 --- /dev/null +++ b/assets/images/Input_layer_up.png diff --git a/assets/images/lock.png b/assets/images/lock.png new file mode 100644 index 0000000..9c98d22 --- /dev/null +++ b/assets/images/lock.png diff --git a/assets/images/login_enter.png b/assets/images/login_enter.png new file mode 100644 index 0000000..277404b --- /dev/null +++ b/assets/images/login_enter.png diff --git a/assets/images/login_enter_dis.png b/assets/images/login_enter_dis.png new file mode 100644 index 0000000..e33c94a --- /dev/null +++ b/assets/images/login_enter_dis.png diff --git a/assets/images/login_logo.png b/assets/images/login_logo.png new file mode 100644 index 0000000..1459d52 --- /dev/null +++ b/assets/images/login_logo.png diff --git a/assets/images/phone.png b/assets/images/phone.png new file mode 100644 index 0000000..ad920db --- /dev/null +++ b/assets/images/phone.png diff --git a/assets/images/securitycode.png b/assets/images/securitycode.png new file mode 100644 index 0000000..4a11448 --- /dev/null +++ b/assets/images/securitycode.png diff --git a/assets/images/securitycode_dis.png b/assets/images/securitycode_dis.png new file mode 100644 index 0000000..2684270 --- /dev/null +++ b/assets/images/securitycode_dis.png diff --git a/assets/images/splash.png b/assets/images/splash.png new file mode 100644 index 0000000..d6f7440 --- /dev/null +++ b/assets/images/splash.png diff --git a/assets/images/wow_logo.png b/assets/images/wow_logo.png new file mode 100644 index 0000000..43978a0 --- /dev/null +++ b/assets/images/wow_logo.png diff --git a/lib/app/splash_page.dart b/lib/app/splash_page.dart index fdb5d92..c4ac7fd 100644 --- a/lib/app/splash_page.dart +++ b/lib/app/splash_page.dart @@ -1,7 +1,10 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; +import 'package:wow_english/common/extension/string_extension.dart'; import 'package:wow_english/network/basic_configuration.dart'; import 'package:wow_english/route/route.dart'; -import 'package:wow_english/widgets/we_app_bar.dart'; + class SplashPage extends StatelessWidget { const SplashPage({super.key}); @@ -22,23 +25,36 @@ class TransitionView extends StatefulWidget { } class _TransitionViewState extends State { + + Future startTime() async { + Timer(const Duration(seconds: 1),() { + if(BasicConfigurationManager().sessionId!.isNotEmpty) { + Navigator.of(context).pushNamedAndRemoveUntil(AppRouteName.tab, (route) => false); + } else { + Navigator.of(context).pushNamedAndRemoveUntil(AppRouteName.login,(route) => false); + } + }); + } + + @override + void initState() { + super.initState(); + startTime(); + } + @override Widget build(BuildContext context) { return Scaffold( - appBar: WEAppBar( - titleText: '首页', - backgroundColor: Theme.of(context).colorScheme.inversePrimary - ), body: Center( - child: GestureDetector( - onTap: (){ - if(BasicConfigurationManager().sessionId!.isNotEmpty) { - Navigator.of(context).pushNamedAndRemoveUntil(AppRouteName.tab, (route) => false); - } else { - Navigator.of(context).pushNamed(AppRouteName.login,arguments: {'title':'登陆'}); - } - }, - child: const Text('登陆'), + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + 'splash'.assetPng, + ), + fit: BoxFit.fill + ) + ), ), ), ); diff --git a/lib/common/extension/string_extension.dart b/lib/common/extension/string_extension.dart new file mode 100644 index 0000000..38b97a6 --- /dev/null +++ b/lib/common/extension/string_extension.dart @@ -0,0 +1,8 @@ +const String _assetImagePrefix = "assets/images/"; + +/// 资源类扩展方法 +extension AssetExtension on String { + /// 图片url + String get assetImg => _assetImagePrefix + this; + String get assetPng => 'assets/images/$this.png'; +} \ No newline at end of file diff --git a/lib/login/blocs/login_bloc.dart b/lib/login/blocs/login_bloc.dart index c0b17f4..65e221f 100644 --- a/lib/login/blocs/login_bloc.dart +++ b/lib/login/blocs/login_bloc.dart @@ -1,42 +1,125 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_easyloading/flutter_easyloading.dart'; -import 'package:wow_english/network/api.dart'; -import 'package:wow_english/network/network_manager.dart'; part 'login_event.dart'; part 'login_state.dart'; +enum LoginType { + ///密码登陆 + pwd, + ///验证码登陆 + sms, +} + class LoginBloc extends Bloc { - bool _isLogin = false; + bool _canLogin = false; + ///是否可以发送验证码 + bool _canSendSms = false; + ///是否阅读协议 + bool _agreement = false; + ///登陆方式 + LoginType _loginType = LoginType.sms; + + final TextEditingController phoneNumController = TextEditingController(); + final TextEditingController checkNumController = TextEditingController(); - bool get isLogin => _isLogin; + bool get canLogin => _canLogin; + bool get agreement => _agreement; + LoginType get loginType => _loginType; + bool get canSendSms => _canSendSms; LoginBloc() : super(LoginInitial()) { on(_requestLoginApi); + on(_changeLoginType); + on(_changePhoneNumber); + on(_agreementTypeChange); + on(_forgetPassword); + on(_checkFiledChange); } + ///请求登陆 void _requestLoginApi(RequestLoginEvent event, Emitter emitter) async { - EasyLoading.show(status: 'loading'); - await DioUtil().requestData( - Api.testApi, - successCallBack: (dynamic data){ - EasyLoading.dismiss(); - if (kDebugMode) { - print(data); - } - _isLogin = true; - emitter(LoginEventChangeState()); - }, - errorCallBack: (dynamic error){ - EasyLoading.dismiss(); - if (kDebugMode) { - print(error); - } - _isLogin = false; - emitter(LoginEventChangeState()); - }); + + } + + ///切换登陆方式 + void _changeLoginType(ChangeLoginTypeEvent event, Emitter emitter) async { + if (_loginType == LoginType.sms) { + _loginType = LoginType.pwd; + } else { + _loginType = LoginType.sms; + } + checkNumController.clear(); + if (_loginStateChange()) { + emitter(LoginEventChangeState()); + } + emitter(LoginTypeChangeState()); + } + + ///手机号输入 + void _changePhoneNumber(PhoneNumChangeEvent event, Emitter emitter) async { + if(phoneNumController.text.isNotEmpty) { + if (!_canSendSms) { + _canSendSms = true; + emitter(SmsSendTypeChangeState()); + } + if (_loginStateChange()) { + emitter(LoginEventChangeState()); + } + } else { + if (_canSendSms) { + _canSendSms = false; + emitter(SmsSendTypeChangeState()); + } + if (_loginStateChange()) { + emitter(LoginEventChangeState()); + } + } + } + + ///验证码/密码输入变化 + void _checkFiledChange(CheckFieldChangeEvent event,Emitter emitter) async { + if (_loginStateChange()) { + emitter(LoginEventChangeState()); + } + } + + ///是否阅读协议 + void _agreementTypeChange(AgreementChangeEvent event, Emitter emitter) async { + _agreement = !_agreement; + emitter(AgreementTypeChangeState()); + if (_loginStateChange()) { + emitter(LoginEventChangeState()); + } + } + + ///忘记密码 + void _forgetPassword(ForgetPasswordEvent event, Emitter emitter) async { + + } + + bool _loginStateChange() { + if (_agreement) { + if (phoneNumController.text.isNotEmpty && checkNumController.text.isNotEmpty) { + if (!_canLogin) { + _canLogin = true; + return true; + } + } else { + if (_canLogin) { + _canLogin = false; + return true; + } + } + } else { + if (_canLogin) { + _canLogin = false; + return true; + } + } + return false; } } diff --git a/lib/login/blocs/login_event.dart b/lib/login/blocs/login_event.dart index fff0f04..7922b5c 100644 --- a/lib/login/blocs/login_event.dart +++ b/lib/login/blocs/login_event.dart @@ -4,3 +4,13 @@ part of 'login_bloc.dart'; abstract class LoginEvent {} class RequestLoginEvent extends LoginEvent {} + +class ChangeLoginTypeEvent extends LoginEvent {} + +class PhoneNumChangeEvent extends LoginEvent {} + +class CheckFieldChangeEvent extends LoginEvent {} + +class AgreementChangeEvent extends LoginEvent {} + +class ForgetPasswordEvent extends LoginEvent {} diff --git a/lib/login/blocs/login_state.dart b/lib/login/blocs/login_state.dart index 3417041..030cdf2 100644 --- a/lib/login/blocs/login_state.dart +++ b/lib/login/blocs/login_state.dart @@ -6,3 +6,9 @@ abstract class LoginState {} class LoginInitial extends LoginState {} class LoginEventChangeState extends LoginState {} + +class LoginTypeChangeState extends LoginState {} + +class SmsSendTypeChangeState extends LoginState {} + +class AgreementTypeChangeState extends LoginState {} diff --git a/lib/login/login_page.dart b/lib/login/login_page.dart index a42a079..e3f9f84 100644 --- a/lib/login/login_page.dart +++ b/lib/login/login_page.dart @@ -1,15 +1,11 @@ -import 'package:flutter/foundation.dart'; 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/login/blocs/login_bloc.dart'; -import 'package:wow_english/modes/test_model.dart'; -import 'package:wow_english/route/route.dart'; -import 'package:wow_english/widgets/we_app_bar.dart'; class LoginPage extends StatelessWidget { - const LoginPage({super.key, this.title}); - - final String? title; + const LoginPage({super.key}); @override Widget build(BuildContext context) { @@ -23,46 +19,87 @@ class LoginPage extends StatelessWidget { builder: (context, state) { final bloc = BlocProvider.of(context); return Scaffold( - appBar: WEAppBar( - titleText: title??'', - ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, + body: SafeArea( + child: ListView( children: [ - GestureDetector( - onTap: () { - Navigator.of(context).pushNamedAndRemoveUntil(AppRouteName.tab, (route) => false); - }, - child: const Text( - '进入首页' - ), - ), - Text( - bloc.isLogin?'登陆成功':'还未登陆' - ), - GestureDetector( - onTap: () { - TestModel testModel = TestModel(name: 'lcy',age: 31,sex: '男'); - Map jsonMap = testModel.toJson(); - if (kDebugMode) { - print(jsonMap); - } - TestModel testModel2 = TestModel.fromJson(jsonMap); - if (kDebugMode) { - print(testModel2.name); - } - }, - child: const Text( - '数据转换' - ), - ), - GestureDetector( - onTap: (){ - bloc.add(RequestLoginEvent()); - }, - child: const Text( - '发起网络请求' + Container( + padding: EdgeInsets.only(top: 25.h), + child: Stack( + children: [ + Positioned( + right: 29.w, + child: GestureDetector( + onTap: () => bloc.add(ChangeLoginTypeEvent()), + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + 'login_logo'.assetPng + ), + fit: BoxFit.fill + ), + ), + padding: const EdgeInsets.symmetric(horizontal: 18.0), + child: Text( + bloc.loginType == LoginType.sms?'密码登陆':'验证码密码' + ), + ), + ) + ), + Center( + child: Column( + children: [ + Image.asset( + 'wow_logo'.assetPng, + height: 81.h, + width: 139.w,), + Offstage( + offstage: bloc.loginType == LoginType.pwd, + child: _buildSmsViewWidget(), + ), + Offstage( + offstage: bloc.loginType == LoginType.sms, + child: _buildPwdViewWidget(), + ), + 20.verticalSpace, + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + onTap: () => bloc.add(AgreementChangeEvent()), + child: Icon( + bloc.agreement ? Icons.check_circle_outlined:Icons.circle_outlined, + color:bloc.agreement ? Colors.green:Colors.black), + ), + 6.horizontalSpace, + const Text('我已阅读并同意《用户隐私协议》,《儿童隐私策略》') + ], + ), + 14.5.verticalSpace, + GestureDetector( + onTap: () => bloc.add(ChangeLoginTypeEvent()), + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + bloc.canLogin?'login_enter'.assetPng:'login_enter_dis'.assetPng + ), + fit: BoxFit.fill + ), + ), + padding: const EdgeInsets.symmetric( + horizontal: 36.0, + vertical: 20.0 + ), + child: const Text( + '登录' + ), + ), + ) + ], + ), + ) + ], ), ) ], @@ -71,4 +108,202 @@ class LoginPage extends StatelessWidget { ); }, ); + + Widget _buildSmsViewWidget()=> BlocBuilder( + builder: (context,state){ + final bloc = BlocProvider.of(context); + return Column( + children: [ + 15.verticalSpace, + Container( + padding: EdgeInsets.symmetric(horizontal: 135.w), + width: double.infinity, + height: 55, + alignment: Alignment.center, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + 'Input_layer_up'.assetPng + ) + ) + ), + child: TextField( + controller: bloc.phoneNumController, + textAlign: TextAlign.center, + textInputAction: TextInputAction.done, + keyboardType: TextInputType.phone, + decoration: const InputDecoration( + hintText: '请输入手机号', + border: InputBorder.none, + ), + onChanged: (String value) { + bloc.add(PhoneNumChangeEvent()); + }, + ) + ), + 6.5.verticalSpace, + const Text('未注册用户登录默认注册'), + 4.5.verticalSpace, + Container( + padding: EdgeInsets.symmetric(horizontal: 205.w), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + width: 257, + height: 50, + alignment: Alignment.center, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + 'Input_layer_down'.assetPng + ) + ) + ), + child: TextField( + controller: bloc.checkNumController, + textAlign: TextAlign.center, + textInputAction: TextInputAction.done, + keyboardType: TextInputType.number, + decoration: const InputDecoration( + hintText: '请输入验证码', + border: InputBorder.none, + ), + onChanged: (String value) { + bloc.add(CheckFieldChangeEvent()); + }, + ) + ), + GestureDetector( + onTap: () { + if (bloc.canSendSms) { + bloc.add(ChangeLoginTypeEvent()); + } + }, + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + bloc.canSendSms?'securitycode'.assetPng:'securitycode_dis'.assetPng + ), + fit: BoxFit.fill + ), + ), + padding: const EdgeInsets.symmetric(horizontal:12.0,vertical: 15.0), + child: const Text( + '获取验证码' + ), + ), + ) + ], + ), + ) + ], + ); + }); + + Widget _buildPwdViewWidget()=> BlocBuilder( + builder: (context,state){ + final bloc = BlocProvider.of(context); + return Container( + padding: EdgeInsets.symmetric(horizontal: 135.w), + child: Column( + children: [ + 15.verticalSpace, + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'phone'.assetPng, + height: 45, + width: 35, + ), + 10.5.horizontalSpace, + Container( + width: 397.5, + height: 55, + alignment: Alignment.center, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + 'Input_layer_up'.assetPng + ), + fit: BoxFit.fill, + ) + ), + child: TextField( + controller: bloc.phoneNumController, + textAlign: TextAlign.center, + textInputAction: TextInputAction.done, + decoration: const InputDecoration( + hintText: '请输入手机号', + border: InputBorder.none, + ), + keyboardType: TextInputType.phone, + onChanged: (String value) { + bloc.add(PhoneNumChangeEvent()); + }, + ) + ), + 5.horizontalSpace, + const SizedBox( + width: 100, + height: 55.0, + ) + ], + ), + 12.verticalSpace, + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'lock'.assetPng, + height: 34, + width: 31, + ), + 10.5.horizontalSpace, + Container( + width: 397.5, + height: 55, + alignment: Alignment.center, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + 'Input_layer_down'.assetPng + ), + fit: BoxFit.fill, + ) + ), + child: TextField( + controller: bloc.checkNumController, + textAlign: TextAlign.center, + textInputAction: TextInputAction.done, + decoration: const InputDecoration( + hintText: '请输入密码', + border: InputBorder.none, + ), + onChanged: (String value) { + bloc.add(CheckFieldChangeEvent()); + }, + ) + ), + 5.horizontalSpace, + GestureDetector( + onTap: () => bloc.add(ForgetPasswordEvent()), + child: Container( + width: 100, + height: 55.0, + alignment: Alignment.centerLeft, + child: const Text( + '忘记密码 ?' + ), + ), + ) + ], + ) + ], + ), + ); + }); + } diff --git a/lib/route/route.dart b/lib/route/route.dart index a62269a..93b9927 100644 --- a/lib/route/route.dart +++ b/lib/route/route.dart @@ -25,8 +25,7 @@ class AppRouter { transitionDuration: Duration.zero, transitionsBuilder: (_, __, ___, child) => child); case AppRouteName.login: - final title = (settings.arguments as Map)['title'] as String; - return CupertinoPageRoute(builder: (_) => LoginPage(title: title)); + return CupertinoPageRoute(builder: (_) => const LoginPage()); case AppRouteName.tab: return PageRouteBuilder( opaque: false, diff --git a/pubspec.yaml b/pubspec.yaml index a6b7d91..996fa78 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -108,6 +108,9 @@ flutter: # the material Icons class. uses-material-design: true + assets: + - assets/images/ + # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg