change_pwd_page.dart 7.3 KB

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