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