Commit bfb40cd0bdeb57879c4cc8471a8d303b36b43e7f

Authored by liangchengyou
1 parent 1d5315dd

feat:忘记密码获取验证码

assets/images/steven_bride.png 0 → 100644

142 KB

lib/common/pages/wow_web_page.dart 0 → 100644
  1 +import 'dart:io';
  2 +
  3 +import 'package:flutter/material.dart';
  4 +import 'package:flutter/services.dart';
  5 +import 'package:flutter_easyloading/flutter_easyloading.dart';
  6 +import 'package:limiting_direction_csx/limiting_direction_csx.dart';
  7 +import 'package:webview_flutter/webview_flutter.dart';
  8 +import 'package:wow_english/common/widgets/we_app_bar.dart';
  9 +
  10 +class WowWebViewPage extends StatefulWidget {
  11 + const WowWebViewPage({super.key, required this.urlStr, required this.webViewTitle});
  12 +
  13 + final String urlStr;
  14 + final String webViewTitle;
  15 +
  16 + @override
  17 + State<StatefulWidget> createState() {
  18 + return _WowWebViewPageState();
  19 + }
  20 +}
  21 +
  22 +class _WowWebViewPageState extends State<WowWebViewPage> {
  23 +
  24 + late final WebViewController _controller;
  25 +
  26 + @override
  27 + void initState() {
  28 + super.initState();
  29 +
  30 + if (Platform.isIOS) {
  31 + LimitingDirectionCsx.setScreenDirection(DeviceDirectionMask.PortraitUpsideDown);
  32 + } else {
  33 + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
  34 + }
  35 +
  36 + final WebViewController controller =WebViewController()
  37 + ..setJavaScriptMode(JavaScriptMode.unrestricted)
  38 + ..setBackgroundColor(const Color(0x00000000))
  39 + ..setNavigationDelegate(
  40 + NavigationDelegate(
  41 + onProgress: (int progress) {
  42 + // Update loading bar.
  43 + },
  44 + onPageStarted: (String url) {
  45 + EasyLoading.show();
  46 + },
  47 + onPageFinished: (String url) {
  48 + EasyLoading.dismiss();
  49 + },
  50 + onWebResourceError: (WebResourceError error) {
  51 + EasyLoading.showError(error.description);
  52 + },
  53 + onNavigationRequest: (NavigationRequest request) {
  54 + return NavigationDecision.navigate;
  55 + },
  56 + ),
  57 + )
  58 + ..loadRequest(Uri.parse(widget.urlStr));
  59 + _controller = controller;
  60 + }
  61 +
  62 + @override
  63 + Widget build(BuildContext context) {
  64 + return Scaffold(
  65 + backgroundColor: Colors.white,
  66 + appBar: WEAppBar(
  67 + titleText: widget.webViewTitle,
  68 + ),
  69 + body: WebViewWidget(controller: _controller,),
  70 + );
  71 + }
  72 +
  73 + @override
  74 + void deactivate() {
  75 + super.deactivate();
  76 + if (Platform.isIOS) {
  77 + LimitingDirectionCsx.setScreenDirection(DeviceDirectionMask.Landscape);
  78 + } else {
  79 + SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft,DeviceOrientation.landscapeRight]);
  80 + }
  81 + }
  82 +}
0 \ No newline at end of file 83 \ No newline at end of file
lib/widgets/we_app_bar.dart renamed to lib/common/widgets/we_app_bar.dart
lib/login/forgetpwd/bloc/forget_pwd_home_bloc.dart
1 -import 'dart:async';  
2 -  
3 -import 'package:bloc/bloc.dart';  
4 -import 'package:meta/meta.dart'; 1 +import 'package:flutter/cupertino.dart';
  2 +import 'package:flutter_bloc/flutter_bloc.dart';
5 3
6 part 'forget_pwd_home_event.dart'; 4 part 'forget_pwd_home_event.dart';
7 part 'forget_pwd_home_state.dart'; 5 part 'forget_pwd_home_state.dart';
8 6
9 class ForgetPwdHomeBloc extends Bloc<ForgetPwdHomeEvent, ForgetPwdHomeState> { 7 class ForgetPwdHomeBloc extends Bloc<ForgetPwdHomeEvent, ForgetPwdHomeState> {
  8 +
  9 + ///是否可以发送验证码
  10 + bool _canSendSms = false;
  11 + bool _canSetPwd = false;
  12 +
  13 + bool get canSendSms => _canSendSms;
  14 + bool get canSetPwd => _canSetPwd;
  15 +
  16 + final TextEditingController phoneNumController = TextEditingController();
  17 + final TextEditingController checkNumController = TextEditingController();
  18 +
10 ForgetPwdHomeBloc() : super(ForgetPwdHomeInitial()) { 19 ForgetPwdHomeBloc() : super(ForgetPwdHomeInitial()) {
11 - on<ForgetPwdHomeEvent>((event, emit) {  
12 - // TODO: implement event handler  
13 - }); 20 + on<PhoneNumChangeEvent>(_changePhoneNumber);
  21 + on<CheckCodeChangeEvent>(_changeCodeNumber);
  22 + on<SetPassWordEvent>(_setPassWord);
  23 + on<SendSmsCodeEvent>(_sendSmsCode);
  24 + }
  25 +
  26 + void _changePhoneNumber(PhoneNumChangeEvent event, Emitter<ForgetPwdHomeState> emitter) async {
  27 + if (phoneNumController.text.isNotEmpty) {
  28 + if (!_canSendSms) {
  29 + _canSendSms = true;
  30 + emitter(SendSmsCodeTypeChangeState());
  31 + emitter(SetPwdTypeChangeState());
  32 + }
  33 + } else {
  34 + if (_canSendSms) {
  35 + _canSendSms = false;
  36 + emitter(SendSmsCodeTypeChangeState());
  37 + emitter(SetPwdTypeChangeState());
  38 + }
  39 + }
  40 + }
  41 +
  42 + void _changeCodeNumber(CheckCodeChangeEvent event, Emitter<ForgetPwdHomeState> emitter) async {
  43 + if (checkNumController.text.isNotEmpty) {
  44 + if (!_canSetPwd) {
  45 + _canSetPwd = true;
  46 + emitter(SendSmsCodeTypeChangeState());
  47 + emitter(SetPwdTypeChangeState());
  48 + }
  49 + } else {
  50 + if (_canSetPwd) {
  51 + _canSetPwd = false;
  52 + emitter(SendSmsCodeTypeChangeState());
  53 + emitter(SetPwdTypeChangeState());
  54 + }
  55 + }
  56 + }
  57 +
  58 + void _setPassWord(SetPassWordEvent event,Emitter<ForgetPwdHomeState> emitter) async {
  59 +
  60 + }
  61 +
  62 + void _sendSmsCode(SendSmsCodeEvent event,Emitter<ForgetPwdHomeState> emitter) async {
  63 +
14 } 64 }
15 } 65 }
lib/login/forgetpwd/bloc/forget_pwd_home_event.dart
@@ -2,3 +2,11 @@ part of &#39;forget_pwd_home_bloc.dart&#39;; @@ -2,3 +2,11 @@ part of &#39;forget_pwd_home_bloc.dart&#39;;
2 2
3 @immutable 3 @immutable
4 abstract class ForgetPwdHomeEvent {} 4 abstract class ForgetPwdHomeEvent {}
  5 +
  6 +class PhoneNumChangeEvent extends ForgetPwdHomeEvent {}
  7 +
  8 +class CheckCodeChangeEvent extends ForgetPwdHomeEvent {}
  9 +
  10 +class SetPassWordEvent extends ForgetPwdHomeEvent {}
  11 +
  12 +class SendSmsCodeEvent extends ForgetPwdHomeEvent {}
lib/login/forgetpwd/bloc/forget_pwd_home_state.dart
@@ -4,3 +4,7 @@ part of &#39;forget_pwd_home_bloc.dart&#39;; @@ -4,3 +4,7 @@ part of &#39;forget_pwd_home_bloc.dart&#39;;
4 abstract class ForgetPwdHomeState {} 4 abstract class ForgetPwdHomeState {}
5 5
6 class ForgetPwdHomeInitial extends ForgetPwdHomeState {} 6 class ForgetPwdHomeInitial extends ForgetPwdHomeState {}
  7 +
  8 +class SendSmsCodeTypeChangeState extends ForgetPwdHomeState {}
  9 +
  10 +class SetPwdTypeChangeState extends ForgetPwdHomeState {}
lib/login/forgetpwd/forget_password_home_page.dart
@@ -2,6 +2,7 @@ import &#39;package:flutter/material.dart&#39;; @@ -2,6 +2,7 @@ import &#39;package:flutter/material.dart&#39;;
2 import 'package:flutter_bloc/flutter_bloc.dart'; 2 import 'package:flutter_bloc/flutter_bloc.dart';
3 import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 import 'package:flutter_screenutil/flutter_screenutil.dart';
4 import 'package:wow_english/common/extension/string_extension.dart'; 4 import 'package:wow_english/common/extension/string_extension.dart';
  5 +import 'package:wow_english/common/widgets/textfield_customer_widget.dart';
5 import 'package:wow_english/login/forgetpwd/bloc/forget_pwd_home_bloc.dart'; 6 import 'package:wow_english/login/forgetpwd/bloc/forget_pwd_home_bloc.dart';
6 7
7 class ForgetPasswordHomePage extends StatelessWidget { 8 class ForgetPasswordHomePage extends StatelessWidget {
@@ -25,7 +26,7 @@ class ForgetPasswordHomePage extends StatelessWidget { @@ -25,7 +26,7 @@ class ForgetPasswordHomePage extends StatelessWidget {
25 child: ListView( 26 child: ListView(
26 children: [ 27 children: [
27 Padding( 28 Padding(
28 - padding: EdgeInsets.symmetric(horizontal: 40.w), 29 + padding: EdgeInsets.only(left: 49.w,right: 10.w),
29 child: Column( 30 child: Column(
30 children: [ 31 children: [
31 34.verticalSpace, 32 34.verticalSpace,
@@ -45,6 +46,122 @@ class ForgetPasswordHomePage extends StatelessWidget { @@ -45,6 +46,122 @@ class ForgetPasswordHomePage extends StatelessWidget {
45 ), 46 ),
46 ) 47 )
47 ], 48 ],
  49 + ),
  50 + Row(
  51 + crossAxisAlignment: CrossAxisAlignment.start,
  52 + children: [
  53 + Expanded(
  54 + child: Column(
  55 + children: [
  56 + 44.5.verticalSpace,
  57 + Row(
  58 + children: [
  59 + Image.asset(
  60 + 'phone'.assetPng,
  61 + height: 45.h,
  62 + width: 35.w,
  63 + ),
  64 + 15.horizontalSpace,
  65 + Expanded(
  66 + child: TextFieldCustomerWidget(
  67 + height: 50.h,
  68 + hitText: '请输入当前手机号',
  69 + textInputType: TextInputType.phone,
  70 + bgImageName: 'Input_layer_up',
  71 + onChangeValue: (String value) {
  72 + bloc.add(PhoneNumChangeEvent());
  73 + },
  74 + controller: bloc.phoneNumController,
  75 + )
  76 + )
  77 + ],
  78 + ),
  79 + 11.5.verticalSpace,
  80 + Row(
  81 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
  82 + children: [
  83 + Image.asset(
  84 + 'lock'.assetPng,
  85 + height: 34.h,
  86 + width: 31.w,
  87 + ),
  88 + 18.5.horizontalSpace,
  89 + Expanded(
  90 + child: TextFieldCustomerWidget(
  91 + hitText: '请输入验证码',
  92 + bgImageName: 'Input_layer_down',
  93 + onChangeValue: (String value) {
  94 + bloc.add(CheckCodeChangeEvent());
  95 + },
  96 + textInputType: TextInputType.emailAddress,
  97 + controller: bloc.checkNumController,
  98 + )
  99 + ),
  100 + 16.5.horizontalSpace,
  101 + GestureDetector(
  102 + onTap: () {
  103 + if (bloc.canSendSms) {
  104 + bloc.add(SendSmsCodeEvent());
  105 + }
  106 + },
  107 + child: Container(
  108 + decoration: BoxDecoration(
  109 + image: DecorationImage(
  110 + image: AssetImage(
  111 + bloc.canSendSms?'securitycode'.assetPng:'securitycode_dis'.assetPng
  112 + ),
  113 + fit: BoxFit.fill
  114 + ),
  115 + ),
  116 + padding: const EdgeInsets.symmetric(horizontal:12.0,vertical: 15.0),
  117 + child: const Text(
  118 + '获取验证码',
  119 + style: TextStyle(
  120 + fontSize: 16,
  121 + color: Colors.white
  122 + ),
  123 + ),
  124 + ),
  125 + )
  126 + ],
  127 + )
  128 + ],
  129 + )
  130 + ),
  131 + 2.verticalSpace,
  132 + Image.asset(
  133 + 'steven_bride'.assetPng,
  134 + height: 173.h,
  135 + width: 157.w,
  136 + )
  137 + ],
  138 + ),
  139 + GestureDetector(
  140 + onTap: () {
  141 + if (bloc.canSetPwd) {
  142 + bloc.add(SetPassWordEvent());
  143 + }
  144 + },
  145 + child: Container(
  146 + decoration: BoxDecoration(
  147 + image: DecorationImage(
  148 + image: AssetImage(
  149 + bloc.canSetPwd?'login_enter'.assetPng:'login_enter_dis'.assetPng
  150 + ),
  151 + fit: BoxFit.fill
  152 + ),
  153 + ),
  154 + padding: const EdgeInsets.symmetric(
  155 + horizontal: 28.0,
  156 + vertical: 14.0
  157 + ),
  158 + child:const Text(
  159 + '确定',
  160 + style: TextStyle(
  161 + fontSize: 16
  162 + ),
  163 + ),
  164 + ),
48 ) 165 )
49 ], 166 ],
50 ), 167 ),
lib/login/loginpage/bloc/login_bloc.dart
  1 +import 'dart:async';
  2 +
1 import 'package:flutter/cupertino.dart'; 3 import 'package:flutter/cupertino.dart';
  4 +import 'package:flutter/foundation.dart';
2 import 'package:flutter_bloc/flutter_bloc.dart'; 5 import 'package:flutter_bloc/flutter_bloc.dart';
3 6
4 part 'login_event.dart'; 7 part 'login_event.dart';
@@ -16,11 +19,15 @@ class LoginBloc extends Bloc&lt;LoginEvent, LoginState&gt; { @@ -16,11 +19,15 @@ class LoginBloc extends Bloc&lt;LoginEvent, LoginState&gt; {
16 bool _canLogin = false; 19 bool _canLogin = false;
17 ///是否可以发送验证码 20 ///是否可以发送验证码
18 bool _canSendSms = false; 21 bool _canSendSms = false;
  22 + ///正在发送验证码
  23 + bool _sendSmsIng = false;
19 ///是否阅读协议 24 ///是否阅读协议
20 bool _agreement = false; 25 bool _agreement = false;
21 ///登陆方式 26 ///登陆方式
22 LoginType _loginType = LoginType.sms; 27 LoginType _loginType = LoginType.sms;
23 28
  29 + int _countDown = 0;
  30 +
24 final TextEditingController phoneNumController = TextEditingController(); 31 final TextEditingController phoneNumController = TextEditingController();
25 final TextEditingController checkNumController = TextEditingController(); 32 final TextEditingController checkNumController = TextEditingController();
26 33
@@ -28,6 +35,8 @@ class LoginBloc extends Bloc&lt;LoginEvent, LoginState&gt; { @@ -28,6 +35,8 @@ class LoginBloc extends Bloc&lt;LoginEvent, LoginState&gt; {
28 bool get agreement => _agreement; 35 bool get agreement => _agreement;
29 LoginType get loginType => _loginType; 36 LoginType get loginType => _loginType;
30 bool get canSendSms => _canSendSms; 37 bool get canSendSms => _canSendSms;
  38 + int get countDown => _countDown;
  39 + bool get sendSmsIng => _sendSmsIng;
31 40
32 LoginBloc() : super(LoginInitial()) { 41 LoginBloc() : super(LoginInitial()) {
33 on<RequestLoginEvent>(_requestLoginApi); 42 on<RequestLoginEvent>(_requestLoginApi);
@@ -36,6 +45,8 @@ class LoginBloc extends Bloc&lt;LoginEvent, LoginState&gt; { @@ -36,6 +45,8 @@ class LoginBloc extends Bloc&lt;LoginEvent, LoginState&gt; {
36 on<AgreementChangeEvent>(_agreementTypeChange); 45 on<AgreementChangeEvent>(_agreementTypeChange);
37 on<ForgetPasswordEvent>(_forgetPassword); 46 on<ForgetPasswordEvent>(_forgetPassword);
38 on<CheckFieldChangeEvent>(_checkFiledChange); 47 on<CheckFieldChangeEvent>(_checkFiledChange);
  48 + on<CountDownEvent>(_countDownChange);
  49 + on<CancelCountDownEvent>(_cancelTimer);
39 } 50 }
40 51
41 52
@@ -100,6 +111,17 @@ class LoginBloc extends Bloc&lt;LoginEvent, LoginState&gt; { @@ -100,6 +111,17 @@ class LoginBloc extends Bloc&lt;LoginEvent, LoginState&gt; {
100 111
101 } 112 }
102 113
  114 + ///倒计时
  115 + void _countDownChange(CountDownEvent event, Emitter<LoginState> emitter) {
  116 + _sendSmsIng = !_sendSmsIng;
  117 + emitter(CountDownNumChangeState());
  118 + }
  119 +
  120 + void _cancelTimer(CancelCountDownEvent event,Emitter<LoginState> emitter) {
  121 +
  122 + }
  123 +
  124 + ///登陆状态判断
103 bool _loginStateChange() { 125 bool _loginStateChange() {
104 if (_agreement) { 126 if (_agreement) {
105 if (phoneNumController.text.isNotEmpty && checkNumController.text.isNotEmpty) { 127 if (phoneNumController.text.isNotEmpty && checkNumController.text.isNotEmpty) {
lib/login/loginpage/bloc/login_event.dart
@@ -14,3 +14,7 @@ class CheckFieldChangeEvent extends LoginEvent {} @@ -14,3 +14,7 @@ class CheckFieldChangeEvent extends LoginEvent {}
14 class AgreementChangeEvent extends LoginEvent {} 14 class AgreementChangeEvent extends LoginEvent {}
15 15
16 class ForgetPasswordEvent extends LoginEvent {} 16 class ForgetPasswordEvent extends LoginEvent {}
  17 +
  18 +class CountDownEvent extends LoginEvent {}
  19 +
  20 +class CancelCountDownEvent extends LoginEvent {}
lib/login/loginpage/bloc/login_state.dart
@@ -12,3 +12,5 @@ class LoginTypeChangeState extends LoginState {} @@ -12,3 +12,5 @@ class LoginTypeChangeState extends LoginState {}
12 class SmsSendTypeChangeState extends LoginState {} 12 class SmsSendTypeChangeState extends LoginState {}
13 13
14 class AgreementTypeChangeState extends LoginState {} 14 class AgreementTypeChangeState extends LoginState {}
  15 +
  16 +class CountDownNumChangeState extends LoginState {}
lib/login/loginpage/login_page.dart
1 -import 'package:common_utils/common_utils.dart'; 1 +import 'package:flutter/gestures.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
3 import 'package:flutter_bloc/flutter_bloc.dart'; 3 import 'package:flutter_bloc/flutter_bloc.dart';
4 import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 import 'package:flutter_screenutil/flutter_screenutil.dart';
5 -import 'package:fluttertoast/fluttertoast.dart';  
6 import 'package:wow_english/common/extension/string_extension.dart'; 5 import 'package:wow_english/common/extension/string_extension.dart';
7 import 'package:wow_english/common/widgets/textfield_customer_widget.dart'; 6 import 'package:wow_english/common/widgets/textfield_customer_widget.dart';
8 import 'package:wow_english/login/loginpage/bloc/login_bloc.dart'; 7 import 'package:wow_english/login/loginpage/bloc/login_bloc.dart';
9 import 'package:wow_english/route/route.dart'; 8 import 'package:wow_english/route/route.dart';
10 9
11 -  
12 class LoginPage extends StatelessWidget { 10 class LoginPage extends StatelessWidget {
13 const LoginPage({super.key}); 11 const LoginPage({super.key});
14 12
@@ -77,7 +75,54 @@ class LoginPage extends StatelessWidget { @@ -77,7 +75,54 @@ class LoginPage extends StatelessWidget {
77 color:bloc.agreement ? Colors.green:Colors.black), 75 color:bloc.agreement ? Colors.green:Colors.black),
78 ), 76 ),
79 6.horizontalSpace, 77 6.horizontalSpace,
80 - const Text('我已阅读并同意《用户隐私协议》,《儿童隐私策略》') 78 + RichText(
  79 + text: TextSpan(
  80 + children:[
  81 + const TextSpan(
  82 + text: '我已阅读并同意',
  83 + style: TextStyle(
  84 + fontSize: 12,
  85 + color: Color(0xFF333333),
  86 + )
  87 + ),
  88 + TextSpan(
  89 + text: '《用户隐私协议》',
  90 + style: const TextStyle(
  91 + fontSize: 12,
  92 + color: Color(0xFF333333),
  93 + ),
  94 + recognizer: TapGestureRecognizer()..onTap = (){
  95 + Navigator.of(context).pushNamed(
  96 + AppRouteName.webView,
  97 + arguments: {
  98 + 'urlStr':'https://www.zhihu.com',
  99 + 'webViewTitle':'用户隐私协议'
  100 + });
  101 + }),
  102 + const TextSpan(
  103 + text: ',',
  104 + style: TextStyle(
  105 + fontSize: 12,
  106 + color: Color(0xFF333333)
  107 + )
  108 + ),
  109 + TextSpan(
  110 + text: '《儿童隐私政策》',
  111 + style: const TextStyle(
  112 + fontSize: 12,
  113 + color: Color(0xFF333333)
  114 + ),
  115 + recognizer: TapGestureRecognizer()..onTap = (){
  116 + Navigator.of(context).pushNamed(
  117 + AppRouteName.webView,
  118 + arguments: {
  119 + 'urlStr':'https://www.zhihu.com',
  120 + 'webViewTitle':'儿童隐私协议'
  121 + });
  122 + })
  123 + ]
  124 + ),
  125 + )
81 ], 126 ],
82 ), 127 ),
83 GestureDetector( 128 GestureDetector(
@@ -142,21 +187,21 @@ class LoginPage extends StatelessWidget { @@ -142,21 +187,21 @@ class LoginPage extends StatelessWidget {
142 mainAxisAlignment: MainAxisAlignment.spaceBetween, 187 mainAxisAlignment: MainAxisAlignment.spaceBetween,
143 children: [ 188 children: [
144 Expanded( 189 Expanded(
145 - child: TextFieldCustomerWidget(  
146 - height: 50.h,  
147 - hitText: '请输入验证码',  
148 - textInputType: TextInputType.number,  
149 - bgImageName: 'Input_layer_down',  
150 - onChangeValue: (String value) {  
151 - bloc.add(CheckFieldChangeEvent());  
152 - },  
153 - controller: bloc.checkNumController,  
154 - ) 190 + child: TextFieldCustomerWidget(
  191 + height: 50.h,
  192 + hitText: '请输入验证码',
  193 + textInputType: TextInputType.number,
  194 + bgImageName: 'Input_layer_down',
  195 + onChangeValue: (String value) {
  196 + bloc.add(CheckFieldChangeEvent());
  197 + },
  198 + controller: bloc.checkNumController,
  199 + )
155 ), 200 ),
156 GestureDetector( 201 GestureDetector(
157 onTap: () { 202 onTap: () {
158 if (bloc.canSendSms) { 203 if (bloc.canSendSms) {
159 - bloc.add(ChangeLoginTypeEvent()); 204 + bloc.add(CountDownEvent());
160 } 205 }
161 }, 206 },
162 child: Container( 207 child: Container(
@@ -169,8 +214,8 @@ class LoginPage extends StatelessWidget { @@ -169,8 +214,8 @@ class LoginPage extends StatelessWidget {
169 ), 214 ),
170 ), 215 ),
171 padding: const EdgeInsets.symmetric(horizontal:12.0,vertical: 15.0), 216 padding: const EdgeInsets.symmetric(horizontal:12.0,vertical: 15.0),
172 - child: const Text(  
173 - '获取验证码' 217 + child: Text(
  218 + !bloc.sendSmsIng ? '获取验证码':'${bloc.countDown}s后在次获取'
174 ), 219 ),
175 ), 220 ),
176 ) 221 )
@@ -228,22 +273,18 @@ class LoginPage extends StatelessWidget { @@ -228,22 +273,18 @@ class LoginPage extends StatelessWidget {
228 ), 273 ),
229 10.5.horizontalSpace, 274 10.5.horizontalSpace,
230 Expanded( 275 Expanded(
231 - child: TextFieldCustomerWidget(  
232 - hitText: '请输入密码',  
233 - bgImageName: 'Input_layer_down',  
234 - onChangeValue: (String value) {  
235 - bloc.add(CheckFieldChangeEvent());  
236 - },  
237 - controller: bloc.checkNumController,  
238 - ) 276 + child: TextFieldCustomerWidget(
  277 + hitText: '请输入密码',
  278 + bgImageName: 'Input_layer_down',
  279 + onChangeValue: (String value) {
  280 + bloc.add(CheckFieldChangeEvent());
  281 + },
  282 + controller: bloc.checkNumController,
  283 + )
239 ), 284 ),
240 5.horizontalSpace, 285 5.horizontalSpace,
241 GestureDetector( 286 GestureDetector(
242 onTap: () { 287 onTap: () {
243 - if(!RegexUtil.isMobileExact(bloc.phoneNumController.text)) {  
244 - Fluttertoast.showToast(msg: '手机号不正确!');  
245 - return;  
246 - }  
247 Navigator.of(context).pushNamed(AppRouteName.fogPwd); 288 Navigator.of(context).pushNamed(AppRouteName.fogPwd);
248 }, 289 },
249 child: Container( 290 child: Container(
@@ -261,5 +302,338 @@ class LoginPage extends StatelessWidget { @@ -261,5 +302,338 @@ class LoginPage extends StatelessWidget {
261 ), 302 ),
262 ); 303 );
263 }); 304 });
264 -  
265 } 305 }
  306 +
  307 +// class LoginPage extends StatefulWidget {
  308 +// const LoginPage({super.key});
  309 +//
  310 +// @override
  311 +// State<StatefulWidget> createState() {
  312 +// return _LoginPageState();
  313 +// }
  314 +//
  315 +// }
  316 +//
  317 +// class _LoginPageState extends State<LoginPage> {
  318 +// late Timer _timer;
  319 +// int _countdownTime = 0;
  320 +//
  321 +// void startCountdownTimer(BuildContext context) {
  322 +// final bloc = BlocProvider.of<LoginBloc>(context);
  323 +// if (bloc.sendSmsIng) {
  324 +// return;
  325 +// }
  326 +// bloc.add(CancelCountDownEvent());
  327 +// const oneSec = Duration(seconds: 1);
  328 +// _countdownTime = 60;
  329 +// _timer = Timer.periodic(oneSec,(timer) {
  330 +// setState(() {
  331 +// if (_countdownTime < 1) {
  332 +// bloc.add(CancelCountDownEvent());
  333 +// _timer.cancel();
  334 +// } else {
  335 +// _countdownTime = _countdownTime - 1;
  336 +// }
  337 +// });
  338 +// if (kDebugMode) {
  339 +// print(_countdownTime);
  340 +// }
  341 +// });
  342 +// }
  343 +//
  344 +//
  345 +//
  346 +// @override
  347 +// Widget build(BuildContext context) {
  348 +// return BlocProvider(
  349 +// create: (context) => LoginBloc(),
  350 +// child: _buildLoginViewWidget(),
  351 +// );
  352 +// }
  353 +//
  354 +// Widget _buildLoginViewWidget() => BlocBuilder<LoginBloc,LoginState> (
  355 +// builder: (context, state) {
  356 +// final bloc = BlocProvider.of<LoginBloc>(context);
  357 +// return Scaffold(
  358 +// body: SafeArea(
  359 +// child: ListView(
  360 +// children: [
  361 +// Container(
  362 +// padding: EdgeInsets.only(top: 25.h),
  363 +// child: Stack(
  364 +// children: [
  365 +// Positioned(
  366 +// right: 29.w,
  367 +// child: GestureDetector(
  368 +// onTap: () => bloc.add(ChangeLoginTypeEvent()),
  369 +// child: Container(
  370 +// decoration: BoxDecoration(
  371 +// image: DecorationImage(
  372 +// image: AssetImage(
  373 +// 'login_logo'.assetPng
  374 +// ),
  375 +// fit: BoxFit.fill
  376 +// ),
  377 +// ),
  378 +// padding: const EdgeInsets.symmetric(horizontal: 18.0),
  379 +// child: Text(
  380 +// bloc.loginType == LoginType.sms?'密码登陆':'验证码密码'
  381 +// ),
  382 +// ),
  383 +// )
  384 +// ),
  385 +// Center(
  386 +// child: Column(
  387 +// children: [
  388 +// Image.asset(
  389 +// 'wow_logo'.assetPng,
  390 +// height: 81.h,
  391 +// width: 131.w,
  392 +// ),
  393 +// Offstage(
  394 +// offstage: bloc.loginType == LoginType.pwd,
  395 +// child: _buildSmsViewWidget(),
  396 +// ),
  397 +// Offstage(
  398 +// offstage: bloc.loginType == LoginType.sms,
  399 +// child: _buildPwdViewWidget(),
  400 +// ),
  401 +// Row(
  402 +// mainAxisAlignment: MainAxisAlignment.center,
  403 +// children: [
  404 +// GestureDetector(
  405 +// onTap: () => bloc.add(AgreementChangeEvent()),
  406 +// child: Icon(
  407 +// bloc.agreement ? Icons.check_circle_outlined:Icons.circle_outlined,
  408 +// color:bloc.agreement ? Colors.green:Colors.black),
  409 +// ),
  410 +// 6.horizontalSpace,
  411 +// RichText(
  412 +// text: TextSpan(
  413 +// children:[
  414 +// const TextSpan(
  415 +// text: '我已阅读并同意',
  416 +// style: TextStyle(
  417 +// fontSize: 12,
  418 +// color: Color(0xFF333333),
  419 +// )
  420 +// ),
  421 +// TextSpan(
  422 +// text: '《用户隐私协议》',
  423 +// style: const TextStyle(
  424 +// fontSize: 12,
  425 +// color: Color(0xFF333333),
  426 +// ),
  427 +// recognizer: TapGestureRecognizer()..onTap = (){
  428 +// Navigator.of(context).pushNamed(
  429 +// AppRouteName.webView,
  430 +// arguments: {
  431 +// 'urlStr':'https://www.zhihu.com',
  432 +// 'webViewTitle':'用户隐私协议'
  433 +// });
  434 +// }),
  435 +// const TextSpan(
  436 +// text: ',',
  437 +// style: TextStyle(
  438 +// fontSize: 12,
  439 +// color: Color(0xFF333333)
  440 +// )
  441 +// ),
  442 +// TextSpan(
  443 +// text: '《儿童隐私政策》',
  444 +// style: const TextStyle(
  445 +// fontSize: 12,
  446 +// color: Color(0xFF333333)
  447 +// ),
  448 +// recognizer: TapGestureRecognizer()..onTap = (){
  449 +// Navigator.of(context).pushNamed(
  450 +// AppRouteName.webView,
  451 +// arguments: {
  452 +// 'urlStr':'https://www.zhihu.com',
  453 +// 'webViewTitle':'儿童隐私协议'
  454 +// });
  455 +// })
  456 +// ]
  457 +// ),
  458 +// )
  459 +// ],
  460 +// ),
  461 +// GestureDetector(
  462 +// onTap: () {
  463 +// if (bloc.canLogin) {
  464 +// bloc.add(RequestLoginEvent());
  465 +// }
  466 +// },
  467 +// child: Container(
  468 +// decoration: BoxDecoration(
  469 +// image: DecorationImage(
  470 +// image: AssetImage(
  471 +// bloc.canLogin?'login_enter'.assetPng:'login_enter_dis'.assetPng
  472 +// ),
  473 +// fit: BoxFit.fill
  474 +// ),
  475 +// ),
  476 +// padding: const EdgeInsets.symmetric(
  477 +// horizontal: 28.0,
  478 +// vertical: 14.0
  479 +// ),
  480 +// child: const Text(
  481 +// '登录'
  482 +// ),
  483 +// ),
  484 +// )
  485 +// ],
  486 +// ),
  487 +// )
  488 +// ],
  489 +// ),
  490 +// )
  491 +// ],
  492 +// ),
  493 +// ),
  494 +// );
  495 +// },
  496 +// );
  497 +//
  498 +// Widget _buildSmsViewWidget()=> BlocBuilder<LoginBloc,LoginState>(
  499 +// builder: (context,state){
  500 +// final bloc = BlocProvider.of<LoginBloc>(context);
  501 +// return Padding(
  502 +// padding: EdgeInsets.symmetric(horizontal: 135.w),
  503 +// child: Column(
  504 +// children: [
  505 +// 15.verticalSpace,
  506 +// TextFieldCustomerWidget(
  507 +// height: 55.h,
  508 +// hitText: '请输入手机号',
  509 +// textInputType: TextInputType.phone,
  510 +// bgImageName: 'Input_layer_up',
  511 +// onChangeValue: (String value) {
  512 +// bloc.add(PhoneNumChangeEvent());
  513 +// },
  514 +// controller: bloc.phoneNumController,
  515 +// ),
  516 +// 6.5.verticalSpace,
  517 +// const Text('未注册用户登录默认注册'),
  518 +// 4.5.verticalSpace,
  519 +// Row(
  520 +// mainAxisAlignment: MainAxisAlignment.spaceBetween,
  521 +// children: [
  522 +// Expanded(
  523 +// child: TextFieldCustomerWidget(
  524 +// height: 50.h,
  525 +// hitText: '请输入验证码',
  526 +// textInputType: TextInputType.number,
  527 +// bgImageName: 'Input_layer_down',
  528 +// onChangeValue: (String value) {
  529 +// bloc.add(CheckFieldChangeEvent());
  530 +// },
  531 +// controller: bloc.checkNumController,
  532 +// )
  533 +// ),
  534 +// GestureDetector(
  535 +// onTap: () {
  536 +// if (bloc.canSendSms) {
  537 +//
  538 +// }
  539 +// },
  540 +// child: Container(
  541 +// decoration: BoxDecoration(
  542 +// image: DecorationImage(
  543 +// image: AssetImage(
  544 +// bloc.canSendSms?'securitycode'.assetPng:'securitycode_dis'.assetPng
  545 +// ),
  546 +// fit: BoxFit.fill
  547 +// ),
  548 +// ),
  549 +// padding: const EdgeInsets.symmetric(horizontal:12.0,vertical: 15.0),
  550 +// child: Text(
  551 +// !bloc.sendSmsIng ? '获取验证码':'${bloc.countDown}s后在次获取'
  552 +// ),
  553 +// ),
  554 +// )
  555 +// ],
  556 +// )
  557 +// ],
  558 +// ),
  559 +// );
  560 +// });
  561 +
  562 + // Widget _buildPwdViewWidget()=> BlocBuilder<LoginBloc,LoginState>(
  563 + // builder: (context,state){
  564 + // final bloc = BlocProvider.of<LoginBloc>(context);
  565 + // return Padding(
  566 + // padding: EdgeInsets.symmetric(horizontal: 90.w),
  567 + // child: Column(
  568 + // children: [
  569 + // 15.verticalSpace,
  570 + // Row(
  571 + // mainAxisAlignment: MainAxisAlignment.center,
  572 + // children: [
  573 + // Image.asset(
  574 + // 'phone'.assetPng,
  575 + // height: 45.h,
  576 + // width: 35.w,
  577 + // ),
  578 + // 10.5.horizontalSpace,
  579 + // Expanded(
  580 + // child: TextFieldCustomerWidget(
  581 + // height: 50.h,
  582 + // hitText: '请输入手机号',
  583 + // textInputType: TextInputType.phone,
  584 + // bgImageName: 'Input_layer_up',
  585 + // onChangeValue: (String value) {
  586 + // bloc.add(PhoneNumChangeEvent());
  587 + // },
  588 + // controller: bloc.phoneNumController,
  589 + // )
  590 + // ),
  591 + // 5.horizontalSpace,
  592 + // SizedBox(
  593 + // width: 100.w,
  594 + // height: 55.h,
  595 + // )
  596 + // ],
  597 + // ),
  598 + // 12.verticalSpace,
  599 + // Row(
  600 + // mainAxisAlignment: MainAxisAlignment.center,
  601 + // children: [
  602 + // Image.asset(
  603 + // 'lock'.assetPng,
  604 + // height: 34.h,
  605 + // width: 31.w,
  606 + // ),
  607 + // 10.5.horizontalSpace,
  608 + // Expanded(
  609 + // child: TextFieldCustomerWidget(
  610 + // hitText: '请输入密码',
  611 + // bgImageName: 'Input_layer_down',
  612 + // onChangeValue: (String value) {
  613 + // bloc.add(CheckFieldChangeEvent());
  614 + // },
  615 + // controller: bloc.checkNumController,
  616 + // )
  617 + // ),
  618 + // 5.horizontalSpace,
  619 + // GestureDetector(
  620 + // onTap: () {
  621 + // Navigator.of(context).pushNamed(AppRouteName.fogPwd);
  622 + // },
  623 + // child: Container(
  624 + // width: 100.w,
  625 + // height: 55.h,
  626 + // alignment: Alignment.centerLeft,
  627 + // child: const Text(
  628 + // '忘记密码 ?'
  629 + // ),
  630 + // ),
  631 + // )
  632 + // ],
  633 + // )
  634 + // ],
  635 + // ),
  636 + // );
  637 + // });
  638 +
  639 +
lib/pages/page1.dart
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 -import 'package:wow_english/widgets/we_app_bar.dart'; 2 +import 'package:wow_english/common/widgets/we_app_bar.dart';
3 3
4 class Page1 extends StatelessWidget { 4 class Page1 extends StatelessWidget {
5 const Page1({super.key}); 5 const Page1({super.key});
lib/pages/page2.dart
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 -import 'package:wow_english/widgets/we_app_bar.dart'; 2 +import 'package:wow_english/common/widgets/we_app_bar.dart';
3 3
4 class Page2 extends StatelessWidget { 4 class Page2 extends StatelessWidget {
5 const Page2({super.key}); 5 const Page2({super.key});
lib/route/route.dart
1 import 'package:flutter/cupertino.dart'; 1 import 'package:flutter/cupertino.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
3 import 'package:wow_english/app/splash_page.dart'; 3 import 'package:wow_english/app/splash_page.dart';
  4 +import 'package:wow_english/common/pages/wow_web_page.dart';
4 import 'package:wow_english/home/home_page.dart'; 5 import 'package:wow_english/home/home_page.dart';
5 import 'package:wow_english/login/forgetpwd/forget_password_home_page.dart'; 6 import 'package:wow_english/login/forgetpwd/forget_password_home_page.dart';
6 import 'package:wow_english/login/loginpage/login_page.dart'; 7 import 'package:wow_english/login/loginpage/login_page.dart';
@@ -14,6 +15,7 @@ class AppRouteName { @@ -14,6 +15,7 @@ class AppRouteName {
14 static const String home = 'home'; 15 static const String home = 'home';
15 static const String fogPwd = 'fogPwd'; 16 static const String fogPwd = 'fogPwd';
16 static const String setPwd = 'setPwd'; 17 static const String setPwd = 'setPwd';
  18 + static const String webView = 'webView';
17 static const String tab = '/'; 19 static const String tab = '/';
18 } 20 }
19 21
@@ -39,6 +41,10 @@ class AppRouter { @@ -39,6 +41,10 @@ class AppRouter {
39 case AppRouteName.setPwd: 41 case AppRouteName.setPwd:
40 final phoneNum = (settings.arguments as Map)['phoneNumber'] as String; 42 final phoneNum = (settings.arguments as Map)['phoneNumber'] as String;
41 return CupertinoPageRoute(builder: (_) => SetPassWordPage(phoneNum: phoneNum)); 43 return CupertinoPageRoute(builder: (_) => SetPassWordPage(phoneNum: phoneNum));
  44 + case AppRouteName.webView:
  45 + final urlStr = (settings.arguments as Map)['urlStr'] as String;
  46 + final webViewTitle = (settings.arguments as Map)['webViewTitle'] as String;
  47 + return CupertinoPageRoute(builder: (_) => WowWebViewPage(urlStr: urlStr,webViewTitle: webViewTitle,));
42 case AppRouteName.tab: 48 case AppRouteName.tab:
43 return PageRouteBuilder( 49 return PageRouteBuilder(
44 opaque: false, 50 opaque: false,
pubspec.yaml
@@ -46,7 +46,7 @@ dependencies: @@ -46,7 +46,7 @@ dependencies:
46 #Url跳转 https://pub.dev/packages/url_launcher 46 #Url跳转 https://pub.dev/packages/url_launcher
47 url_launcher: ^6.1.11 47 url_launcher: ^6.1.11
48 #网页加载 https://pub.dev/packages/webview_flutter 48 #网页加载 https://pub.dev/packages/webview_flutter
49 - webview_flutter: ^4.2.0 49 + webview_flutter: ^4.2.2
50 #下拉刷新 https://pub.dev/packages/pull_to_refresh 50 #下拉刷新 https://pub.dev/packages/pull_to_refresh
51 pull_to_refresh: ^2.0.0 51 pull_to_refresh: ^2.0.0
52 # 数据持久化 https://pub.dev/packages/shared_preferences 52 # 数据持久化 https://pub.dev/packages/shared_preferences
@@ -83,6 +83,8 @@ dependencies: @@ -83,6 +83,8 @@ dependencies:
83 connectivity_plus: ^4.0.1 83 connectivity_plus: ^4.0.1
84 # iOS设备方向控制 https://pub.dev/packages/limiting_direction_csx 84 # iOS设备方向控制 https://pub.dev/packages/limiting_direction_csx
85 limiting_direction_csx: ^0.2.0 85 limiting_direction_csx: ^0.2.0
  86 + # 富文本插件 https://pub.dev/packages/extended_text
  87 + extended_text: ^11.0.1
86 88
87 dev_dependencies: 89 dev_dependencies:
88 build_runner: ^2.4.4 90 build_runner: ^2.4.4