login_controller.dart 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import 'dart:async';
  2. import 'dart:ui';
  3. import 'package:flutter/material.dart';
  4. import 'package:get/get.dart';
  5. import 'package:grpc/grpc.dart';
  6. import 'package:track_common/track_common.dart';
  7. import '../../utils.dart';
  8. abstract class LoginController extends GetxController {
  9. final phone = "".obs;
  10. final password = "".obs;
  11. final codeRetryLeft = 0.seconds.obs;
  12. Timer? ticker;
  13. var isSignInEnable = true;
  14. final isAgreeContract = false.obs;
  15. final isPageQrCode = false.obs;
  16. final qrCode = ''.obs;
  17. var qrCodeValue = '';
  18. late final Object? signOkCall;
  19. var codeErr = ''.obs;
  20. Future<Duration> getCodeLifeTime(String phone);
  21. Future<void> authSendCodeToPhone(String phone);
  22. Future<void> signIn(String phone, String code);
  23. /// (json, codeValue)
  24. Future<(String, String)> getQrCode();
  25. Future<bool> isQrCodeOk(String codeValue);
  26. @override
  27. void onInit() {
  28. signOkCall = Get.arguments;
  29. super.onInit();
  30. ticker = Timer.periodic(1.seconds, (timer) {
  31. codeRetryLeft.value -= 1.seconds;
  32. });
  33. workCheckQrCode();
  34. }
  35. void flushQrCode() async {
  36. if (codeErr.isNotEmpty) {
  37. codeErr.value = '';
  38. }
  39. final code = await getQrCode();
  40. debug('qr code: $code');
  41. qrCode.value = code.$1;
  42. qrCodeValue = code.$2;
  43. }
  44. void toQrcode() async {
  45. isPageQrCode.value = true;
  46. flushQrCode();
  47. }
  48. void workCheckQrCode() async {
  49. while (!isClosed) {
  50. await 1.seconds.delay();
  51. if (!isPageQrCode.value || qrCodeValue.isEmpty || codeErr.isNotEmpty) {
  52. continue;
  53. }
  54. try {
  55. if (await isQrCodeOk(qrCodeValue)) {
  56. onSignOk();
  57. return;
  58. }
  59. } on GrpcError catch (e) {
  60. codeErr.value = e.message ?? '未知错误';
  61. } catch (e) {
  62. warn('code err:', e);
  63. }
  64. }
  65. }
  66. void onGetCode() async {
  67. info("获取验证码");
  68. await tryApi(
  69. () async {
  70. codeRetryLeft.value = await getCodeLifeTime(phone.value);
  71. if (codeRetryLeft.value.inSeconds > 0) {
  72. return;
  73. }
  74. await authSendCodeToPhone(phone.value);
  75. codeRetryLeft.value = await getCodeLifeTime(phone.value);
  76. info("获取验证码结束");
  77. },
  78. errTitle: '获取验证码失败',
  79. onError: (e) async {
  80. if (e.code == StatusCode.notFound) {
  81. Get.snackbar('用户未注册', "请先注册",
  82. isDismissible: true, duration: 3.seconds);
  83. return true;
  84. }
  85. return false;
  86. });
  87. }
  88. void onSignOk() {
  89. final call = signOkCall;
  90. if (call is VoidCallback) {
  91. call();
  92. } else {
  93. Get.back(result: true, closeOverlays: true);
  94. }
  95. }
  96. Future<void> onSignIn() async {
  97. // if (!isAgreeContract.value) {
  98. // Get.snackbar('请先', '阅读并同意协议');
  99. // return;
  100. // }
  101. if (!isSignInEnable) {
  102. return;
  103. }
  104. try {
  105. isSignInEnable = false;
  106. if (phone.value.isEmpty) {
  107. Get.snackbar('手机号错误', "请重新输入");
  108. return;
  109. }
  110. if (password.value.isEmpty) {
  111. Get.snackbar('验证码错误', "请重新输入");
  112. return;
  113. }
  114. await tryApi(
  115. () async {
  116. info("登录 ${phone.value} ${password.value}");
  117. await signIn(phone.value, password.value);
  118. info("登录成功");
  119. onSignOk();
  120. },
  121. errTitle: '登录失败',
  122. onError: (e) async {
  123. switch (e.code) {
  124. case StatusCode.unauthenticated:
  125. Get.snackbar('登录失败', "验证码错误");
  126. return true;
  127. case StatusCode.notFound:
  128. Get.snackbar('用户未注册', "请先注册");
  129. return true;
  130. default:
  131. return false;
  132. }
  133. });
  134. } finally {
  135. isSignInEnable = true;
  136. }
  137. }
  138. @override
  139. void onClose() {
  140. ticker?.cancel();
  141. }
  142. }
  143. class LoginControllerMock extends LoginController {
  144. @override
  145. Future<void> authSendCodeToPhone(String phone) {
  146. // TODO: implement authSendCodeToPhone
  147. throw UnimplementedError();
  148. }
  149. @override
  150. Future<Duration> getCodeLifeTime(String phone) {
  151. // TODO: implement getCodeLifeTime
  152. throw UnimplementedError();
  153. }
  154. @override
  155. Future<void> signIn(String phone, String code) {
  156. // TODO: implement signIn
  157. throw UnimplementedError();
  158. }
  159. @override
  160. Future<(String, String)> getQrCode() {
  161. // TODO: implement getQrCode
  162. throw UnimplementedError();
  163. }
  164. @override
  165. Future<bool> isQrCodeOk(String codeValue) {
  166. // TODO: implement isQrCodeOk
  167. throw UnimplementedError();
  168. }
  169. }