login_page.dart 10 KB

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