You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

999 lines
36 KiB

import 'package:deep_voice/data/models/appconfig.dart';
import 'package:deep_voice/data/models/appconfig_model.dart';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:logger/web.dart';
import '../../../routes/app_routes.dart';
import 'dart:convert';
import 'facebookLogin.dart';
import 'googleLogin.dart';
import 'weixinLogin.dart';
import '../../../data/services/network/api.dart';
import '../../../../data/models/user_Info.dart';
import '../../common/webview_page.dart';
import 'package:get_storage/get_storage.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'dart:io';
import 'package:package_info_plus/package_info_plus.dart';
import '../../../data/services/version_update_service.dart';
enum LoginViewState {
welcome, // 欢迎页面
verification // 验证码页面
}
// 用户渠道枚举
enum UserChannel {
UNKNOWN(0), // 未知渠道
CHINA_HUAWEI(1), // 中国-华为
CHINA_XIAOMI(2), // 中国-小米
CHINA_OPPO(3), // 中国-OPPO
CHINA_VIVO(4), // 中国-VIVO
CHINA_HONOR(5), // 中国-荣耀
OFFICIAL(100), // 官方渠道
GLOBAL_APPLE(101), // 全球-苹果
GLOBAL_GOOGLE(102); // 全球-谷歌
const UserChannel(this.value);
final int value;
}
class LoginController extends GetxController {
static LoginController get to => Get.find();
final GetStorage _storage = GetStorage();
// 添加游客登录显示状态
final _isGuestLoginVisible = false.obs;
bool get isGuestLoginVisible => _isGuestLoginVisible.value;
String _deviceId = '';
String _appVersion = ''; // APP版本号
String _countryCode = ''; // 国家代码
UserChannel _userChannel = UserChannel.OFFICIAL; // 默认渠道
final _hasAcceptedPrivacy = false.obs;
bool get hasAcceptedPrivacy => _hasAcceptedPrivacy.value;
set hasAcceptedPrivacy(bool value) => _hasAcceptedPrivacy.value = value;
// 添加国家编码相关状态
final _selectedCountryCode = ''.obs;
final _selectedCountryFlag = '✉️'.obs;
// 国家编码 Getter
String get selectedCountryCode => _selectedCountryCode.value;
String get selectedCountryFlag => _selectedCountryFlag.value;
// 预设国家编码列表
final List<Map<String, String>> countryCodes = [
{'name': '邮箱', 'code': '', 'flag': '✉️'}, // 保持首位
{'name': '中国', 'code': '+86', 'flag': '🇨🇳'}, // 保持第二位
// 按国家代码数字升序排列(去除+号后排序)
{'name': '美国', 'code': '+1', 'flag': '🇺🇸'},
{'name': '加拿大', 'code': '+1', 'flag': '🇨🇦'},
{'name': '俄罗斯', 'code': '+7', 'flag': '🇷🇺'},
{'name': '英国', 'code': '+44', 'flag': '🇬🇧'},
{'name': '德国', 'code': '+49', 'flag': '🇩🇪'},
{'name': '意大利', 'code': '+39', 'flag': '🇮🇹'},
{'name': '法国', 'code': '+33', 'flag': '🇫🇷'},
{'name': '西班牙', 'code': '+34', 'flag': '🇪🇸'},
{'name': '南非', 'code': '+27', 'flag': '🇿🇦'},
{'name': '沙特阿拉伯', 'code': '+966', 'flag': '🇸🇦'},
{'name': '土耳其', 'code': '+90', 'flag': '🇹🇷'},
{'name': '日本', 'code': '+81', 'flag': '🇯🇵'},
{'name': '韩国', 'code': '+82', 'flag': '🇰🇷'},
{'name': '新加坡', 'code': '+65', 'flag': '🇸🇬'},
{'name': '马来西亚', 'code': '+60', 'flag': '🇲🇾'},
{'name': '泰国', 'code': '+66', 'flag': '🇹🇭'},
{'name': '越南', 'code': '+84', 'flag': '🇻🇳'},
{'name': '印度', 'code': '+91', 'flag': '🇮🇳'},
{'name': '巴基斯坦', 'code': '+92', 'flag': '🇵🇰'},
{'name': '菲律宾', 'code': '+63', 'flag': '🇵🇭'},
{'name': '印度尼西亚', 'code': '+62', 'flag': '🇮🇩'},
{'name': '阿联酋', 'code': '+971', 'flag': '🇦🇪'},
{'name': '墨西哥', 'code': '+52', 'flag': '🇲🇽'},
{'name': '巴西', 'code': '+55', 'flag': '🇧🇷'},
{'name': '阿根廷', 'code': '+54', 'flag': '🇦🇷'},
{'name': '澳大利亚', 'code': '+61', 'flag': '🇦🇺'},
{'name': '新西兰', 'code': '+64', 'flag': '🇳🇿'},
// 中国地区(保持最后)
{'name': '中国香港', 'code': '+852', 'flag': '🇭🇰'},
{'name': '中国澳门', 'code': '+853', 'flag': '🇲🇴'},
{'name': '中国台湾', 'code': '+886', 'flag': '🇹🇼'},
// 添加的其他主要国家
{'name': '埃及', 'code': '+20', 'flag': '🇪🇬'},
{'name': '希腊', 'code': '+30', 'flag': '🇬🇷'},
{'name': '荷兰', 'code': '+31', 'flag': '🇳🇱'},
{'name': '比利时', 'code': '+32', 'flag': '🇧🇪'},
{'name': '匈牙利', 'code': '+36', 'flag': '🇭🇺'},
{'name': '罗马尼亚', 'code': '+40', 'flag': '🇷🇴'},
{'name': '瑞士', 'code': '+41', 'flag': '🇨🇭'},
{'name': '奥地利', 'code': '+43', 'flag': '🇦🇹'},
{'name': '丹麦', 'code': '+45', 'flag': '🇩🇰'},
{'name': '瑞典', 'code': '+46', 'flag': '🇸🇪'},
{'name': '挪威', 'code': '+47', 'flag': '🇳🇴'},
{'name': '波兰', 'code': '+48', 'flag': '🇵🇱'},
{'name': '秘鲁', 'code': '+51', 'flag': '🇵🇪'},
{'name': '智利', 'code': '+56', 'flag': '🇨🇱'},
{'name': '哥伦比亚', 'code': '+57', 'flag': '🇨🇴'},
{'name': '委内瑞拉', 'code': '+58', 'flag': '🇻🇪'},
{'name': '葡萄牙', 'code': '+351', 'flag': '🇵🇹'},
{'name': '卢森堡', 'code': '+352', 'flag': '🇱🇺'},
{'name': '爱尔兰', 'code': '+353', 'flag': '🇮🇪'},
{'name': '冰岛', 'code': '+354', 'flag': '🇮🇸'},
{'name': '阿尔巴尼亚', 'code': '+355', 'flag': '🇦🇱'},
{'name': '马耳他', 'code': '+356', 'flag': '🇲🇹'},
{'name': '塞浦路斯', 'code': '+357', 'flag': '🇨🇾'},
{'name': '芬兰', 'code': '+358', 'flag': '🇫🇮'},
{'name': '保加利亚', 'code': '+359', 'flag': '🇧🇬'},
{'name': '立陶宛', 'code': '+370', 'flag': '🇱🇹'},
{'name': '拉脱维亚', 'code': '+371', 'flag': '🇱🇻'},
{'name': '爱沙尼亚', 'code': '+372', 'flag': '🇪🇪'},
{'name': '乌克兰', 'code': '+380', 'flag': '🇺🇦'},
{'name': '塞尔维亚', 'code': '+381', 'flag': '🇷🇸'},
{'name': '克罗地亚', 'code': '+385', 'flag': '🇭🇷'},
{'name': '斯洛文尼亚', 'code': '+386', 'flag': '🇸🇮'},
{'name': '捷克', 'code': '+420', 'flag': '🇨🇿'},
{'name': '斯洛伐克', 'code': '+421', 'flag': '🇸🇰'},
{'name': '危地马拉', 'code': '+502', 'flag': '🇬🇹'},
{'name': '萨尔瓦多', 'code': '+503', 'flag': '🇸🇻'},
{'name': '洪都拉斯', 'code': '+504', 'flag': '🇭🇳'},
{'name': '尼加拉瓜', 'code': '+505', 'flag': '🇳🇮'},
{'name': '哥斯达黎加', 'code': '+506', 'flag': '🇨🇷'},
{'name': '巴拿马', 'code': '+507', 'flag': '🇵🇦'},
{'name': '海地', 'code': '+509', 'flag': '🇭🇹'},
{'name': '玻利维亚', 'code': '+591', 'flag': '🇧🇴'},
{'name': '厄瓜多尔', 'code': '+593', 'flag': '🇪🇨'},
{'name': '巴拉圭', 'code': '+595', 'flag': '🇵🇾'},
{'name': '乌拉圭', 'code': '+598', 'flag': '🇺🇾'},
{'name': '摩洛哥', 'code': '+212', 'flag': '🇲🇦'},
{'name': '阿尔及利亚', 'code': '+213', 'flag': '🇩🇿'},
{'name': '突尼斯', 'code': '+216', 'flag': '🇹🇳'},
{'name': '尼日利亚', 'code': '+234', 'flag': '🇳🇬'},
{'name': '加纳', 'code': '+233', 'flag': '🇬🇭'},
{'name': '埃塞俄比亚', 'code': '+251', 'flag': '🇪🇹'},
{'name': '肯尼亚', 'code': '+254', 'flag': '🇰🇪'},
{'name': '坦桑尼亚', 'code': '+255', 'flag': '🇹🇿'},
{'name': '乌干达', 'code': '+256', 'flag': '🇺🇬'},
{'name': '孟加拉国', 'code': '+880', 'flag': '🇧🇩'},
{'name': '以色列', 'code': '+972', 'flag': '🇮🇱'},
{'name': '黎巴嫩', 'code': '+961', 'flag': '🇱🇧'},
{'name': '约旦', 'code': '+962', 'flag': '🇯🇴'},
{'name': '伊拉克', 'code': '+964', 'flag': '🇮🇶'},
{'name': '科威特', 'code': '+965', 'flag': '🇰🇼'},
{'name': '巴林', 'code': '+973', 'flag': '🇧🇭'},
{'name': '卡塔尔', 'code': '+974', 'flag': '🇶🇦'},
{'name': '阿曼', 'code': '+968', 'flag': '🇴🇲'},
{'name': '阿富汗', 'code': '+93', 'flag': '🇦🇫'},
{'name': '斯里兰卡', 'code': '+94', 'flag': '🇱🇰'},
{'name': '缅甸', 'code': '+95', 'flag': '🇲🇲'},
{'name': '尼泊尔', 'code': '+977', 'flag': '🇳🇵'},
{'name': '蒙古', 'code': '+976', 'flag': '🇲🇳'},
{'name': '柬埔寨', 'code': '+855', 'flag': '🇰🇭'},
{'name': '老挝', 'code': '+856', 'flag': '🇱🇦'},
{'name': '文莱', 'code': '+673', 'flag': '🇧🇳'},
{'name': '东帝汶', 'code': '+670', 'flag': '🇹🇱'},
{'name': '斐济', 'code': '+679', 'flag': '🇫🇯'},
{'name': '所罗门群岛', 'code': '+677', 'flag': '🇸🇧'},
];
// 状态管理
final _viewState = LoginViewState.welcome.obs;
final _isLoading = false.obs;
final _countdownSeconds = 0.obs;
final _contactValue = ''.obs;
final _displayContact = ''.obs;
final _verificationCode = ['', '', '', ''].obs;
int loginType = 0;
// Getters
LoginViewState get viewState => _viewState.value;
bool get isLoading => _isLoading.value;
int get countdownSeconds => _countdownSeconds.value;
String get contactValue => _contactValue.value;
String get displayContact => _displayContact.value;
List<String> get verificationCode => _verificationCode;
// 文本控制器
TextEditingController contactController = TextEditingController();
TextEditingController verificationCodeController = TextEditingController();
@override
void onInit() {
super.onInit();
_viewState.value = LoginViewState.welcome;
_hasAcceptedPrivacy.value =
_storage.read('hasAcceptedPrivacy') ?? false; // 从本地存储中读取是否已接受隐私政策
//使用addPostFrameCallback确保在构建完成后显示对话框
WidgetsBinding.instance.addPostFrameCallback((_) {
//如果用户未接受隐私政策,显示弹窗
if (!_hasAcceptedPrivacy.value) {
_showPrivacyDialog();
}
});
_initDeviceInfo();
_initAppInfo(); // 新增:初始化APP信息
_checkGuestLoginConfig(); // 检查游客登录配置
}
@override
void onClose() {
contactController.dispose();
verificationCodeController.dispose();
super.onClose();
}
// 检查游客登录配置
Future<void> _checkGuestLoginConfig() async {
try {
final versionService = VersionUpdateService.to;
await versionService.checkForUpdate();
// 先检查版本更新,这会同时设置 isShowTourists 的值
await versionService.checkForUpdate();
// 直接使用 VersionUpdateService 中的 isShowTourists 值
_isGuestLoginVisible.value = versionService.isShowTourists.value;
Logger().d('游客登录显示状态: ${_isGuestLoginVisible.value}');
// 监听 isShowTourists 的变化
versionService.isShowTourists.listen((value) {
_isGuestLoginVisible.value = value;
Logger().d('游客登录显示状态更新: $value');
});
} catch (e) {
Logger().e('检查游客登录配置失败: $e');
// 默认不显示游客登录
_isGuestLoginVisible.value = false;
}
}
// 显示隐私政策弹窗
void _showPrivacyDialog() {
// 获取当前主题模式
final bool isDarkMode = Get.theme.brightness == Brightness.dark;
Get.dialog(
WillPopScope(
onWillPop: () async => false, // 禁止通过返回键关闭弹窗
child: Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
backgroundColor:
isDarkMode ? Colors.grey[800] : Colors.white, // 暗黑模式使用深灰色背景
child: Container(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'loginDeclaration'.tr, //APP 声明
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color:
isDarkMode ? Colors.white : Colors.black, // 暗黑模式使用白色文字
),
),
const SizedBox(height: 16),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Text.rich(
TextSpan(
children: [
TextSpan(
text: 'welcomeToThisApp'.tr, //欢迎使用本APP,请充分阅读
style: TextStyle(
fontSize: 14,
color: isDarkMode
? Colors.white70
: Colors.black87, // 暗黑模式使用浅白色
),
),
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: GestureDetector(
onTap: () {
String url = 'https://www.deepsoud.com/ysxy.html';
if (Get.locale?.languageCode != 'zh' ||
Get.locale?.countryCode != 'CN') {
url = 'https://www.deepsoud.com/ysxy_en.html';
}
Get.to(() => WebViewPage(
url: url,
title: 'privacyPolicy'.tr, //隐私政策
));
},
child: Text(
'privacyPolicy'.tr, //隐私政策
style: const TextStyle(
fontSize: 14,
color: Color(0xFF3B82F6),
),
),
),
),
TextSpan(
text: 'and'.tr, //和
style: TextStyle(
fontSize: 14,
color: isDarkMode ? Colors.white70 : Colors.black87,
),
),
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: GestureDetector(
onTap: () {
String url = 'https://www.deepsoud.com/yhxy.html';
if (Get.locale?.languageCode != 'zh' ||
Get.locale?.countryCode != 'CN') {
url = 'https://www.deepsoud.com/yhxy_en.html';
}
Get.to(() => WebViewPage(
url: url,
title: 'userAgreement'.tr, //用户协议
));
},
child: Text(
'userAgreement'.tr, //用户协议
style: const TextStyle(
fontSize: 14,
color: Color(0xFF3B82F6),
),
),
),
),
TextSpan(
text: 'privacyPolicyText'
.tr, //',点击“同意并进入”表示您已充分阅读并同意上述协议。点击“不同意”将退出应用。',
style: TextStyle(
fontSize: 14,
color: isDarkMode ? Colors.white70 : Colors.black87,
),
),
],
),
textAlign: TextAlign.center,
),
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
TextButton(
onPressed: () {
// 用户不同意,退出应用
exit(0);
},
style: TextButton.styleFrom(
foregroundColor: isDarkMode
? Colors.grey[400]
: Colors.black54, // 暗黑模式使用浅灰色
),
child: Text(
'disagree'.tr, //不同意
style: TextStyle(
color: isDarkMode ? Colors.grey[400] : Colors.black54,
),
),
//child: const Text('不同意'),
),
ElevatedButton(
onPressed: () {
_storage.write(
'hasAcceptedPrivacy', true); // 存储用户已接受隐私政策
// 用户同意,关闭弹窗并继续
_hasAcceptedPrivacy.value = true;
Get.back();
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF0066CC),
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
elevation: isDarkMode ? 4 : 2, // 暗黑模式下增加阴影效果提高辨识度
padding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 10), // 统一的内边距
),
child: Text('agreeAndEnter'.tr),
),
],
),
],
),
),
),
),
barrierDismissible: false, // 禁止点击外部关闭弹窗
);
}
// 初始化设备信息
Future<void> _initDeviceInfo() async {
try {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
if (GetPlatform.isAndroid) {
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
_deviceId = androidInfo.id;
} else if (GetPlatform.isIOS) {
IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
_deviceId = iosInfo.identifierForVendor ?? 'unknown';
}
Logger().d('deviceId: $_deviceId');
} catch (e) {
Logger().e('获取设备信息失败: $e');
_deviceId = 'unknown';
}
}
// 新增:初始化APP信息(版本号、渠道、国家代码)
Future<void> _initAppInfo() async {
try {
// 获取APP版本号
final packageInfo = await PackageInfo.fromPlatform();
_appVersion = '${packageInfo.version}+${packageInfo.buildNumber}';
Logger().d('appVersion: $_appVersion');
// 获取国家代码
_countryCode = Get.locale?.countryCode ?? 'Unknown';
Logger().d('countryCode: $_countryCode');
// 获取用户渠道(根据平台和设备信息确定)
_userChannel = UserChannel.UNKNOWN;
Logger().d('userChannel: ${_userChannel.value}');
} catch (e) {
Logger().e('获取APP信息失败: $e');
_appVersion = 'Unknown';
_countryCode = 'Unknown';
_userChannel = UserChannel.UNKNOWN;
}
}
// 更新选中的国家编码
void updateCountryCode(String code, String flag) {
_selectedCountryCode.value = code;
_selectedCountryFlag.value = flag;
// 根据选择更新输入框类型
if (code == '') {
contactController.clear(); // 清空当前输入
loginType = 0; // 设置为邮箱登录类型
} else {
loginType = 1; // 设置为手机号登录类型
}
_countdownSeconds.value = 0;
}
// 获取验证码
void getVerificationCode() {
if (contactController.text.isEmpty) {
Get.snackbar(
'tip'.tr,
'pleaseEnterContactInfo'.tr,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.1),
colorText: Colors.red,
);
return;
}
_contactValue.value = contactController.text;
_formatDisplayContact();
_sendVerificationCode();
}
// 使用验证码直接登录
void loginWithVerificationCode() {
//测试期间暂时关闭验证码登录
// if (contactController.text.isEmpty) {
// Get.snackbar(
// '提示',
// '请输入手机号码或邮箱',
// snackPosition: SnackPosition.TOP,
// backgroundColor: Colors.red.withOpacity(0.1),
// colorText: Colors.red,
// );
// return;
// }
// if (verificationCodeController.text.isEmpty) {
// Get.snackbar(
// '提示',
// '请输入验证码',
// snackPosition: SnackPosition.TOP,
// backgroundColor: Colors.red.withOpacity(0.1),
// colorText: Colors.red,
// );
// return;
// }
// if (verificationCodeController.text.length < 6) {
// Get.snackbar(
// '提示',
// '请输入完整的验证码',
// snackPosition: SnackPosition.TOP,
// backgroundColor: Colors.red.withOpacity(0.1),
// colorText: Colors.red,
// );
// return;
// }
_isLoading.value = true;
// 模拟验证过程
Future.delayed(const Duration(seconds: 2), () {
_isLoading.value = false;
// 验证成功,跳转到配对页面
Get.offAllNamed(Routes.pairing);
});
}
// 切换到验证码页面
void showVerificationView() {
if (contactController.text.isEmpty) {
Get.snackbar(
'tip'.tr,
'pleaseEnterContactInfo'.tr,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.1),
colorText: Colors.red,
);
return;
}
_contactValue.value = contactController.text;
_formatDisplayContact();
_viewState.value = LoginViewState.verification;
_sendVerificationCode();
}
// 返回欢迎页面
void showWelcomeView() {
_viewState.value = LoginViewState.welcome;
_resetVerificationCode();
}
// 格式化显示的联系方式(隐藏部分字符)
void _formatDisplayContact() {
String contact = _contactValue.value;
if (contact.contains('@')) {
// 邮箱逻辑保持不变
final parts = contact.split('@');
if (parts[0].length > 3) {
_displayContact.value = parts[0].substring(0, 3) + '****@' + parts[1];
} else {
_displayContact.value = contact;
}
loginType = 0;
} else if (RegExp(r'^\d+$').hasMatch(contact)) {
// 手机号格式化时包含国家编码
if (contact.length > 7) {
_displayContact.value = '$selectedCountryCode ' +
contact.substring(0, 3) +
'****' +
contact.substring(contact.length - 4);
} else {
_displayContact.value = '$selectedCountryCode $contact';
}
loginType = 1;
} else {
_displayContact.value = contact;
}
}
// 开始倒计时
void _startCountdown() {
_countdownSeconds.value = 60;
Future.doWhile(() async {
await Future.delayed(const Duration(seconds: 1));
_countdownSeconds.value--;
return _countdownSeconds.value > 0;
});
}
// 发送验证码
Future<void> _sendVerificationCode() async {
// 这里应该是实际发送验证码的逻辑
// 为了演示,我们只是模拟发送
if (isEmialContactController() || isPhoneContactController()) {
_startCountdown();
print(contactController.text);
var response = await Api.getCode({
"addr": selectedCountryCode + contactController.text,
"vtype": loginType,
});
if (response != null) {
print("请求后台数据验证码params=${response}");
//短信已发送
//EasyLoading.showInfo('codeSend'.tr);
}
} else {
Get.snackbar(
'tip'.tr,
'pleaseEnterContactInfo'.tr,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.1),
colorText: Colors.red,
);
return;
}
}
// 重新发送验证码
void resendVerificationCode() {
if (_countdownSeconds.value > 0) return;
_startCountdown();
_sendVerificationCode();
}
// 更新验证码输入
void updateVerificationCode(int index, String value) {
print("updateVerificationCode=${index}${value}");
if (index >= 0 && index < 4) {
var newList = [..._verificationCode];
newList[index] = value;
_verificationCode.value = newList;
}
}
// 重置验证码
void _resetVerificationCode() {
_verificationCode.value = ['', '', '', ''];
}
// 检查邮箱格式
bool isEmialContactController() {
// 检查每个元素是否为单个字母或数字字符
final text = contactController.text;
return (text.length > 5 &&
RegExp(r'^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$')
.hasMatch(text));
}
// 检查手机号码格式
bool isPhoneContactController() {
// 检查每个元素是否为单个字母或数字字符
final text = contactController.text;
return RegExp(r'^[0-9]+$').hasMatch(text);
}
// 检查验证码是否完整
bool isVerificationCodeComplete() {
// 检查每个元素是否为单个字母或数字字符
final text = verificationCodeController.text;
print("数据获取Facebook${text.length}");
return text.length == 4 && RegExp(r'^[0-9]+$').hasMatch(text);
}
// 登录
Future<void> login() async {
// 添加基础验证
if (loginType == 0 || loginType == 1) {
// 邮箱或手机号登录
if (contactController.text.isEmpty) {
Get.snackbar(
'error'.tr,
'pleaseEnterContactInfo'.tr,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.1),
colorText: Colors.red,
);
return;
}
// 验证邮箱格式
if (loginType == 0 && !isEmialContactController()) {
Get.snackbar(
'error'.tr,
'invalidEmailFormat'.tr,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.1),
colorText: Colors.red,
);
return;
}
// 验证手机号格式
if (loginType == 1 && !isPhoneContactController()) {
Get.snackbar(
'error'.tr,
'invalidPhoneFormat'.tr,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.1),
colorText: Colors.red,
);
return;
}
}
//验证隐私协议勾选状态
if (!_hasAcceptedPrivacy.value) {
// Get.snackbar(
// 'tip'.tr,
// 'pleaseAcceptPrivacyPolicy'.tr,
// snackPosition: SnackPosition.TOP,
// backgroundColor: Colors.red.withOpacity(0.1),
// colorText: Colors.red,
// );
_showPrivacyDialog();
return;
}
_isLoading.value = true;
// 模拟验证过程
// Future.delayed(const Duration(seconds: 2), () {
// _isLoading.value = false;
// // 验证成功,跳转到配对页面
// Get.offAllNamed(Routes.pairing);
// });
try {
switch (loginType) {
case 0: //邮箱登录
{
if (!isVerificationCodeComplete()) {
Get.snackbar(
'tip'.tr,
'pleaseEnterVerificationCode'.tr,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.1),
colorText: Colors.red,
);
break;
}
requestLogin({
"mail": contactController.text,
"phone": "",
"stype": loginType,
"vcode": verificationCodeController.text,
"ttoken": "",
"phonemodel": "",
"phonemac": _deviceId,
"name": "",
"avatar": "",
});
break;
}
case 1: //手机号登录
{
if (!isVerificationCodeComplete()) {
Get.snackbar(
'tip'.tr,
'pleaseEnterVerificationCode'.tr,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.1),
colorText: Colors.red,
);
break;
}
requestLogin({
"mail": "",
"phone": selectedCountryCode + contactController.text,
"stype": loginType,
"vcode": verificationCodeController.text,
"ttoken": "",
"phonemodel": "",
"phonemac": _deviceId,
"name": "",
"avatar": "",
});
break;
}
case 4: //Facebook登录
{
print("数据获取Facebook");
final facebook = Facebook();
bool authResult = await facebook.signInWithFacebook();
if (authResult) {
print("数据获取_Facebook.token${facebook.token}");
print("数据获取_Facebook.pictureurl${facebook.pictureurl}");
print("数据获取_Facebook.pictureurl${facebook.email}");
// SettingsController().userName = Facebook().name;
// SettingsController().avatar = Facebook().pictureurl;
// SettingsController().userId = Facebook().id;
//SettingsController().avatar = Google().email;
// 验证成功,跳转到配对页面
requestLogin({
"mail": facebook.email,
"phone": "",
"stype": loginType,
"vcode": "",
"ttoken": facebook.token,
"phonemodel": "",
"phonemac": _deviceId,
"name": facebook.name,
"avatar": facebook.pictureurl,
});
}
break;
}
case 3: //Google登录
{
print("数据获取_Google()");
final google = Google();
bool authResult = await google.signInWithGoogle();
print("数据获取_Google().token${authResult}");
if (authResult) {
print("数据获取_Google.token${google.token}");
print("数据获取_Google.pictureurl${google.pictureurl}");
print("数据获取_Google.email${google.email}");
print("数据获取_Google.email${google.displayName}");
// 验证成功,跳转到配对页面
// SettingsController().userName = Google().displayName!;
// //SettingsController().avatar = Google().email;
// SettingsController().userId = Google().id!;
requestLogin({
"mail": google.email,
"phone": "",
"stype": loginType,
"vcode": "",
"ttoken": google.token,
"phonemodel": "",
"phonemac": _deviceId,
"name": google.displayName,
"avatar": google.pictureurl,
});
}
break;
}
case 2: //微信登录
{
print("数据获取_FlWX()");
bool authResult = await FlWX().authBy(
NormalAuth(
scope: "snsapi_userinfo",
state: "wechat_sdk_demo_test",
),
getUserInfo: true, // 按需获取用户信息
);
if (authResult) {
// 确保 FlWX() 返回的是同一个实例,并且 token 已经被设置
// 这里假设 FlWX().token 在 authBy 成功后被设置
print("数据获取_FlWX().token${FlWX().token}");
// SettingsController().userName = FlWX().nickname;
// SettingsController().avatar = FlWX().headimgurl;
// SettingsController().userId = FlWX().openid;
requestLogin({
"mail": "",
"phone": "",
"stype": loginType,
"vcode": "",
"ttoken": FlWX().code,
"phonemodel": "",
"phonemac": _deviceId,
"name": FlWX().nickname,
"avatar": FlWX().headimgurl,
});
// 验证成功,跳转到配对页面
}
break;
}
case 6: //游客登录
{
requestLogin({
"mail": "",
"phone": "",
"stype": loginType,
"vcode": "",
"ttoken": "",
"phonemodel": "",
"phonemac": _deviceId,
"name": "",
"avatar": "",
});
break;
}
default:
{
Get.snackbar(
'error'.tr,
'loginFailed'.tr,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.1),
colorText: Colors.red,
);
break;
}
}
} catch (e) {
Get.snackbar(
'error'.tr,
'loginFailed'.tr,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withOpacity(0.1),
colorText: Colors.red,
);
} finally {
_isLoading.value = false;
}
}
// 使用登陆请求服务器
Future<void> requestLogin(Map params) async {
var response = await Api.login({
"mail": params["mail"],
"phone": params["phone"],
"stype": params["stype"],
"vcode": params["vcode"],
"ttoken": params["ttoken"],
"phonemodel": params["phonemodel"],
"phonemac": params["phonemac"],
"name": params["name"],
"avatar": params["avatar"],
});
if (response != null) {
print("请求后台数据login回复数据=${response}");
// final instance = await GetStorage();
await _storage.write('loginInfo', jsonEncode(response));
// 2. 将响应数据转换为User对象
try {
print('响应数据: ${response.toString()}'); // 调试输出原始数据
if (response['token'].toString() != '') {
// 新增:检查 user 字段是否存在且类型正确
// if (response.containsKey('data') && response['data'] is Map) {
final user = User.fromJson(response);
print('用户初始化成功: ${response['token'].toString()}');
await _storage.write("logintoken", response['token'].toString());
// 存储到 SharedPreferences (仅存储用户数据)
//final prefs = await GetStorage();
await _storage.write('user_info', user.toJson());
//获取app的配置信息
await getAppConfig();
Get.offAllNamed(Routes.pairing);
// } else {
// throw FormatException('API 响应缺少 user 字段');
// }
} else {
throw Exception('接口返回错误: ${response['msg']}');
}
} catch (e, stack) {
// 新增:打印堆栈跟踪
print('用户数据处理失败: $e');
print('堆栈跟踪: $stack');
Get.snackbar('错误', '用户数据解析失败,请检查网络');
}
// Get.offAll(() => IndexWidget());
}
}
// 使用密码登录
void usePasswordLogin() {
// 这里可以实现密码登录的逻辑
Get.snackbar(
'提示',
'密码登录功能尚未实现',
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.blue.withOpacity(0.1),
colorText: Colors.blue,
);
}
Future<bool> getAppConfig() async {
try {
print('getAppConfig:进来了');
//if (User.getname() != "") {
final response = await Api.getappconfig();
print('getAppConfig: $response');
if (response == null) return false;
print('getAppConfig:进来了');
// 根据API设计调整
final resp = UserGetAppConfigResp.fromJson(response);
AppConfig.initialize(resp);
return true;
} catch (e) {
print('getAppConfig 取失败: $e');
return false;
}
}
}