change_pwd_page.dart 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  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. Expanded(
  133. child: SingleChildScrollView(
  134. child: Column(
  135. children: [
  136. buildList(),
  137. const SizedBox(height: 32),
  138. MyButton(
  139. '确认修改',
  140. onTap: onChange,
  141. gradient: const LinearGradient(colors: [Color(0xFF3BD2E5), Color(0xFF247AF8)]),
  142. alignment: Alignment.center,
  143. minHeight: 40,
  144. margin: const EdgeInsets.symmetric(horizontal: 24),
  145. ),
  146. ],
  147. ),
  148. ),
  149. ),
  150. ],
  151. );
  152. }
  153. Widget buildList() {
  154. var formatters = [FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9!\"#$%&()*+,-./:;<=>?@\]\[^_`{|}~]'))];
  155. return Container(
  156. margin: const EdgeInsets.symmetric(horizontal: 12),
  157. padding: const EdgeInsets.fromLTRB(16, 24, 16, 8),
  158. clipBehavior: Clip.hardEdge,
  159. decoration: const BoxDecoration(
  160. borderRadius: BorderRadius.all(Radius.circular(10)),
  161. color: Colors.white,
  162. ),
  163. child: Column(
  164. children: [
  165. oldError.builder(
  166. (error) => buildEdit(
  167. ctrl: oldPwdCtrl,
  168. labelText: '旧密码',
  169. hint: '请输入',
  170. formatters: formatters,
  171. inputType: TextInputType.visiblePassword,
  172. obscureText: true,
  173. errorText: error,
  174. onChanged: (value) => verifyOldText(),
  175. ),
  176. ),
  177. const SizedBox(height: 12),
  178. newError.builder(
  179. (error) => buildEdit(
  180. ctrl: newPwdCtrl,
  181. labelText: '新密码',
  182. hint: '密码长度8-20位,需包含英文、数字及字符',
  183. formatters: formatters,
  184. inputType: TextInputType.visiblePassword,
  185. obscureText: true,
  186. maxLength: 20,
  187. onChanged: (value) => verifyNewText(),
  188. errorText: error,
  189. ),
  190. ),
  191. const SizedBox(height: 12),
  192. confirmError.builder(
  193. (error) => buildEdit(
  194. ctrl: confirmPwdCtrl,
  195. labelText: '确认密码',
  196. hint: '密码长度8-20位,需包含英文、数字及字符',
  197. formatters: formatters,
  198. inputType: TextInputType.visiblePassword,
  199. obscureText: true,
  200. maxLength: 20,
  201. onChanged: (value) => verifyConfirmText(),
  202. errorText: error,
  203. ),
  204. ),
  205. ],
  206. ),
  207. );
  208. }
  209. Widget buildEdit({
  210. required TextEditingController ctrl,
  211. String? hint,
  212. String? labelText,
  213. TextInputAction action = TextInputAction.next,
  214. bool obscureText = false,
  215. ValueChanged? onSubmit,
  216. ValueChanged<String>? onChanged,
  217. List<TextInputFormatter>? formatters,
  218. int? maxLength,
  219. String? errorText,
  220. TextInputType? inputType,
  221. }) {
  222. return TextField(
  223. controller: ctrl,
  224. decoration: InputDecoration(
  225. prefixIconConstraints: const BoxConstraints(),
  226. border: const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(100))),
  227. enabledBorder: const OutlineInputBorder(
  228. borderSide: BorderSide(color: Color(0xFFE6E6E6), width: 1),
  229. borderRadius: BorderRadius.all(Radius.circular(100)),
  230. ),
  231. labelText: labelText,
  232. hintText: hint,
  233. hintStyle: const TextStyle(color: Color(0xFFBBBBBB)),
  234. isDense: true,
  235. contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
  236. errorText: errorText,
  237. ),
  238. maxLength: maxLength,
  239. style: const TextStyle(fontSize: 14),
  240. textInputAction: action,
  241. obscureText: obscureText,
  242. onSubmitted: onSubmit,
  243. onChanged: onChanged,
  244. inputFormatters: formatters,
  245. );
  246. }
  247. }