login_page.dart 11 KB

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