change_pwd_page.dart 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. import 'dart:async';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter/services.dart';
  4. import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
  5. import 'package:lszlgl/base/base_state.dart';
  6. import 'package:lszlgl/main.dart';
  7. import 'package:lszlgl/network/my_api.dart';
  8. import 'package:lszlgl/widget/button.dart';
  9. import 'package:lszlgl/widget/password_textfield.dart';
  10. /// 修改密码
  11. class ChangePwdPage extends StatefulWidget {
  12. final bool startHome;
  13. const ChangePwdPage({
  14. Key? key,
  15. bool? startHome,
  16. }) : startHome = startHome ?? false,
  17. super(key: key);
  18. @override
  19. State<ChangePwdPage> createState() => _ChangePwdPageState();
  20. }
  21. class _ChangePwdPageState extends BaseState<ChangePwdPage> {
  22. late TextEditingController oldPwdCtrl;
  23. late TextEditingController newPwdCtrl;
  24. late TextEditingController confirmPwdCtrl;
  25. final ValueNotifier<String?> oldError = null.notifier();
  26. final ValueNotifier<String?> newError = null.notifier();
  27. final ValueNotifier<String?> confirmError = null.notifier();
  28. void onChange() async {
  29. List<bool> verifyList = await Future.wait([verifyOldText(), verifyNewText(), verifyConfirmText()]);
  30. if (!verifyList.firstWhere((element) => !element, orElse: () => true)) {
  31. return;
  32. }
  33. MyNavigator.showLoading(msg: '密码修改中...');
  34. try {
  35. var rsp = await MyApi.get().updatePassword({
  36. 'oldPassword': oldPwdCtrl.text,
  37. 'newPassword': newPwdCtrl.text,
  38. });
  39. if (rsp.data ?? false) {
  40. MyNavigator.showToast('修改成功');
  41. if (widget.startHome) {
  42. // 进入主页
  43. MyRouter.startMain(popAll: true);
  44. } else {
  45. MyNavigator.pop();
  46. }
  47. }
  48. } catch (e) {
  49. logger.e(e);
  50. }
  51. MyNavigator.dismissLoading();
  52. }
  53. Future<bool> verifyOldText() async {
  54. var text = oldPwdCtrl.text;
  55. if (text.isEmpty) {
  56. oldError.value = '请输入旧密码';
  57. return false;
  58. }
  59. int length = text.length;
  60. if (length < 8) {
  61. oldError.value = '密码长度要大于8位';
  62. return false;
  63. }
  64. oldError.value = null;
  65. return true;
  66. }
  67. Future<bool> verifyNewText() async {
  68. var text = newPwdCtrl.text;
  69. if (text.isEmpty) {
  70. newError.value = '请输入新密码';
  71. return false;
  72. }
  73. int length = text.length;
  74. if (length < 8) {
  75. newError.value = '密码长度要大于8位';
  76. return false;
  77. }
  78. var regex = RegExp(r'\d');
  79. if (!regex.hasMatch(text)) {
  80. newError.value = '密码要包含数字';
  81. return false;
  82. }
  83. regex = RegExp(r'[a-zA-Z]');
  84. if (!regex.hasMatch(text)) {
  85. newError.value = '密码要包含大写字母或小写字母';
  86. return false;
  87. }
  88. regex = RegExp(r'[!\"#$%&()*+,-./:;<=>?@\]\[^_`{|}~]');
  89. if (!regex.hasMatch(text)) {
  90. newError.value = '密码要包含特殊字符';
  91. return false;
  92. }
  93. newError.value = null;
  94. return true;
  95. }
  96. Future<bool> verifyConfirmText() async {
  97. var text = confirmPwdCtrl.text;
  98. if (text.isEmpty) {
  99. confirmError.value = '请输入确认密码';
  100. return false;
  101. }
  102. if (text != newPwdCtrl.text) {
  103. confirmError.value = '两次输入密码不一致';
  104. return false;
  105. }
  106. confirmError.value = null;
  107. return true;
  108. }
  109. @override
  110. void initState() {
  111. super.initState();
  112. oldPwdCtrl = TextEditingController();
  113. newPwdCtrl = TextEditingController();
  114. confirmPwdCtrl = TextEditingController();
  115. }
  116. @override
  117. void dispose() {
  118. super.dispose();
  119. }
  120. @override
  121. Widget build(BuildContext context) {
  122. return myScaffold(
  123. child: KeyboardDismissOnTap(
  124. dismissOnCapturedTaps: true,
  125. child: buildBody(),
  126. ),
  127. );
  128. }
  129. Widget buildBody() {
  130. return Column(
  131. children: [
  132. myAppBar(title: '修改密码'),
  133. Expanded(
  134. child: SingleChildScrollView(
  135. child: Column(
  136. children: [
  137. buildList(),
  138. const SizedBox(height: 32),
  139. const Text('密码长度8-20位,需包含英文、数字及字符',style: TextStyle(color: Colors.grey),),
  140. const SizedBox(height: 12),
  141. MyButton(
  142. '保 存',
  143. onTap: onChange,
  144. gradient: const LinearGradient(colors: [Color(0xFF3BD2E5), Color(0xFF247AF8)]),
  145. radius: 10,
  146. fountSize: 18,
  147. fontWeight: FontWeight.w600,
  148. margin: const EdgeInsets.symmetric(horizontal: 12),
  149. ),
  150. ],
  151. ),
  152. ),
  153. ),
  154. ],
  155. );
  156. }
  157. Widget buildList() {
  158. var formatters = [FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9!\"#$%&()*+,-./:;<=>?@\]\[^_`{|}~]'))];
  159. return Container(
  160. margin: const EdgeInsets.symmetric(horizontal: 12),
  161. padding: const EdgeInsets.fromLTRB(16, 12, 16, 12),
  162. clipBehavior: Clip.hardEdge,
  163. decoration: const BoxDecoration(
  164. borderRadius: BorderRadius.all(Radius.circular(10)),
  165. color: Colors.white,
  166. ),
  167. child: Column(
  168. children: [
  169. oldError.builder(
  170. (error) => buildEdit(
  171. titleName: '旧密码',
  172. ctrl: oldPwdCtrl,
  173. hint: '请填写旧密码',
  174. formatters: formatters,
  175. inputType: TextInputType.visiblePassword,
  176. obscureText: true,
  177. errorText: error,
  178. onChanged: (value) => verifyOldText(),
  179. ),
  180. ),
  181. const SizedBox(height: 12),
  182. newError.builder(
  183. (error) => buildEdit(
  184. titleName: '新密码',
  185. ctrl: newPwdCtrl,
  186. hint: '请输入新的密码',
  187. formatters: formatters,
  188. inputType: TextInputType.visiblePassword,
  189. obscureText: true,
  190. onChanged: (value) => verifyNewText(),
  191. errorText: error,
  192. ),
  193. ),
  194. const SizedBox(height: 12),
  195. confirmError.builder(
  196. (error) => buildEdit(
  197. titleName: '新密码',
  198. ctrl: confirmPwdCtrl,
  199. hint: '请再次输入新的密码',
  200. formatters: formatters,
  201. inputType: TextInputType.visiblePassword,
  202. obscureText: true,
  203. onChanged: (value) => verifyConfirmText(),
  204. errorText: error,
  205. ),
  206. ),
  207. ],
  208. ),
  209. );
  210. }
  211. Widget buildEdit({
  212. required TextEditingController ctrl,
  213. required String titleName,
  214. String? hint,
  215. TextInputAction action = TextInputAction.next,
  216. bool obscureText = false,
  217. ValueChanged? onSubmit,
  218. ValueChanged<String>? onChanged,
  219. List<TextInputFormatter>? formatters,
  220. int? maxLength,
  221. String? errorText,
  222. TextInputType? inputType,
  223. }) {
  224. return PasswordTextField(
  225. controller: ctrl,
  226. textAlign: TextAlign.end,
  227. decoration: InputDecoration(
  228. prefixIcon: Padding(
  229. padding: const EdgeInsets.symmetric(horizontal: 8.0),
  230. child: Text(titleName),
  231. ),
  232. prefixIconConstraints: const BoxConstraints(),
  233. border: const UnderlineInputBorder(
  234. borderSide: BorderSide(width: 1,color: Color(0xffF6F6F8))
  235. ),
  236. enabledBorder: const UnderlineInputBorder(
  237. borderSide: BorderSide(width: 1,color: Color(0xffF6F6F8))
  238. ),
  239. focusedBorder: const UnderlineInputBorder(
  240. borderSide: BorderSide(width: 1,color: Color(0xffF6F6F8))
  241. ),
  242. hintText: hint,
  243. hintStyle: const TextStyle(color: Color(0xFFBBBBBB)),
  244. isDense: true,
  245. contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
  246. errorText: errorText,
  247. ),
  248. maxLength: maxLength,
  249. style: const TextStyle(fontSize: 14),
  250. textInputAction: action,
  251. initialObscurity: obscureText,
  252. onSubmitted: onSubmit,
  253. onChanged: onChanged,
  254. inputFormatters: formatters,
  255. );
  256. }
  257. }