login_phone_cubit.dart 5.25 KB
import 'dart:async';

import 'package:appframe/config/locator.dart';
import 'package:appframe/config/routes.dart';
import 'package:appframe/data/repositories/phone_auth_repository.dart';
import 'package:appframe/utils/login_util.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:shared_preferences/shared_preferences.dart';

class LoginPhoneState extends Equatable {
  final bool agreed;
  final bool showAgreed;

  final bool allowSend;
  final int seconds;

  const LoginPhoneState({
    this.agreed = false,
    this.showAgreed = false,
    this.allowSend = true,
    this.seconds = 0,
  });

  LoginPhoneState copyWith({
    bool? agreed,
    bool? showAgreed,
    bool? allowSend,
    int? seconds,
  }) {
    return LoginPhoneState(
      agreed: agreed ?? this.agreed,
      showAgreed: showAgreed ?? this.showAgreed,
      allowSend: allowSend ?? this.allowSend,
      seconds: seconds ?? this.seconds,
    );
  }

  @override
  List<Object?> get props => [
        agreed,
        showAgreed,
        allowSend,
        seconds,
      ];
}

class LoginPhoneCubit extends Cubit<LoginPhoneState> {
  late TextEditingController _phoneController;
  late TextEditingController _codeController;
  Timer? _timer;
  int countdown = 60; // 倒计时秒数

  late final PhoneAuthRepository _phoneAuthRepository;

  TextEditingController get phoneController => _phoneController;

  TextEditingController get codeController => _codeController;

  LoginPhoneCubit(super.initialState) {
    _phoneController = TextEditingController();
    _codeController = TextEditingController();

    _phoneController.text = '';
    _codeController.text = '';

    _phoneAuthRepository = getIt.get<PhoneAuthRepository>();
  }

  /// 开始倒计时
  void startCountdown() {
    countdown = 60;
    emit(state.copyWith(allowSend: false, seconds: countdown));

    _timer = Timer.periodic(Duration(seconds: 1), (timer) {
      countdown--;
      if (countdown <= 0) {
        _timer?.cancel();
        emit(state.copyWith(allowSend: true, seconds: 60));
      } else {
        emit(state.copyWith(seconds: countdown));
      }
    });
  }

  /// 发送验证码
  Future<void> sendVerificationCode() async {
    if (state.allowSend) {
      // 验证手机号码
      String phone = _phoneController.text;
      if (!RegExp(r'^1[3-9][0-9]{9}$').hasMatch(phone)) {
        Fluttertoast.showToast(msg: '请输入正确的手机号码', gravity: ToastGravity.TOP, backgroundColor: Colors.red);

        return;
      }

      // 发送验证码
      var result = await _phoneAuthRepository.verifyCode(phone, 1);
      if (result == null) {
        Fluttertoast.showToast(msg: '发送请求失败', gravity: ToastGravity.TOP, backgroundColor: Colors.red);
        return;
      }
      if (result['code'] != 0) {
        Fluttertoast.showToast(msg: result['error'], gravity: ToastGravity.TOP, backgroundColor: Colors.red);
        return;
      }

      emit(state.copyWith(allowSend: false, seconds: 60));

      // 开始倒计时
      startCountdown();
    }
  }

  Future<void> phoneAuth() async {
    String phone = _phoneController.text;
    String verifyCode = _codeController.text;

    if (!RegExp(r'^1[3-9][0-9]{9}$').hasMatch(phone)) {
      Fluttertoast.showToast(msg: '请输入正确的手机号码', gravity: ToastGravity.TOP, backgroundColor: Colors.red);
      return;
    }

    if (!RegExp(r'^\d{4}$').hasMatch(verifyCode)) {
      Fluttertoast.showToast(msg: '请输入正确的验证码', gravity: ToastGravity.TOP, backgroundColor: Colors.red);
      return;
    }

    if (!state.agreed) {
      emit(state.copyWith(showAgreed: true));
      return;
    }

    var resultData = await _phoneAuthRepository.login(phone, verifyCode);
    if (resultData == null) {
      Fluttertoast.showToast(msg: '登录请求失败', gravity: ToastGravity.TOP, backgroundColor: Colors.red);
      return;
    }
    if (resultData['code'] != 0) {
      Fluttertoast.showToast(msg: resultData['error'], gravity: ToastGravity.TOP, backgroundColor: Colors.red);
      return;
    }

    var data = resultData['data'] as Map<String, dynamic>;
    int binding = resultData['binding'];
    // binding=1 代表已绑定,不是游客
    var visitor = binding == 1 ? 0 : 1;
    if (visitor == 1) {
      var sharedPreferences = getIt.get<SharedPreferences>();
      sharedPreferences.setString('auth_visitor_type', 'phone');
      sharedPreferences.setString('auth_visitor_id', phone);
    }
    LoginUtil.handleLoginSuccess(data, visitor, 'router');
  }

  void toggleAgreed(bool value) {
    emit(state.copyWith(agreed: value));
  }

  void confirmAgreed() {
    emit(state.copyWith(agreed: true, showAgreed: false));
    phoneAuth();
  }

  void cancelAgreed() {
    emit(state.copyWith(showAgreed: false));
  }

  void goLoginMain() {
    router.go('/loginMain');
  }

  void goLoginQr() {
    router.go('/loginQr');
  }

  @override
  Future<void> close() async {
    try {
      _phoneController.dispose();
    } catch (e) {
      debugPrint('Error disposing controller: $e');
    }

    try {
      _codeController.dispose();
    } catch (e) {
      debugPrint('Error disposing controller: $e');
    }

    await super.close();
  }
}