hi-client/lib/app/modules/kr_login/controllers/kr_login_controller.dart

637 lines
18 KiB
Dart
Executable File

import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:get/get.dart';
import 'package:kaer_with_panels/app/services/api_service/kr_auth_api.dart';
import 'package:kaer_with_panels/app/common/app_run_data.dart';
import 'package:kaer_with_panels/app/model/enum/kr_request_type.dart';
import 'package:kaer_with_panels/app/model/kr_area_code.dart';
import 'package:kaer_with_panels/app/utils/kr_common_util.dart';
import 'package:kaer_with_panels/app/localization/app_translations.dart';
import 'package:kaer_with_panels/app/utils/kr_event_bus.dart';
import 'package:kaer_with_panels/app/services/kr_site_config_service.dart';
import '../../../localization/kr_language_utils.dart';
/// 登录类型
enum KRLoginProgressStatus {
/// 检查是否注册
kr_check,
/// 验证码登陆
kr_loginByCode,
/// 密码登陆
kr_loginByPsd,
/// 注册发送验证码
kr_registerSendCode,
/// 这次设置密码
kr_registerSetPsd,
/// 忘记密码发送验证码
kr_forgetPsdSendCode,
/// 忘记密码设置密码
kr_forgetPsdSetPsd,
}
extension KRLoginTypeExt on KRLoginProgressStatus {
int get value {
switch (this) {
case KRLoginProgressStatus.kr_check:
return 0;
case KRLoginProgressStatus.kr_loginByCode:
return 2;
case KRLoginProgressStatus.kr_loginByPsd:
return 3;
case KRLoginProgressStatus.kr_registerSendCode:
return 4;
case KRLoginProgressStatus.kr_registerSetPsd:
return 5;
case KRLoginProgressStatus.kr_forgetPsdSendCode:
return 6;
case KRLoginProgressStatus.kr_forgetPsdSetPsd:
return 7;
}
}
}
class KRLoginController extends GetxController
with GetSingleTickerProviderStateMixin {
/// 是否注册
RxBool kr_isRegistered = false.obs;
/// 登陆类型
var kr_loginType = KRLoginType.kr_email.obs;
/// 登陆进度状态
var kr_loginStatus = KRLoginProgressStatus.kr_check.obs;
/// 验证码倒计时
var _countdown = 60; // 倒计时初始值
late Timer _timer;
var kr_countdownText = AppTranslations.kr_login.sendCode.obs;
/// 是否允许发送验证码
RxBool kr_canSendCode = true.obs;
/// 国家编码列表
late List<KRAreaCodeItem> kr_areaCodeList = KRAreaCode.kr_getCodeList();
var kr_cutSeleteCodeIndex = 0.obs;
/// 是否加密密码
var kr_obscureText = true.obs;
/// 匹配邮箱列表
RxList kr_emailList = [].obs;
RxBool kr_isDropdownVisible = false.obs;
/// 定位
final LayerLink kr_layerLink = LayerLink();
OverlayEntry? overlayEntry; // 悬浮框
bool isDropdownVisible = false; // 控制悬浮框显示状态
/// 动画
late AnimationController animationController;
late Animation<double> animation;
var height = 100.0.obs;
/// 账号编辑控制器
late TextEditingController accountController = TextEditingController();
/// 验证码编辑控制器
late TextEditingController codeController = TextEditingController();
/// 密码编辑控制器
late TextEditingController psdController = TextEditingController();
/// 密码编辑控制器
late TextEditingController agPsdController = TextEditingController();
var kr_accountHasText = false.obs;
var kr_codeHasText = false.obs;
var kr_psdHasText = false.obs;
var kr_agPsdHasText = false.obs;
// 添加邀请码相关控制
final TextEditingController inviteCodeController = TextEditingController();
final RxBool kr_inviteCodeHasText = false.obs;
// 添加 FocusNode
late FocusNode kr_accountFocusNode;
// 添加获取按钮文本的方法
String kr_getNextBtnText() {
switch (kr_loginStatus.value) {
case KRLoginProgressStatus.kr_check:
return AppTranslations.kr_login.passwordLogin; // 显示"登录"
case KRLoginProgressStatus.kr_loginByCode:
return AppTranslations.kr_login.passwordLogin; // 已废弃,保留以防兼容性问题
case KRLoginProgressStatus.kr_loginByPsd:
return AppTranslations.kr_login.passwordLogin;
case KRLoginProgressStatus.kr_registerSendCode:
return AppTranslations.kr_login.next;
case KRLoginProgressStatus.kr_registerSetPsd:
return AppTranslations.kr_login.registerNow;
case KRLoginProgressStatus.kr_forgetPsdSendCode:
return AppTranslations.kr_login.next;
case KRLoginProgressStatus.kr_forgetPsdSetPsd:
return AppTranslations.kr_login.setAndLogin;
}
}
@override
void onInit() {
super.onInit();
// 初始化计时器
_timer = Timer(Duration.zero, () {});
animationController = AnimationController(
duration: Duration(milliseconds: 500),
vsync: this,
);
animation = Tween<double>(begin: 300.0, end: 300.0).animate(
CurvedAnimation(parent: animationController, curve: Curves.easeInOut),
)..addListener(() {
height.value = animation.value;
});
// 初始化 FocusNode
kr_accountFocusNode = FocusNode();
// 监听 kr_loginStatus 的变化
ever(kr_loginStatus, (status) {
switch (status) {
case KRLoginProgressStatus.kr_check:
kr_isDropdownVisible.value = true;
accountController.clear();
codeController.clear();
psdController.clear();
agPsdController.clear();
inviteCodeController.clear();
break;
case KRLoginProgressStatus.kr_loginByCode:
kr_isDropdownVisible.value = false;
break;
case KRLoginProgressStatus.kr_loginByPsd:
kr_isDropdownVisible.value = false;
break;
case KRLoginProgressStatus.kr_registerSendCode:
kr_isDropdownVisible.value = false;
break;
case KRLoginProgressStatus.kr_registerSetPsd:
kr_isDropdownVisible.value = false;
break;
case KRLoginProgressStatus.kr_forgetPsdSendCode:
kr_isDropdownVisible.value = false;
break;
case KRLoginProgressStatus.kr_forgetPsdSetPsd:
kr_isDropdownVisible.value = false;
break;
}
});
// accountController 监听器(仅支持邮箱)
accountController.addListener(() {
String input = accountController.text.trim();
// 延迟执行状态更新
Future.microtask(() {
// 始终保持邮箱类型
kr_loginType.value = KRLoginType.kr_email;
// 更新邮箱建议列表
kr_emailList.value = kr_generateAndSortEmailList(input);
kr_accountHasText.value = input.isNotEmpty;
});
});
/// 验证码
codeController.addListener(() {
kr_codeHasText.value = !codeController.text.isEmpty;
});
/// 密码
psdController.addListener(() {
kr_psdHasText.value = !psdController.text.isEmpty;
});
/// 密码
agPsdController.addListener(() {
kr_agPsdHasText.value = !agPsdController.text.isEmpty;
});
// 添加邀请码输入监听
inviteCodeController.addListener(() {
kr_inviteCodeHasText.value = inviteCodeController.text.isNotEmpty;
});
// 语言变化时更新所有翻译文本
ever(KRLanguageUtils.kr_language, (_) {
if (kr_canSendCode.value) {
kr_countdownText.value = "";
kr_countdownText.value = AppTranslations.kr_login.sendCode;
}
});
kr_initFocus();
}
// 判断是否是手机号
bool _isNumeric(String input) {
final numericRegex = RegExp(r'^\d+$'); // 匹配纯数字
return numericRegex.hasMatch(input);
}
/// 直接登录(不再检查是否注册)
void kr_check() async {
if (accountController.text.isEmpty) {
KRCommonUtil.kr_showToast(AppTranslations.kr_login.enterAccount);
return;
}
if (psdController.text.isEmpty) {
KRCommonUtil.kr_showToast(AppTranslations.kr_login.enterPassword);
return;
}
// 直接调用登录
kr_login();
}
/// 发送验证码(仅支持邮箱)
void kr_sendCode() async {
final either = await KRAuthApi().kr_sendCode(
accountController.text,
kr_loginStatus.value == KRLoginProgressStatus.kr_registerSendCode
? 2 // 注册验证码类型为2
: 3); // 重置密码验证码类型为3
either.fold((l) {
KRCommonUtil.kr_showToast(l.msg);
}, (r) async {
/// 开始倒计时
_startCountdown();
});
}
/// 开始登录(仅支持邮箱+密码)
void kr_login() async {
if (psdController.text.isEmpty) {
KRCommonUtil.kr_showToast(AppTranslations.kr_login.enterPassword);
return;
}
final either = await KRAuthApi().kr_login(
accountController.text,
psdController.text);
either.fold((l) {
KRCommonUtil.kr_showToast(l.msg);
}, (r) async {
_saveLoginData(r);
});
}
/// 开始注册(仅支持邮箱,验证码和邀请码可选)
void kr_register() async {
// 验证邮箱
if (accountController.text.isEmpty) {
KRCommonUtil.kr_showToast(AppTranslations.kr_login.enterAccount);
return;
}
if (psdController.text.isEmpty) {
KRCommonUtil.kr_showToast(AppTranslations.kr_login.enterPassword);
return;
}
if (agPsdController.text.isEmpty) {
KRCommonUtil.kr_showToast(AppTranslations.kr_login.reenterPassword);
return;
}
if (psdController.text != agPsdController.text) {
KRCommonUtil.kr_showToast(AppTranslations.kr_login.passwordMismatch);
return;
}
// 检查是否需要验证码(基于站点配置)
final siteConfig = KRSiteConfigService();
final needVerification = siteConfig.isEmailVerificationEnabled() ||
siteConfig.isRegisterVerificationEnabled();
if (needVerification && codeController.text.isEmpty) {
KRCommonUtil.kr_showToast(AppTranslations.kr_login.enterCode);
return;
}
final either = await KRAuthApi().kr_register(
accountController.text,
psdController.text,
code: codeController.text.isEmpty ? null : codeController.text,
inviteCode: inviteCodeController.text.isEmpty ? null : inviteCodeController.text);
either.fold((l) {
KRCommonUtil.kr_showToast(l.msg);
}, (r) async {
_saveLoginData(r);
KRCommonUtil.kr_showToast(AppTranslations.kr_login.registerSuccess);
});
}
void kr_checkCode() {
if (codeController.text.isEmpty) {
KRCommonUtil.kr_showToast(AppTranslations.kr_login.enterCode);
return;
}
switch (kr_loginStatus.value) {
case KRLoginProgressStatus.kr_check:
break;
case KRLoginProgressStatus.kr_loginByCode:
break;
case KRLoginProgressStatus.kr_loginByPsd:
break;
case KRLoginProgressStatus.kr_registerSendCode:
kr_checkVerificationCode(KRLoginProgressStatus.kr_registerSendCode);
break;
case KRLoginProgressStatus.kr_registerSetPsd:
break;
case KRLoginProgressStatus.kr_forgetPsdSendCode:
kr_checkVerificationCode(KRLoginProgressStatus.kr_forgetPsdSendCode);
break;
case KRLoginProgressStatus.kr_forgetPsdSetPsd:
break;
}
}
/// 验证验证码(仅支持邮箱)
void kr_checkVerificationCode(KRLoginProgressStatus status) async {
final either = await KRAuthApi().kr_checkVerificationCode(
accountController.text,
codeController.text,
kr_loginStatus.value == KRLoginProgressStatus.kr_registerSendCode
? 2 // 注册验证码类型为2
: 3); // 重置密码验证码类型为3
either.fold((l) {
KRCommonUtil.kr_showToast(l.msg);
}, (r) async {
if (status == KRLoginProgressStatus.kr_registerSendCode) {
kr_loginStatus.value = KRLoginProgressStatus.kr_registerSetPsd;
} else if (status == KRLoginProgressStatus.kr_forgetPsdSendCode) {
kr_loginStatus.value = KRLoginProgressStatus.kr_forgetPsdSetPsd;
}
});
}
/// 忘记密码-设置新密码(仅支持邮箱)
void kr_setNewPsdByForgetPsd() async {
if (psdController.text.isEmpty) {
KRCommonUtil.kr_showToast(AppTranslations.kr_login.enterPassword);
return;
}
if (agPsdController.text.isEmpty) {
KRCommonUtil.kr_showToast(AppTranslations.kr_login.reenterPassword);
return;
}
if (psdController.text != agPsdController.text) {
KRCommonUtil.kr_showToast(AppTranslations.kr_login.passwordMismatch);
return;
}
final either = await KRAuthApi().kr_setNewPsdByForgetPsd(
accountController.text,
codeController.text,
psdController.text);
either.fold((l) {
KRCommonUtil.kr_showToast(l.msg);
}, (r) async {
codeController.clear();
psdController.clear();
kr_loginStatus.value = KRLoginProgressStatus.kr_forgetPsdSetPsd;
_saveLoginData(r);
});
}
/// 开始倒计时
void _startCountdown() {
kr_canSendCode.value = false;
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
if (_countdown > 0) {
_countdown -= 1;
kr_countdownText.value = "${_countdown}s";
} else {
kr_canSendCode.value = true;
kr_countdownText.value = AppTranslations.kr_login.sendCode;
_countdown = 60;
timer.cancel();
_onCountdownFinished();
}
});
}
/// 设置登录数据(仅支持邮箱)
void _saveLoginData(String token) {
KRAppRunData.getInstance().kr_saveUserInfo(
token,
accountController.text,
KRLoginType.kr_email,
null);
kr_loginStatus.value = KRLoginProgressStatus.kr_check;
// 登录/注册成功后,发送消息触发订阅服务刷新
// 延迟一小段时间确保登录状态已经完全保存
Future.delayed(Duration(milliseconds: 100), () {
KREventBus().kr_sendMessage(KRMessageType.kr_payment);
});
// 登录成功后返回到上一页
Get.back();
}
/// 根据输入内容匹配邮箱
List<String> kr_generateAndSortEmailList(String input) {
// 常用邮箱域名
List<String> _commonEmailDomains = [
"@gmail.com",
"@yahoo.com",
"@outlook.com",
"@hotmail.com",
"@icloud.com",
"@aol.com",
"@zoho.com",
"@protonmail.com",
"@qq.com",
"@163.com",
"@126.com",
"@sina.com",
"@sohu.com",
"@foxmail.com",
"@aliyun.com",
"@189.cn",
"@china.com",
];
// 判断是否是邮箱格式
bool isEmail(String input) {
final emailRegex =
RegExp(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$");
return emailRegex.hasMatch(input);
}
// 输入过短或者是邮箱格式,直接返回空数组
if (input.length < 2 || isEmail(input)) {
return [];
}
// 处理输入,确保只保留一个 '@' 后的内容
String sanitizedInput =
input.contains("@") ? input.substring(0, input.indexOf("@")) : input;
// 根据匹配度排序
List<String> emailList = _commonEmailDomains.map((domain) {
return "$sanitizedInput$domain";
}).toList();
// 根据用户输入的 @ 后部分对域名进行匹配和排序
String? userDomain = input.contains("@") ? input.split("@").last : null;
if (userDomain != null && userDomain.isNotEmpty) {
emailList.sort((a, b) {
String domainA = a.split("@")[1];
String domainB = b.split("@")[1];
int matchScoreA = domainA.startsWith(userDomain) ? 1 : 0;
int matchScoreB = domainB.startsWith(userDomain) ? 1 : 0;
// 先比较匹配度,再按照字母顺序排序
if (matchScoreA == matchScoreB) {
return domainA.compareTo(domainB);
}
return matchScoreB.compareTo(matchScoreA);
});
}
return emailList;
}
/// 返回
void kr_back() {
kr_removeOverlay();
switch (kr_loginStatus.value) {
case KRLoginProgressStatus.kr_check:
break;
case KRLoginProgressStatus.kr_loginByCode:
kr_loginStatus.value = KRLoginProgressStatus.kr_check;
_resetTimer();
break;
case KRLoginProgressStatus.kr_loginByPsd:
kr_loginStatus.value = KRLoginProgressStatus.kr_check;
break;
case KRLoginProgressStatus.kr_registerSendCode:
kr_loginStatus.value = KRLoginProgressStatus.kr_check;
_resetTimer();
break;
case KRLoginProgressStatus.kr_registerSetPsd:
kr_loginStatus.value = KRLoginProgressStatus.kr_registerSendCode;
psdController.clear();
agPsdController.clear();
break;
case KRLoginProgressStatus.kr_forgetPsdSendCode:
kr_loginStatus.value = KRLoginProgressStatus.kr_loginByPsd;
_resetTimer();
codeController.clear();
psdController.clear();
agPsdController.clear();
break;
case KRLoginProgressStatus.kr_forgetPsdSetPsd:
kr_loginStatus.value = KRLoginProgressStatus.kr_forgetPsdSendCode;
psdController.clear();
agPsdController.clear();
break;
}
}
/// 重置计时器
void _resetTimer() {
if (_timer.isActive) {
_timer.cancel();
}
_countdown = 60;
kr_canSendCode.value = true;
kr_countdownText.value = AppTranslations.kr_login.sendCode;
}
void _onCountdownFinished() {}
void toggleHeight() {
// if (animationController.status == AnimationStatus.completed) {
// animationController.reverse();
// } else {
// animationController.forward();
// }
}
@override
void onReady() {
super.onReady();
// 每次打开登录页面时,重置为登录状态(而不是注册状态)
// 这样确保点击"登录/注册"按钮时始终显示登录页面
kr_loginStatus.value = KRLoginProgressStatus.kr_check;
}
@override
void onClose() {
kr_removeOverlay();
if (_timer.isActive) {
_timer.cancel();
}
animationController.dispose();
inviteCodeController.dispose();
kr_accountFocusNode.dispose();
super.onClose();
}
// 添加点击输入框的方法
void kr_onInputTap() {
kr_accountFocusNode.requestFocus();
}
// 添加焦点管理
void kr_initFocus() {
kr_accountFocusNode.addListener(() {
if (kr_accountFocusNode.hasFocus) {
// 获得焦点时的处理
_updateInputState();
}
});
}
void _updateInputState() {
String input = accountController.text.trim();
// 始终保持邮箱类型
kr_loginType.value = KRLoginType.kr_email;
kr_emailList.value = kr_generateAndSortEmailList(input);
}
// 添加移除悬浮框的方法
void kr_removeOverlay() {
overlayEntry?.remove();
overlayEntry = null;
}
}