login_page.dart 11 KB

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