bindphone_dialog.dart 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. import 'dart:async';
  2. import 'dart:math';
  3. import 'package:flutter/cupertino.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:shared_preferences/shared_preferences.dart';
  6. import 'package:sport/pages/login/login_widget.dart';
  7. import 'package:sport/provider/login_info_model.dart';
  8. import 'package:sport/utils/toast.dart';
  9. import 'package:sport/widgets/button_cancel.dart';
  10. import 'package:sport/widgets/button_primary.dart';
  11. import 'package:sport/widgets/dialog/request_dialog.dart';
  12. import 'package:sport/widgets/misc.dart';
  13. class BindPhoneDialog extends StatefulWidget {
  14. @override
  15. State<StatefulWidget> createState() {
  16. return _BindPhoneDialog();
  17. }
  18. }
  19. class _BindPhoneDialog extends State<BindPhoneDialog> {
  20. String _phone = "";
  21. String _code = "";
  22. late FocusNode _codeFocus;
  23. Timer? _timer;
  24. ValueNotifier<int> _seconds = ValueNotifier(0);
  25. @override
  26. void initState() {
  27. super.initState();
  28. _codeFocus = FocusNode();
  29. }
  30. @override
  31. void dispose() {
  32. super.dispose();
  33. _codeFocus.dispose();
  34. _cancelTimer();
  35. }
  36. void _cancelTimer() {
  37. if (_timer != null) {
  38. _timer!.cancel();
  39. }
  40. _timer = null;
  41. }
  42. void _startTimer() {
  43. _cancelTimer();
  44. _seconds.value = 60;
  45. const period = const Duration(seconds: 1);
  46. _timer = Timer.periodic(period, (timer) {
  47. //更新界面
  48. _seconds.value = _seconds.value - 1;
  49. if (_seconds.value <= 0) {
  50. setState(() {
  51. _cancelTimer();
  52. });
  53. }
  54. });
  55. setState(() {});
  56. }
  57. @override
  58. Widget build(BuildContext context) {
  59. return Dialog(
  60. backgroundColor: Colors.transparent,
  61. elevation: 0,
  62. // shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
  63. child: Container(
  64. decoration: BoxDecoration(
  65. borderRadius: BorderRadius.all(Radius.circular(10.0)),
  66. color: Colors.white,
  67. ),
  68. child: Stack(
  69. children: <Widget>[
  70. SingleChildScrollView(
  71. child: Column(
  72. children: <Widget>[
  73. SizedBox(
  74. height: 30,
  75. ),
  76. Text(
  77. "绑定号码",
  78. style: Theme.of(context).textTheme.headline1!,
  79. strutStyle: fixedLine,
  80. ),
  81. Padding(
  82. padding: const EdgeInsets.all(16.0),
  83. child: Column(
  84. mainAxisSize: MainAxisSize.min,
  85. children: <Widget>[
  86. Input(
  87. width: double.infinity,
  88. labelText: "请输入手机号",
  89. height: 35,
  90. textInputType: TextInputType.phone,
  91. maxLength: 11,
  92. callBack: (value) {
  93. _phone = value;
  94. _phone = _phone.substring(0, min(11, _phone.length));
  95. },
  96. ),
  97. Row(
  98. children: <Widget>[
  99. Expanded(
  100. child: Input(
  101. height: 35,
  102. width: double.infinity,
  103. focusNode: _codeFocus,
  104. labelText: "请输入验证码",
  105. textInputType: TextInputType.number,
  106. maxLength: 4,
  107. callBack: (value) {
  108. _code = value;
  109. _code = _code.substring(0, min(4, _code.length));
  110. },
  111. ),
  112. ),
  113. SizedBox(
  114. width: 10,
  115. ),
  116. InkWell(
  117. onTap: () async {
  118. if (_phone.length < 11) {
  119. ToastUtil.show("请输入正确的手机码号码");
  120. return;
  121. }
  122. if (_seconds.value > 0) return;
  123. final _loginInfoModel = LoginInfoModel();
  124. var code = await request(context, () async {
  125. return await _loginInfoModel.getCaptcha(_phone).catchError((err) {});
  126. });
  127. if (code == true) {
  128. _startTimer();
  129. _codeFocus.requestFocus();
  130. }
  131. },
  132. child: Container(
  133. width: 95,
  134. child: Center(
  135. child: _seconds.value > 0
  136. ? ValueListenableBuilder(
  137. valueListenable: _seconds,
  138. builder: (BuildContext context, int value, Widget? child) => Text(
  139. "${value}s后重新获取",
  140. style: Theme.of(context).textTheme.subtitle1!.copyWith(color: Theme.of(context).accentColor),
  141. ),
  142. )
  143. : Text(
  144. "发送验证码",
  145. style: Theme.of(context).textTheme.subtitle1!.copyWith(color: Theme.of(context).accentColor),
  146. ),
  147. )))
  148. ],
  149. ),
  150. SizedBox(
  151. height: 6,
  152. ),
  153. Text(
  154. "根据相关条约与法律法规,您需要进行手机号码绑定才可进行相关操作",
  155. style: Theme.of(context).textTheme.bodyText1!.copyWith(color: Color(0xffc2c2c2)),
  156. strutStyle: StrutStyle(height: 1.4),
  157. ),
  158. SizedBox(
  159. height: 16,
  160. ),
  161. Row(
  162. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  163. children: <Widget>[
  164. Expanded(
  165. child: CancelButton(
  166. height: 35,
  167. callback: () {
  168. Navigator.of(context).pop(false);
  169. },
  170. content: "取消"),
  171. ),
  172. SizedBox(
  173. width: 16,
  174. ),
  175. Expanded(
  176. child: PrimaryButton(
  177. height: 35,
  178. callback: () async {
  179. final _loginInfoModel = LoginInfoModel();
  180. var result = await _loginInfoModel.loginApi.bindPhone(_phone, _code);
  181. if (result != null && result['code'] == 0) {
  182. _loginInfoModel.saveUserInfo({"phone": _phone});
  183. ToastUtil.show("绑定成功");
  184. Navigator.of(context).pop(true);
  185. }
  186. },
  187. content: "绑定"),
  188. )
  189. ],
  190. )
  191. ],
  192. ),
  193. )
  194. ],
  195. ),
  196. ),
  197. Positioned(
  198. right: 0,
  199. top: 0,
  200. child: IconButton(
  201. icon: Image.asset("lib/assets/img/btn_close_big.png"),
  202. onPressed: () => Navigator.pop(context, false),
  203. )),
  204. ],
  205. ),
  206. ),
  207. );
  208. }
  209. }
  210. Future<bool> showBindPhoneDialog(BuildContext context) async {
  211. SharedPreferences preferences = await SharedPreferences.getInstance();
  212. bool result = (preferences.get("phone") ?? "").toString().length > 0;
  213. if (!result) {
  214. result = await showDialog(context: context, builder: (context) => BindPhoneDialog());
  215. }
  216. return result;
  217. }