phone.dart 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. import 'package:dio/dio.dart';
  2. import 'package:fast/constants.dart';
  3. import 'package:fast/utils/api.dart';
  4. import 'package:fast/utils/http_utils.dart';
  5. import 'package:fast/utils/size_fit.dart';
  6. import 'package:fast/view/phone_code.dart';
  7. import 'package:fast/view/web.dart';
  8. import 'package:flutter/material.dart';
  9. import 'package:flutter/services.dart';
  10. import 'package:get/get.dart';
  11. import 'component/fast_btn.dart';
  12. import 'component/header.dart';
  13. import 'component/toast.dart';
  14. class Phone extends StatefulWidget {
  15. int type; //1 login 2 bind phone
  16. Phone({Key? key, required this.type}) : super(key: key);
  17. @override
  18. State<Phone> createState() => _PhoneState();
  19. }
  20. class _PhoneState extends State<Phone> {
  21. String code = '';
  22. bool showError = false;
  23. @override
  24. Widget build(BuildContext context) {
  25. SizeFit.initialize(context);
  26. return Material(
  27. child: Container(
  28. color: kBgColor,
  29. child: Column(children: [
  30. Stack(
  31. children: [
  32. Header(
  33. isIndexPage: false,
  34. ),
  35. Positioned(
  36. left: 16.px,
  37. top:54.px,
  38. child: GestureDetector(onTap: () => Navigator.pop(context),child: Container(
  39. width: 32.px,
  40. height: 32.px,
  41. alignment: Alignment.center,
  42. decoration: BoxDecoration(
  43. borderRadius: BorderRadius.all(Radius.circular(16.px)),
  44. color: const Color(0x33000000)
  45. ),
  46. child: Image.asset(
  47. 'assets/images/naviback.png',
  48. width: 20.px,
  49. height: 20.px,
  50. fit: BoxFit.cover,
  51. )
  52. ),))
  53. ],
  54. ),
  55. SizedBox(
  56. height: 50.px,
  57. ),
  58. Opacity(
  59. opacity: showError ? 1 : 0,
  60. child: Text(
  61. '手机号错误,请重新输入',
  62. style: TextStyle(color: kThemeColor, fontSize: 12.px),
  63. ),
  64. ),
  65. SizedBox(
  66. height: 10.px,
  67. ),
  68. Stack(
  69. children: [
  70. Container(
  71. width: 311.px,
  72. height: 48.px,
  73. alignment: Alignment.center,
  74. decoration: BoxDecoration(
  75. color: const Color(0x26C4CCDA),
  76. borderRadius: BorderRadius.all(Radius.circular(16.px))),
  77. child: Row(
  78. mainAxisAlignment: MainAxisAlignment.center,
  79. children: [
  80. SizedBox(
  81. width: 14.px,
  82. ),
  83. Text(
  84. '+86',
  85. style: TextStyle(
  86. color: const Color(0x66FFFFFF),
  87. fontWeight: FontWeight.bold,
  88. fontSize: 14.px),
  89. ),
  90. SizedBox(
  91. width: 8.px,
  92. ),
  93. Image.asset(
  94. 'assets/images/arrow.png',
  95. width: 16.px,
  96. height: 16.px,
  97. ),
  98. SizedBox(
  99. width: 16.px,
  100. ),
  101. Expanded(
  102. child: Container(
  103. alignment: Alignment.centerLeft,
  104. padding: EdgeInsets.only(bottom: 5.px),
  105. color: Colors.transparent,
  106. child: TextField(
  107. onChanged: (value) {
  108. setState(() {
  109. code = value;
  110. });
  111. },
  112. style: TextStyle(
  113. color: Colors.white,
  114. fontSize: 16.px,
  115. fontFamily: 'Exo2',
  116. fontWeight: FontWeight.w600),
  117. cursorColor: Colors.white,
  118. maxLength: 11,
  119. autofocus: false,
  120. textAlign: TextAlign.left,
  121. keyboardType: TextInputType.number,
  122. decoration: InputDecoration(
  123. counterText: "",
  124. hintText: "请输入您的手机号",
  125. border: InputBorder.none,
  126. contentPadding: EdgeInsets.zero,
  127. hintStyle: TextStyle(
  128. color: const Color(0x66FFFFFF),
  129. fontSize: 16.px,
  130. height: 1.0)),
  131. ),
  132. ))
  133. ],
  134. ),
  135. ),
  136. ],
  137. ),
  138. SizedBox(
  139. height: 28.px,
  140. ),
  141. FastBtn(
  142. title: '下一步',
  143. disable: code.length != 11,
  144. // color: const Color(0x80AAFF00),
  145. width: 311.px,
  146. height: 48.px,
  147. callback: () {
  148. next();
  149. }),
  150. SizedBox(
  151. height: 30.px,
  152. ),
  153. if (widget.type == 1)
  154. Row(
  155. mainAxisAlignment: MainAxisAlignment.center,
  156. children: [
  157. Text(
  158. '登录即表示同意',
  159. style: TextStyle(color: Colors.white, fontSize: 12.px),
  160. ),
  161. GestureDetector(
  162. onTap: () {
  163. Get.to(() => Web(
  164. title: '隐私政策',
  165. url: 'https://www.baidu.com',
  166. ));
  167. },
  168. child: Text(
  169. ' 用户协议',
  170. style: TextStyle(color: kThemeColor, fontSize: 12.px),
  171. ),
  172. ),
  173. Text(
  174. ' 和 ',
  175. style: TextStyle(color: Colors.white, fontSize: 12.px),
  176. ),
  177. GestureDetector(
  178. onTap: () {
  179. Get.to(() => Web(
  180. title: '隐私政策',
  181. url: 'https://www.baidu.com',
  182. ));
  183. },
  184. child: Text(
  185. '隐私条款',
  186. style: TextStyle(color: kThemeColor, fontSize: 12.px),
  187. ),
  188. )
  189. ],
  190. ),
  191. ])));
  192. }
  193. Future next() async {
  194. if (!isChinaPhoneLegal(code)) {
  195. setState(() {
  196. showError = true;
  197. });
  198. return;
  199. }
  200. setState(() {
  201. showError = false;
  202. });
  203. var data = await HttpUtils.post(Api.sendCode, data: {'mobile': code});
  204. Get.to(() => PhoneCode(
  205. phone: code,
  206. type: widget.type,
  207. ));
  208. }
  209. bool isChinaPhoneLegal(String str) {
  210. return RegExp(
  211. '^((13[0-9])|(15[^4])|(166)|(17[0-8])|(18[0-9])|(19[8-9])|(147,145))\\d{8}\$')
  212. .hasMatch(str);
  213. }
  214. Future invite() async {
  215. try {
  216. Map<String, dynamic> data =
  217. await HttpUtils.post(Api.inviteCode, data: {'mobile': code});
  218. showToast();
  219. Navigator.of(context).pop();
  220. } on DioError catch (e) {
  221. if (e.response?.data['error_code'] == 'INVITE_CODE_NOT_EXIST') {
  222. setState(() {
  223. showError = true;
  224. });
  225. }
  226. }
  227. }
  228. showToast() {
  229. showDialog(
  230. context: context,
  231. barrierDismissible: false,
  232. barrierColor: Colors.transparent,
  233. builder: (BuildContext context) {
  234. return Toast(
  235. title: '成功受邀',
  236. content: Row(
  237. mainAxisAlignment: MainAxisAlignment.center,
  238. children: [
  239. Text(
  240. '+3',
  241. style: TextStyle(
  242. color: Colors.white,
  243. fontSize: 16.px,
  244. fontWeight: FontWeight.w800,
  245. fontFamily: 'Exo2',
  246. decoration: TextDecoration.none),
  247. ),
  248. SizedBox(
  249. width: 3.px,
  250. ),
  251. Image.asset(
  252. 'assets/images/stone.png',
  253. width: 24.px,
  254. height: 24.px,
  255. )
  256. ],
  257. ),
  258. );
  259. });
  260. }
  261. Future jump() async {
  262. var data = await HttpUtils.post(Api.inviteCode, data: {'skip': true});
  263. Navigator.of(context).pop();
  264. }
  265. }