Commit bfb40cd0bdeb57879c4cc8471a8d303b36b43e7f
1 parent
1d5315dd
feat:忘记密码获取验证码
Showing
15 changed files
with
712 additions
and
41 deletions
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 'forget_pwd_home_bloc.dart'; | @@ -2,3 +2,11 @@ part of 'forget_pwd_home_bloc.dart'; | ||
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 'forget_pwd_home_bloc.dart'; | @@ -4,3 +4,7 @@ part of 'forget_pwd_home_bloc.dart'; | ||
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 'package:flutter/material.dart'; | @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; | ||
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<LoginEvent, LoginState> { | @@ -16,11 +19,15 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> { | ||
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<LoginEvent, LoginState> { | @@ -28,6 +35,8 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> { | ||
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<LoginEvent, LoginState> { | @@ -36,6 +45,8 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> { | ||
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<LoginEvent, LoginState> { | @@ -100,6 +111,17 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> { | ||
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 |