login_page.dart 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. import 'package:flutter/cupertino.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter/services.dart';
  4. import 'package:flutter/src/widgets/framework.dart';
  5. import 'package:flutter_screenutil/flutter_screenutil.dart';
  6. import 'package:keyboard/base/base_page.dart';
  7. import 'package:keyboard/module/login/login_controller.dart';
  8. import 'package:get/get.dart';
  9. import 'package:keyboard/router/app_pages.dart';
  10. import 'package:keyboard/utils/common_expand.dart';
  11. import '../../data/consts/web_url.dart';
  12. import '../../resource/assets.gen.dart';
  13. import '../../resource/colors.gen.dart';
  14. import '../../resource/string.gen.dart';
  15. import '../../utils/styles.dart';
  16. import '../../widget/click_text_span.dart';
  17. class LoginPage extends BasePage<LoginController> {
  18. const LoginPage({super.key});
  19. static start() {
  20. Get.toNamed(RoutePath.login);
  21. }
  22. @override
  23. Color backgroundColor() {
  24. return const Color(0xFFF6F5FA);
  25. }
  26. @override
  27. immersive() {
  28. return true;
  29. }
  30. @override
  31. Widget buildBody(BuildContext context) {
  32. return Stack(
  33. children: [
  34. Assets.images.bgLogin.image(fit: BoxFit.contain, width: 360.w),
  35. SafeArea(
  36. child: Column(
  37. children: [
  38. SizedBox(height: 225.w),
  39. buildPhoneTextFiled(),
  40. SizedBox(height: 16.w),
  41. buildCodeTextFiled(),
  42. SizedBox(height: 46.w),
  43. buildLoginButton(),
  44. SizedBox(height: 25.w),
  45. _buildPrivacy(),
  46. SizedBox(height: 100.w),
  47. buildOtherLogin(),
  48. ],
  49. ),
  50. ),
  51. ],
  52. );
  53. }
  54. Widget buildPhoneTextFiled() {
  55. return Container(
  56. height: 48.w,
  57. margin: EdgeInsets.symmetric(horizontal: 20.w),
  58. padding: EdgeInsets.symmetric(horizontal: 16.w),
  59. decoration: BoxDecoration(
  60. color: Colors.white,
  61. borderRadius: BorderRadius.circular(100.w),
  62. ),
  63. child: Row(
  64. children: [
  65. Expanded(
  66. child: TextField(
  67. cursorHeight: 20.w,
  68. style: TextStyle(
  69. fontSize: 14.sp,
  70. color: Colors.black.withAlpha( 204),
  71. fontWeight: FontWeight.w500,
  72. ),
  73. maxLines: 1,
  74. maxLength: 11,
  75. keyboardType: TextInputType.phone,
  76. inputFormatters: [FilteringTextInputFormatter.digitsOnly],
  77. textAlignVertical: TextAlignVertical.center,
  78. textInputAction: TextInputAction.next,
  79. decoration: InputDecoration(
  80. hintText: StringName.loginEtPhoneHint,
  81. counterText: '',
  82. hintStyle: TextStyle(
  83. fontSize: 14.sp,
  84. color: Colors.black.withAlpha(61),
  85. fontWeight: FontWeight.normal,
  86. ),
  87. labelStyle: TextStyle(
  88. fontSize: 14.sp,
  89. color: ColorName.primaryTextColor,
  90. ),
  91. contentPadding: const EdgeInsets.all(0),
  92. border: const OutlineInputBorder(borderSide: BorderSide.none),
  93. enabled: true,
  94. ),
  95. onChanged: controller.onPhoneChanged,
  96. ),
  97. ),
  98. ],
  99. ),
  100. );
  101. }
  102. Widget buildCodeTextFiled() {
  103. return Container(
  104. height: 48.w,
  105. margin: EdgeInsets.symmetric(horizontal: 20.w),
  106. padding: EdgeInsets.symmetric(horizontal: 16.w),
  107. decoration: BoxDecoration(
  108. color: Colors.white,
  109. borderRadius: BorderRadius.circular(100.w),
  110. ),
  111. child: Row(
  112. children: [
  113. Expanded(
  114. child: TextField(
  115. cursorHeight: 20.w,
  116. style: TextStyle(
  117. fontSize: 14.sp,
  118. color: Colors.black.withAlpha( 204),
  119. fontWeight: FontWeight.w500,
  120. ),
  121. maxLines: 1,
  122. maxLength: 4,
  123. keyboardType: TextInputType.phone,
  124. inputFormatters: [FilteringTextInputFormatter.digitsOnly],
  125. textAlignVertical: TextAlignVertical.center,
  126. textInputAction: TextInputAction.next,
  127. decoration: InputDecoration(
  128. hintText: StringName.loginPrintVerificationCode,
  129. counterText: '',
  130. hintStyle: TextStyle(
  131. fontSize: 14.sp,
  132. color: Colors.black.withAlpha(61),
  133. fontWeight: FontWeight.normal,
  134. ),
  135. labelStyle: TextStyle(
  136. fontSize: 14.sp,
  137. color: ColorName.primaryTextColor,
  138. ),
  139. contentPadding: const EdgeInsets.all(0),
  140. border: const OutlineInputBorder(borderSide: BorderSide.none),
  141. enabled: true,
  142. ),
  143. onChanged: controller.onCodeChanged,
  144. ),
  145. ),
  146. buildVerificationCodeSendBtn(),
  147. ],
  148. ),
  149. );
  150. }
  151. Widget buildVerificationCodeSendBtn() {
  152. return GestureDetector(
  153. onTap: controller.onSendVerificationCode,
  154. child: Container(
  155. margin: EdgeInsets.only(left: 12.w, right: 8.w),
  156. child: Obx(() {
  157. String txt = "";
  158. if (controller.countDown != null) {
  159. txt =
  160. '${controller.countDown}${StringName.loginRetransmissionCode}';
  161. } else {
  162. if (controller.isFirstSend) {
  163. txt = StringName.loginSendVerificationCode;
  164. } else {
  165. txt = StringName.loginResendCode;
  166. }
  167. }
  168. return Text(
  169. txt,
  170. style: TextStyle(
  171. fontSize: 14.sp,
  172. color: controller.isFirstSend
  173. ? Colors.black.withAlpha(204)
  174. : Color(0xCC7D46FC)
  175. ),
  176. );
  177. }),
  178. ),
  179. );
  180. }
  181. Widget buildLoginButton() {
  182. return GestureDetector(
  183. onTap: () {
  184. controller.onLoginClick();
  185. },
  186. child: Container(
  187. height: 48.w,
  188. margin: EdgeInsets.symmetric(horizontal: 24.w),
  189. child: Row(
  190. children: [
  191. Expanded(
  192. child: Obx(() {
  193. return Container(
  194. height: 48.w,
  195. decoration:
  196. controller.phone.length == 11 &&
  197. controller.code.isNotEmpty &&
  198. controller.isAgree
  199. ? Styles.getActivateButtonDecoration(50.r)
  200. : Styles.getInactiveButtonDecoration(50.r),
  201. child: Center(
  202. child: Text(
  203. StringName.login,
  204. style: TextStyle(color: Colors.white, fontSize: 16.sp),
  205. ),
  206. ),
  207. );
  208. }),
  209. ),
  210. ],
  211. ),
  212. ),
  213. );
  214. }
  215. Widget _buildPrivacy() {
  216. return Row(
  217. mainAxisAlignment: MainAxisAlignment.center,
  218. children: [
  219. Obx(() {
  220. return GestureDetector(
  221. behavior: HitTestBehavior.opaque,
  222. onTap: () {
  223. controller.clickAgree();
  224. },
  225. child: Padding(
  226. padding: EdgeInsets.symmetric(vertical: 20.w,horizontal: 20.w),
  227. child:
  228. controller.isAgree
  229. ? Assets.images.iconLoginAgreePrivacy.image(
  230. width: 14.w,
  231. height: 14.w,
  232. )
  233. : Container(
  234. width: 14.w,
  235. height: 14.w,
  236. child: Container(
  237. decoration: BoxDecoration(
  238. shape: BoxShape.circle,
  239. border: Border.all(
  240. color: Colors.black.withAlpha(153),
  241. width: 1.w,
  242. ),
  243. ),
  244. ),
  245. ),
  246. ),
  247. );
  248. }),
  249. Transform.translate(offset: Offset(-17.w,0),child: Text.rich(
  250. TextSpan(
  251. children: [
  252. TextSpan(
  253. text: StringName.textSpanIHaveReadAndAgree,
  254. style: TextStyle(
  255. color: Colors.black.withAlpha(128),
  256. fontSize: 12.sp,
  257. fontWeight: FontWeight.w400,
  258. ),
  259. ),
  260. ClickTextSpan(
  261. text: StringName.textSpanPrivacyPolicy,
  262. url: WebUrl.privacyPolicy,
  263. fontSize: 12.sp,
  264. color: Colors.black.withAlpha(204),
  265. ),
  266. TextSpan(
  267. text: StringName.textSpanAnd,
  268. style: TextStyle(
  269. color: Colors.black.withAlpha(128),
  270. fontSize: 12.sp,
  271. fontWeight: FontWeight.w400,
  272. ),
  273. ),
  274. ClickTextSpan(
  275. text: StringName.textSpanServiceTerms,
  276. url: WebUrl.serviceAgreement,
  277. color: Colors.black.withAlpha(204),
  278. fontSize: 12.sp,
  279. ),
  280. ],
  281. ),
  282. ),),
  283. ],
  284. );
  285. }
  286. Widget buildOtherLogin() {
  287. return Container(
  288. child: Column(
  289. children: [
  290. Text(
  291. StringName.loginOtherlogin,
  292. style: TextStyle(
  293. color: Colors.black.withValues(alpha: 0.5),
  294. fontSize: 12.sp,
  295. height: 0,
  296. ),
  297. ),
  298. SizedBox(height: 18.h),
  299. Material(
  300. color: Colors.white,
  301. shape: const CircleBorder(),
  302. child: InkWell(
  303. customBorder: const CircleBorder(), // 保证点击区域是圆的
  304. onTap: () {
  305. controller.clickWxLogin();
  306. },
  307. child: SizedBox(
  308. width: 44.w,
  309. height: 44.w,
  310. child: Center(
  311. child: Assets.images.iconWechatLogoBlack.image(
  312. width: 22.w,
  313. height: 22.w,
  314. ),
  315. ),
  316. ),
  317. ),
  318. ),
  319. SizedBox(height: 6.w),
  320. Text(
  321. StringName.wechat,
  322. textAlign: TextAlign.center,
  323. style: TextStyle(
  324. color: Colors.black.withValues(alpha: 0.5),
  325. fontSize: 12.sp,
  326. height: 0,
  327. ),
  328. ),
  329. ],
  330. ),
  331. );
  332. }
  333. }