import 'dart:convert'; import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../model/user_model.dart'; import '../service/user_service.dart'; import '../tool/encryption_util.dart'; import 'dart:async'; // 必须加这个 class UserProvider with ChangeNotifier { UserModel? _user; String? _token; List _sexTags = []; String _scoreDataSource = 'cn'; String? _selectedSegaId; String? _selectedCnUserName; // ===================== 【新增:初始化等待控制】 ===================== bool _isInitialized = false; Completer? _initCompleter; // 外部等待初始化完成的方法 Future waitInit() async { if (_isInitialized) return; if (_initCompleter == null) { _initCompleter = Completer(); } await _initCompleter!.future; } UserModel? get user => _user; String? get token => _token; bool get isLogin => _token != null && _user != null; String get username => _user?.name ?? "未登录"; List get sexTags => _sexTags; String get scoreDataSource => _scoreDataSource; String? get selectedSegaId => _selectedSegaId; String? get selectedCnUserName => _selectedCnUserName; List get availableSegaCards => _user?.segaCards ?? []; List get availableCnUserNames { final map = _user?.userName2userId; if (map == null || map.isEmpty) return []; return map.keys.toList(); } String get avatarUrl { if (_user?.iconId != null) { return "https://cdn.godserver.cn/resource/static/coll/Icon/UI_Icon_${_user!.iconId!}.png"; } else { return "https://cdn.godserver.cn/resource/static/coll/Icon/UI_Icon_605526.png"; } } static UserProvider? _instance; static UserProvider get instance { _instance ??= UserProvider(); return _instance!; } Future initUser() async { try { final prefs = await SharedPreferences.getInstance(); _token = prefs.getString("token"); _scoreDataSource = prefs.getString("scoreDataSource") ?? 'cn'; _selectedSegaId = prefs.getString("selectedSegaId"); _selectedCnUserName = prefs.getString("selectedCnUserName"); if (_token != null) { try { _user = await UserService.getUserInfo(_token!); await fetchSexTags(); if (_selectedSegaId != null && !availableSegaCards.any((c) => c.segaId == _selectedSegaId)) { _selectedSegaId = null; await prefs.remove("selectedSegaId"); } if (_selectedCnUserName != null && !availableCnUserNames.contains(_selectedCnUserName)) { _selectedCnUserName = null; await prefs.remove("selectedCnUserName"); } } catch (e) { await logout(); } } } finally { // ===================== 【关键:标记初始化完成】 ===================== _isInitialized = true; _initCompleter?.complete(); notifyListeners(); } } Future login(String username, String twoKeyCode) async { try { _token = await UserService.login(username, twoKeyCode); if (_token != null && _token!.isNotEmpty) { final prefs = await SharedPreferences.getInstance(); await prefs.setString("token", _token!); _user = await UserService.getUserInfo(_token!); await fetchSexTags(); } } catch (e) { rethrow; } finally { notifyListeners(); } } Future register(String username, String password, String inviter) async { await UserService.register(username, password, inviter); } Future logout() async { _token = null; _user = null; _selectedSegaId = null; _selectedCnUserName = null; final prefs = await SharedPreferences.getInstance(); await prefs.remove("token"); await prefs.remove("selectedSegaId"); await prefs.remove("selectedCnUserName"); notifyListeners(); } Future saveUserInfo() async { if (_token == null || _user == null) return; try { final userJson = _user!.toJson(); final encrypted = EncryptionUtil.encryptAndCompress(jsonEncode(userJson)); await UserService.updateUser(_token!, encrypted); _user = await UserService.getUserInfo(_token!); notifyListeners(); } catch (e) { rethrow; } } Future refreshToken() async { if (_token == null) return false; try { final newToken = await UserService.refreshToken(_token!); if (newToken != null) { _token = newToken; final prefs = await SharedPreferences.getInstance(); await prefs.setString("token", newToken); notifyListeners(); return true; } } catch (e) { await logout(); } return false; } Future> fetchRadarData(String id) async { if (_token == null) throw "请先登录"; try { return await UserService.getRadarData(_token!, id); } catch (e) { rethrow; } } Future fetchSexTags() async { _sexTags = await UserService.fetchSexTags(); notifyListeners(); } void updateUser(UserModel? newUser) { _user = newUser; notifyListeners(); } Future setScoreDataSource(String source) async { _scoreDataSource = source; final prefs = await SharedPreferences.getInstance(); await prefs.setString("scoreDataSource", source); notifyListeners(); } Future setSelectedSegaId(String? segaId) async { _selectedSegaId = segaId; final prefs = await SharedPreferences.getInstance(); if (segaId != null) { await prefs.setString("selectedSegaId", segaId); } else { await prefs.remove("selectedSegaId"); } notifyListeners(); } Future setSelectedCnUserName(String? userName) async { _selectedCnUserName = userName; final prefs = await SharedPreferences.getInstance(); if (userName != null && userName.isNotEmpty) { await prefs.setString("selectedCnUserName", userName); } else { await prefs.remove("selectedCnUserName"); } notifyListeners(); } Future syncSegaScore(Map data) async { if (_token == null || _user == null) { throw "请先登录"; } if (_selectedSegaId == null || _selectedSegaId!.isEmpty) { throw "请先选择要同步的 SegaID"; } try { final result = await UserService.uploadSegaRating( _token!, _selectedSegaId!, data, ); if (result["code"] == 200) { print("✅ 同步成功:${result["msg"]}"); } else { print("❌ 同步失败:${result["msg"]}"); throw result["msg"] ?? "同步失败"; } } catch (e) { print("❌ 同步异常:$e"); rethrow; } } Future> uploadStegImage(Uint8List imageBytes, {String? segaId}) async { if (_token == null) { throw Exception("请先登录"); } final targetSegaId = segaId ?? _selectedSegaId; if (targetSegaId == null || targetSegaId.isEmpty) { throw Exception("请提供或选择要隐藏的 SegaID"); } try { print("🚀 开始隐写并上传... SegaID: $targetSegaId"); final result = await UserService.uploadStegImage( token: _token!, segaId: targetSegaId, originalImageBytes: imageBytes, ); print("✅ 隐写上传成功: ${result['msg']}"); return result; } catch (e) { print("❌ 隐写上传失败: $e"); rethrow; } } }