auth_login_page.dart 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. import 'package:cpt_auth/modules/auth_login/auth_login_state.dart';
  2. import 'package:cs_resources/generated/assets.dart';
  3. import 'package:cs_resources/generated/l10n.dart';
  4. import 'package:cs_resources/theme/app_colors_theme.dart';
  5. import 'package:flutter/gestures.dart';
  6. import 'package:flutter/material.dart';
  7. import 'package:auto_route/auto_route.dart';
  8. import 'package:hooks_riverpod/hooks_riverpod.dart';
  9. import 'package:plugin_basic/dialog/country_code_selecter.dart';
  10. import 'package:router/ext/auto_router_extensions.dart';
  11. import 'package:widgets/ext/ex_widget.dart';
  12. import 'package:widgets/my_appbar.dart';
  13. import 'package:widgets/my_button.dart';
  14. import 'package:widgets/my_load_image.dart';
  15. import 'package:widgets/my_text_field.dart';
  16. import 'package:widgets/my_text_view.dart';
  17. import 'package:widgets/shatter/custom_check_box.dart';
  18. import 'package:widgets/widget_export.dart';
  19. import '../../router/page/auth_page_router.dart';
  20. import 'auth_login_view_model.dart';
  21. /*
  22. * 用户的登录页面
  23. */
  24. @RoutePage()
  25. class AuthLoginPage extends HookConsumerWidget {
  26. const AuthLoginPage({Key? key}) : super(key: key);
  27. //启动当前页面
  28. static void startInstance({BuildContext? context}) {
  29. if (context != null) {
  30. context.router.navigate(const AuthLoginPageRoute());
  31. } else {
  32. appRouter.navigate(const AuthLoginPageRoute());
  33. }
  34. }
  35. //替换之前的页面
  36. static void startAndPopAll({BuildContext? context}) {
  37. if (context != null) {
  38. context.router.popUntilRoot();
  39. context.router.replace(const AuthLoginPageRoute());
  40. } else {
  41. appRouter.popUntilRoot();
  42. appRouter.replace(const AuthLoginPageRoute());
  43. }
  44. }
  45. @override
  46. Widget build(BuildContext context, WidgetRef ref) {
  47. final viewModel = ref.read(authLoginViewModelProvider.notifier);
  48. final state = ref.watch(authLoginViewModelProvider);
  49. return Scaffold(
  50. appBar: MyAppBar.appBar(context, "", showBackButton: false),
  51. backgroundColor: context.appColors.backgroundDefault,
  52. body: SingleChildScrollView(
  53. scrollDirection: Axis.vertical,
  54. physics: const BouncingScrollPhysics(),
  55. child: Container(
  56. margin: const EdgeInsets.symmetric(horizontal: 38),
  57. width: double.infinity,
  58. child: Column(
  59. mainAxisSize: MainAxisSize.max,
  60. crossAxisAlignment: CrossAxisAlignment.center,
  61. children: [
  62. //顶部Logo
  63. const MyAssetImage(
  64. Assets.assetsYyHomeSplash,
  65. width: 109.5,
  66. height: 48,
  67. ).marginOnly(top: 45, bottom: 45),
  68. // 登录表单 - 账号
  69. Row(
  70. mainAxisSize: MainAxisSize.max,
  71. crossAxisAlignment: CrossAxisAlignment.center,
  72. children: [
  73. //封装的国家选择控件
  74. CountryCodeSelector(
  75. onChanged: (countryCode) {
  76. viewModel.saveCountryCode(countryCode);
  77. },
  78. ).marginOnly(left: 15),
  79. //电话输入框
  80. _buildInputLayout(
  81. context,
  82. state,
  83. "account",
  84. fillBGColor: Colors.transparent,
  85. textInputType: TextInputType.number,
  86. textInputAction: TextInputAction.done,
  87. errorText: state.accountErrorText,
  88. onSubmit: (formKey, value) {
  89. state.formData[formKey]!['focusNode'].unfocus();
  90. FocusScope.of(context).requestFocus(state.formData['password']!['focusNode']);
  91. },
  92. ).expanded(),
  93. ],
  94. ).decorated(
  95. color: context.appColors.authFiledBG,
  96. borderRadius: BorderRadius.circular(5.0),
  97. ),
  98. // 登录表单 - 密码
  99. _buildInputLayout(
  100. context,
  101. state,
  102. "password",
  103. marginTop: 15,
  104. obscureText: !state.pwdVisibility,
  105. errorText: state.passwordErrorText,
  106. showRightIcon: true,
  107. rightWidget: IconButton(
  108. highlightColor: Colors.transparent,
  109. splashColor: Colors.transparent,
  110. icon: !state.pwdVisibility
  111. ? const MyAssetImage(
  112. Assets.authPasswordHide,
  113. width: 22.5,
  114. height: 16.5,
  115. )
  116. : const MyAssetImage(
  117. Assets.authPasswordShow,
  118. width: 22.5,
  119. height: 16.5,
  120. ),
  121. onPressed: () {
  122. viewModel.switchPwdVisibility();
  123. },
  124. ),
  125. onSubmit: (formKey, value) {
  126. state.formData[formKey]!['focusNode'].unfocus();
  127. viewModel.doLogin();
  128. },
  129. ),
  130. //登录按钮
  131. MyButton(
  132. onPressed: viewModel.doLogin,
  133. text: S.current.login,
  134. enable: state.isLoginBtnEnable,
  135. textColor: Colors.white,
  136. disabledTextColor: Colors.white,
  137. backgroundColor: context.appColors.btnBgDefault,
  138. disabledBackgroundColor: context.appColors.btnBgDefault.withOpacity(0.2),
  139. fontWeight: FontWeight.w500,
  140. type: ClickType.throttle,
  141. minHeight: 50,
  142. radius: 5,
  143. ).marginOnly(top: 20, bottom: 23),
  144. //忘记密码
  145. MyTextView(
  146. S.current.forgot_password,
  147. isFontMedium: true,
  148. fontSize: 16,
  149. textColor: context.appColors.textPrimary,
  150. onClick: viewModel.gotoForgotPage,
  151. ),
  152. //创建账户-注册
  153. MyButton(
  154. onPressed: viewModel.gotoSignUpPage,
  155. text: S.current.create_new_yy_home_account,
  156. textColor: Colors.white,
  157. backgroundColor: context.appColors.btnBgDefault,
  158. fontWeight: FontWeight.w500,
  159. type: ClickType.throttle,
  160. minHeight: 50,
  161. radius: 5,
  162. ).marginOnly(top: 28),
  163. //同意协议
  164. Row(
  165. mainAxisSize: MainAxisSize.min,
  166. children: [
  167. MyAssetImage(
  168. state.isAgreeTerms ? Assets.baseServiceCheckBoxChecked : Assets.baseServiceCheckBoxUncheck,
  169. color: state.isAgreeTerms ? context.appColors.textPrimary : Colors.transparent,
  170. width: 15.5,
  171. height: 15.5,
  172. ).onTap(viewModel.switchAgreeTerms, padding: 10),
  173. RichText(
  174. text: TextSpan(
  175. children: [
  176. TextSpan(
  177. text: S.current.agree_to,
  178. style: TextStyle(color: context.appColors.textDarkGray, fontWeight: FontWeight.w500, fontSize: 15), // 灰色文本
  179. ),
  180. const TextSpan(
  181. text: " ",
  182. ),
  183. TextSpan(
  184. text: S.current.terms_of_service,
  185. style: TextStyle(color: context.appColors.textPrimary, fontWeight: FontWeight.w500, fontSize: 15), // 蓝色文本
  186. recognizer: TapGestureRecognizer()..onTap = viewModel.gotoTermsPage,
  187. ),
  188. ],
  189. ),
  190. ),
  191. ],
  192. ).marginOnly(top: 30, bottom: 30),
  193. //结束
  194. ],
  195. ),
  196. ),
  197. ),
  198. );
  199. }
  200. /// 输入框 账号与密码
  201. Widget _buildInputLayout(
  202. BuildContext context,
  203. LoginState state,
  204. String key, {
  205. double marginTop = 0,
  206. bool? showRightIcon = false, //是否展示右侧的布局
  207. Widget? rightWidget, //右侧的布局
  208. TextInputType textInputType = TextInputType.text,
  209. String? errorText,
  210. Color? fillBGColor,
  211. bool obscureText = false,
  212. TextInputAction textInputAction = TextInputAction.done,
  213. Function? onSubmit,
  214. }) {
  215. return IgnoreKeyboardDismiss(
  216. child: MyTextField(
  217. key,
  218. fillBackgroundColor: fillBGColor ?? context.appColors.authFiledBG,
  219. state.formData[key]!['value'],
  220. hintText: state.formData[key]!['hintText'],
  221. hintStyle: TextStyle(
  222. color: context.appColors.authFiledHint,
  223. fontSize: 16.0,
  224. fontWeight: FontWeight.w500,
  225. ),
  226. controller: state.formData[key]!['controller'],
  227. focusNode: state.formData[key]!['focusNode'],
  228. margin: EdgeInsets.only(top: marginTop),
  229. padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 3),
  230. showDivider: false,
  231. height: 44,
  232. style: TextStyle(
  233. color: context.appColors.authFiledText,
  234. fontSize: 16.0,
  235. fontWeight: FontWeight.w500,
  236. ),
  237. inputType: textInputType,
  238. textInputAction: textInputAction,
  239. onSubmit: onSubmit,
  240. cursorColor: context.appColors.authFiledText,
  241. obscureText: obscureText,
  242. errorText: errorText,
  243. showLeftIcon: true,
  244. showRightIcon: showRightIcon,
  245. rightWidget: rightWidget,
  246. ),
  247. );
  248. }
  249. }