import 'package:dio/dio.dart' as dio; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:logger/logger.dart'; import '../../../data/models/user_Info.dart'; import '../../settings/controllers/settings_controller.dart'; import 'dart:io'; //import 'dart:convert'; import 'package:flutter_image_compress/flutter_image_compress.dart'; import 'package:path_provider/path_provider.dart'; import '../../../data/services/network/api.dart'; import 'package:dio/dio.dart'; import '../../../routes/app_routes.dart'; //import '../../../modules/login/controllers/googleLogin.dart'; //import '../../../modules/login/controllers/facebookLogin.dart'; import '../../../data/services/account_service.dart'; //import 'package:http_parser/http_parser.dart'; // 新增此导入 class ProfileController extends GetxController { static ProfileController get to => Get.find(); //用户信息 static const String userKey = 'user_info'; //用户信息存储键 final _storage = GetStorage(); //本地存储 final ImagePicker _picker = ImagePicker(); //图片选择器 final Rx userInfo = User.instance.obs; // 响应式用户信息对象,使用单例模式确保全局唯一性 final RxString localAvatar = ''.obs; // 本地头像路径,便于响应式更新UI final RxBool hasEdits = false.obs; // 是否有编辑 final RxBool isUpdating = false.obs; // 是否正在更新用户信息 final RxBool isEditingNickname = false.obs; // 是否正在编辑昵称(内联编辑状态) // 用于乐观更新的原始状态备份 String _originalName = ''; String _originalAvatar = ''; String _originalLocalAvatar = ''; // 使用响应式变量 final currentLanguage = 'zh'.obs; // 账号服务 late final AccountService _accountService; // 错误处理工具方法 String _getErrorMessage(dynamic error) { final errorStr = error.toString().toLowerCase(); if (errorStr.contains('network') || errorStr.contains('socket') || errorStr.contains('timeout') || errorStr.contains('connection')) { return 'networkConnectionFailed'.tr; //网络连接失败 } else if (errorStr.contains('server') || errorStr.contains('500') || errorStr.contains('502') || errorStr.contains('503')) { return 'serverTemporarilyUnavailable'.tr; //服务器暂时不可用 } else if (errorStr.contains('401') || errorStr.contains('unauthorized')) { return 'loginExpiredPleaseRelogin'.tr; //登录过期,请重新登录 } else if (errorStr.contains('403') || errorStr.contains('forbidden')) { return 'noPermissionForThisOperation'.tr; //没有权限执行此操作 } else if (errorStr.contains('404')) { return 'requestedResourceNotFound'.tr; //请求的资源不存在 } else if (errorStr.contains('file') || errorStr.contains('image')) { return 'imageProcessingFailedPleaseReselect'.tr; //图片处理失败,请重新选择图片 } else { return 'operationFailedPleaseRetry'.tr; //操作失败,请重试 } } @override void onInit() { super.onInit(); // 获取或注册账号服务 _accountService = Get.find(); loadUserInfo(); loadLanguagePreference(); } // 加载用户语言偏好设置 void loadLanguagePreference() { try { final String? languageCode = _storage.read('languageCode'); final String? countryCode = _storage.read('countryCode'); if (languageCode != null && countryCode != null) { Get.updateLocale(Locale(languageCode, countryCode)); currentLanguage.value = languageCode; } } catch (e) { print('Failed to load language preference: $e'); } } // 保存用户语言偏好设置 Future saveLanguagePreference(Locale locale) async { try { await _storage.write('languageCode', locale.languageCode); await _storage.write('countryCode', locale.countryCode); } catch (e) { print('Failed to save language preference: $e'); } } // 切换应用语言 void changeLanguage(String languageCode, String countryCode) { // 使用Future.delayed来避免在构建过程中更新UI Future.delayed(Duration.zero, () async { final locale = Locale(languageCode, countryCode); await saveLanguagePreference(locale); Get.updateLocale(locale); currentLanguage.value = languageCode; }); } // Future updateUserData({ // String? userName, // String? email, // String? avatar, // }) async { // try { // if (userName != null) { // await _storage.write('userName', userName); // _userName.value = userName; // } // if (email != null) { // await _storage.write('userEmail', email); // _email.value = email; // } // if (avatar != null) { // await _storage.write('userAvatar', avatar); // _avatar.value = avatar; // } // Get.snackbar('Success', 'Profile updated successfully'); // } catch (e) { // Get.snackbar('Error', 'Failed to update profile'); // } // } // void toggleEditing() { // _isEditing.value = !_isEditing.value; // } // 验证base64图片数据 // Future _verifyBase64Image(String base64String) async { // try { // // 解码base64数据 // List imageBytes = base64Decode(base64String); // // 获取应用文档目录 // final appDir = await getApplicationDocumentsDirectory(); // final verifyPath = '${appDir.path}/verify_base64_${DateTime.now().millisecondsSinceEpoch}.jpg'; // // 将解码后的数据写入文件 // final file = File(verifyPath); // await file.writeAsBytes(imageBytes); // // 记录验证文件的路径 // Logger().d('Base64验证图片已保存到: $verifyPath'); // // 显示图片预览对话框 // Get.dialog( // Dialog( // child: Column( // mainAxisSize: MainAxisSize.min, // children: [ // Padding( // padding: const EdgeInsets.all(16.0), // child: Text('Base64 图片验证', style: TextStyle(fontWeight: FontWeight.bold)), // ), // Image.file(File(verifyPath)), // Padding( // padding: const EdgeInsets.all(16.0), // child: ElevatedButton( // onPressed: () => Get.back(), // child: Text('关闭'), // ), // ), // ], // ), // ), // ); // Get.snackbar('验证', '已将Base64转换回图片,请查看预览'); // } catch (e) { // Logger().e('验证Base64图片失败: $e'); // Get.snackbar('错误', 'Base64验证失败: $e'); // } // } // 更新用户信息到后端 Future _syncWithBackend() async { try { Logger().d('开始同步用户信息到后端'); // 创建FormData对象用于上传 dio.FormData formData = dio.FormData(); // 添加基本用户信息 formData.fields.add(MapEntry('language', currentLanguage.value)); formData.fields.add(MapEntry('name', userInfo.value.name)); // 如果有头像,添加到FormData if (localAvatar.value.isNotEmpty) { try { File imageFile = File(localAvatar.value); if (await imageFile.exists()) { // 添加文件到FormData formData.files.add( MapEntry( 'file', await dio.MultipartFile.fromFile( imageFile.path, filename: 'avatar.jpg', ), ), ); Logger().d('已添加头像文件到请求'); } else { Logger().e('头像文件不存在: ${localAvatar.value}'); throw Exception('头像文件不存在'); } } catch (e) { Logger().e('读取头像文件失败: $e'); throw Exception('读取头像文件失败: $e'); } } Logger().d('准备更新用户信息: ${formData.fields}'); // 调用API,使用FormData final response = await Api.updateUserSetting(formData); Logger().d('--更新用户信息响应: $response'); if (response != null && response is Map) { // 检查响应是否包含错误 if (response.containsKey('error') || response.containsKey('msg')) { final errorMsg = response['error'] ?? response['msg'] ?? 'serverReturnedError'.tr; //服务器返回错误 Logger().e('服务器返回错误: $errorMsg'); throw Exception('${'serverError'.tr}: $errorMsg'); //服务器错误 } Logger().d('更新成功: $response'); // 更新用户信息为服务器返回的最新数据 userInfo.update((u) { if (u != null) { u.name = response['name'] ?? u.name; u.avatar = response['avatar'] ?? u.avatar; } }); // 如果服务器返回了新的头像URL,下载并保存到本地 if (response['avatar'] != null && response['avatar'].toString().isNotEmpty) { final serverAvatar = response['avatar'].toString(); if (serverAvatar.startsWith('http')) { // 异步下载新头像,不阻塞当前流程 _downloadAndSaveAvatar(serverAvatar); } } Logger().d('更新后的用户信息: ${userInfo.value.toJson()}'); } else { Logger().e('服务器响应为空或格式错误: $response'); throw Exception('服务器响应异常'); } } catch (e) { Logger().e('同步到后端失败: $e'); // 根据错误类型抛出更具体的异常 if (e.toString().contains('SocketException') || e.toString().contains('TimeoutException') || e.toString().contains('network')) { throw Exception( 'network: ${'networkConnectionFailedCheckSettings'.tr}'); //网络连接失败,请检查网络设置 } else if (e.toString().contains('500') || e.toString().contains('server')) { throw Exception( 'server: ${'serverInternalErrorRetryLater'.tr}'); //服务器内部错误,请稍后重试 } else { throw Exception('unknown: ${e.toString()}'); } } } void loadUserInfo() { final userJson = _storage.read(userKey); if (userJson != null) { userInfo.value = User.instance; Logger().d('从本地加载用户信息: $userJson'); // 加载本地头像路径并验证文件有效性 final savedLocalAvatar = _storage.read('local_avatar'); if (savedLocalAvatar != null && savedLocalAvatar.toString().isNotEmpty) { final avatarPath = savedLocalAvatar.toString(); // 验证文件是否存在 final file = File(avatarPath); file.exists().then((exists) { if (exists) { localAvatar.value = avatarPath; Logger().d('加载本地头像路径: ${localAvatar.value}'); } else { // 文件不存在,清除无效路径 localAvatar.value = ''; _storage.remove('local_avatar'); Logger().w('本地头像文件不存在,已清除路径: $avatarPath'); } }); } else { // 确保本地头像路径为空 localAvatar.value = ''; Logger().d('没有本地头像路径'); } // 保存原始状态用于回滚 _saveOriginalState(); // 如果有远程头像地址,下载并保存到本地 if (userInfo.value.avatar.isNotEmpty) { Logger().d('远程头像地址: ${userInfo.value.avatar}'); _downloadAndSaveAvatar(userInfo.value.avatar); } // 确保状态一致性 _ensureStateConsistency(); } } // 确保本地状态与服务器状态的一致性 void _ensureStateConsistency() { // 检查本地头像文件是否存在 if (localAvatar.value.isNotEmpty) { final file = File(localAvatar.value); file.exists().then((exists) { if (!exists) { Logger().w('本地头像文件不存在,清除本地头像路径: ${localAvatar.value}'); localAvatar.value = ''; _storage.remove('local_avatar'); // 如果有远程头像,重新下载 if (userInfo.value.avatar.isNotEmpty) { _downloadAndSaveAvatar(userInfo.value.avatar); } } }); } } // 保存原始状态用于乐观更新回滚 void _saveOriginalState() { _originalName = userInfo.value.name; _originalAvatar = userInfo.value.avatar; _originalLocalAvatar = localAvatar.value; Logger().d( '已保存原始状态 - 名称: $_originalName, 头像: $_originalAvatar, 本地头像: $_originalLocalAvatar'); } // 回滚到原始状态 Future _rollbackToOriginalState() async { Logger().d('开始回滚到原始状态'); // 回滚内存中的状态 userInfo.update((user) { if (user != null) { user.name = _originalName; user.avatar = _originalAvatar; } }); localAvatar.value = _originalLocalAvatar; // 重置编辑状态 hasEdits.value = false; // 关键修复:回滚后立即同步到本地存储 try { await _syncLocalStorage(); Logger().d('回滚状态已同步到本地存储'); } catch (e) { Logger().e('回滚状态同步到本地存储失败: $e'); } Logger().d( '已回滚到原始状态 - 名称: $_originalName, 头像: $_originalAvatar, 本地头像: $_originalLocalAvatar'); } // 开始编辑昵称(内联编辑) void startEditingNickname() { isEditingNickname.value = true; Logger().d('开始内联编辑昵称'); } // 完成编辑昵称(内联编辑) void finishEditingNickname(String newName) { isEditingNickname.value = false; if (newName.trim().isNotEmpty && newName.trim() != _originalName) { // 乐观更新 userInfo.update((user) { if (user != null) { user.name = newName.trim(); } }); hasEdits.value = true; Logger().d('昵称内联编辑完成,新名称: ${newName.trim()}'); } else { Logger().d('昵称内联编辑取消或无变化'); } } // 取消编辑昵称(内联编辑) void cancelEditingNickname() { isEditingNickname.value = false; Logger().d('取消内联编辑昵称'); } // 下载并保存远程头像 Future _downloadAndSaveAvatar(String url) async { try { Logger().d('开始下载头像: $url'); final dio = Dio(BaseOptions( headers: { 'accept': '*/*', 'Authorization': _storage.read("logintoken"), }, )); final response = await dio.get( url, options: Options(responseType: ResponseType.bytes), ); Logger().d('下载状态: ${response.statusCode}'); if (response.statusCode == 200) { // 保存到应用文档目录 final appDir = await getApplicationSupportDirectory(); final fileName = '/UserAvatar/avatar_${DateTime.now().millisecondsSinceEpoch}.jpg'; final localPath = '${appDir.path}/$fileName'; // 写入文件 final file = File(localPath); await file.parent.create(recursive: true); await file.writeAsBytes(response.data); // 更新本地头像路径 localAvatar.value = localPath; await _storage.write('local_avatar', localPath); Logger().d('头像已下载到本地: $localPath'); //Get.snackbar('头像', '头像已下载到本地'); } } catch (e) { Logger().e('下载头像失败: $e'); } } Future saveUserInfo() async { await _storage.write(userKey, userInfo.value.toJson()); Logger().d('用户信息已保存到本地存储'); } // 同步所有相关状态到本地存储 Future _syncLocalStorage() async { try { // 保存用户信息 await saveUserInfo(); // 同步本地头像路径 if (localAvatar.value.isNotEmpty) { await _storage.write('local_avatar', localAvatar.value); Logger().d('本地头像路径已保存: ${localAvatar.value}'); } else { // 如果本地头像为空,清除存储中的路径 await _storage.remove('local_avatar'); Logger().d('本地头像路径已清除'); } Logger().d('所有状态已同步到本地存储'); } catch (e) { Logger().e('同步本地存储失败: $e'); } } // 更新用户头像 Future updateUserAvatar() async { final XFile? image = await _picker.pickImage( source: ImageSource.gallery, // 从相册选择 maxWidth: 800, maxHeight: 800, imageQuality: 85, ); if (image != null) { try { // 保存当前状态用于可能的回滚 _saveOriginalState(); // 检查文件大小 final file = File(image.path); var fileSize = await file.length(); var quality = 85; // 如果文件大于1MB,进行压缩 while (fileSize > 1024 * 1024 && quality > 30) { final compressedImage = await FlutterImageCompress.compressAndGetFile( file.absolute.path, file.absolute.path, // 覆盖原文件 quality: quality, minWidth: 800, minHeight: 800, ); if (compressedImage == null) { Get.snackbar('error'.tr, 'imageCompressionFailed'.tr); //图片压缩失败 return; } //更新文件大小和质量 fileSize = await compressedImage.length(); quality -= 5; Logger().d('压缩后文件大小:$fileSize'); } // 乐观更新:立即更新UI userInfo.update((user) { if (user != null) { user.avatar = image.path; } }); // 更新本地头像路径 localAvatar.value = image.path; await _storage.write('local_avatar', image.path); hasEdits.value = true; //表示有编辑 Logger().d('头像已乐观更新,等待用户保存'); } catch (e) { Logger().e('更新头像失败: $e'); final errorMessage = _getErrorMessage(e); Get.snackbar( 'avatarUpdateFailed'.tr, errorMessage, duration: const Duration(seconds: 3), snackPosition: SnackPosition.TOP, ); //头像更新失败 // 发生错误时回滚状态 await _rollbackToOriginalState(); } } } // 更新用户名和头像(保存操作) Future updateUserNameAndAvatar(String name) async { if (name.trim().isEmpty) { Logger().e('无效名称: $name'); Get.snackbar('error'.tr, 'usernameCannotBeEmpty'.tr); //用户名不能为空 return; } // 显示加载状态 isUpdating.value = true; try { Logger().d('开始保存用户信息 - 名称: ${name.trim()}, 本地头像: ${localAvatar.value}'); // 同步到后端 await _syncWithBackend(); // 同步成功后更新原始状态和本地存储 _saveOriginalState(); await _syncLocalStorage(); // 同步更新 SettingsController if (Get.isRegistered()) { final settingsController = Get.find(); settingsController.userInfo.value.name = userInfo.value.name; settingsController.userInfo.value.avatar = '${userInfo.value.avatar}?time=${DateTime.now().millisecondsSinceEpoch}'; settingsController.userInfo.refresh(); } // 重置编辑状态 hasEdits.value = false; Logger().d('用户信息保存成功'); // 显示成功提示 Get.snackbar( 'saveSuccess'.tr, 'personalInfoUpdated'.tr, duration: const Duration(seconds: 3), snackPosition: SnackPosition.TOP, backgroundColor: Colors.green.withOpacity(0.1), colorText: Colors.green.shade700, icon: Icon( Icons.check_circle_outline, color: Colors.green.shade700, ), margin: const EdgeInsets.all(16), borderRadius: 8, isDismissible: true, forwardAnimationCurve: Curves.easeOutBack, ); //个人信息更新成功 Logger().d('成功提示已显示'); // 备用成功提示机制 - 使用ScaffoldMessenger确保用户看到 Future.delayed(const Duration(milliseconds: 100), () { if (Get.context != null) { ScaffoldMessenger.of(Get.context!).showSnackBar( SnackBar( content: Row( children: [ Icon(Icons.check_circle, color: Colors.white), SizedBox(width: 8), Text('personalInfoUpdated'.tr), ], ), backgroundColor: Colors.green, duration: Duration(seconds: 2), behavior: SnackBarBehavior.floating, ), ); } }); } catch (e) { Logger().e('更新用户名和头像错误: $e'); // 同步失败时回滚到原始状态 await _rollbackToOriginalState(); // 显示错误提示 final errorMessage = _getErrorMessage(e); Get.snackbar( 'saveFailed'.tr, errorMessage, duration: const Duration(seconds: 4), snackPosition: SnackPosition.TOP, ); //保存失败 } finally { // 隐藏加载状态 isUpdating.value = false; } } // 退出登录 Future signOut() async { try { // 显示加载提示 Get.dialog( const Center(child: CircularProgressIndicator()), barrierDismissible: false, ); // 调用账号服务执行登出 final result = await _accountService.signOut(); // 关闭加载提示 Get.back(); if (result.success) { // 先显示成功提示 Get.snackbar('success'.tr, result.message ?? 'loggedOut'.tr); //已退出登录 Logger().d('退出登录成功'); // 然后导航到登录页面 if (Get.currentRoute != Routes.login) { await Get.offAllNamed(Routes.login); } } else { Get.snackbar('error'.tr, result.errorMessage ?? 'logoutFailedRetry'.tr); //退出登录失败,请重试 Logger().e('退出登录失败: ${result.errorMessage}'); } } catch (e) { // 确保加载提示被关闭 if (Get.isDialogOpen ?? false) { Get.back(); } Get.snackbar('error'.tr, 'logoutFailedRetry'.tr); //退出登录失败,请重试 Logger().e('退出登录错误: $e'); } } // 注销账号 Future deleteAccount() async { try { // 显示加载提示 Get.dialog( const Center(child: CircularProgressIndicator()), barrierDismissible: false, ); // 调用账号服务执行账号删除 final result = await _accountService.deleteAccount(); // 关闭加载提示 Get.back(); if (result.success) { // 先显示成功提示 Get.snackbar('success'.tr, result.message ?? 'accountPermanentlyDeleted'.tr); //账号已被永久删除 Logger().d('账号删除成功'); // 然后导航到登录页面 if (Get.currentRoute != Routes.login) { await Get.offAllNamed(Routes.login); } } else { Get.snackbar('error'.tr, result.errorMessage ?? 'deleteAccountFailedRetry'.tr); //删除账号失败,请重试 Logger().e('删除账号失败: ${result.errorMessage}'); } } catch (e) { // 确保加载提示被关闭 if (Get.isDialogOpen ?? false) { Get.back(); } Get.snackbar('error'.tr, 'deleteAccountFailedRetry'.tr); //删除账号失败,请重试 Logger().e('删除账号失败: $e'); } } }