import 'dart:convert'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:uuid/uuid.dart'; import '../models/cognitive_type.dart'; import '../models/assessment_data.dart'; // ----------------------------------------------------------------------------- // [Fix] UserSession 정의 및 isGuest 추가 // ----------------------------------------------------------------------------- class UserSession { final String userId; final String? userName; final String? email; final String? photoUrl; final String? provider; // 'google', 'apple', 'guest' UserSession({ required this.userId, this.userName, this.email, this.photoUrl, this.provider, }); // [Fix] 에러 해결: isGuest 게터 추가 bool get isGuest => provider == 'guest' || provider == null; Map toJson() => { 'userId': userId, 'userName': userName, 'email': email, 'photoUrl': photoUrl, 'provider': provider, }; factory UserSession.fromJson(Map json) => UserSession( userId: json['userId'], userName: json['userName'], email: json['email'], photoUrl: json['photoUrl'], provider: json['provider'], ); } // ----------------------------------------------------------------------------- // IdentityService 구현 // ----------------------------------------------------------------------------- class IdentityService { static const String _userIdKey = 'app_user_id'; static const String _userSessionKey = 'app_user_session'; static const String _userNameKey = 'app_user_name'; // 추가 static const String _assessmentHistoryKey = 'cognitive_assessment_history'; final _storage = const FlutterSecureStorage(); final _uuid = const Uuid(); IOSOptions _getIOSOptions() => const IOSOptions(accessibility: KeychainAccessibility.first_unlock); AndroidOptions _getAndroidOptions() => const AndroidOptions(encryptedSharedPreferences: true); // =========================================================================== // 1. 유저 세션 관리 (호환성 복구) // =========================================================================== Future getOrCreateUser() async { String? userId = await _storage.read(key: _userIdKey, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); if (userId == null) { userId = _uuid.v4(); await _storage.write(key: _userIdKey, value: userId, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); } return userId; } /// [Fix] SessionNotifier 에러 해결 Future getUserSession() async { String? jsonStr = await _storage.read(key: _userSessionKey, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); if (jsonStr == null) return null; try { return UserSession.fromJson(jsonDecode(jsonStr)); } catch (e) { return null; } } /// [Fix] SessionNotifier 에러 해결 Future saveSocialLogin({ required String userId, String? email, String? name, String? photoUrl, required String provider, }) async { final session = UserSession( userId: userId, email: email, userName: name, photoUrl: photoUrl, provider: provider, ); await _storage.write( key: _userSessionKey, value: jsonEncode(session.toJson()), iOptions: _getIOSOptions(), aOptions: _getAndroidOptions() ); await _storage.write(key: _userIdKey, value: userId, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); return session; } /// [Fix] SessionNotifier 에러 해결 Future logout() async { await _storage.delete(key: _userSessionKey, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); } /// [Fix] GameCompletionScreen 에러 해결 Future saveUserName(String name) async { await _storage.write(key: _userNameKey, value: name, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); // 세션이 있다면 세션 이름도 업데이트 final currentSession = await getUserSession(); if (currentSession != null) { final newSession = UserSession( userId: currentSession.userId, userName: name, email: currentSession.email, photoUrl: currentSession.photoUrl, provider: currentSession.provider, ); await _storage.write( key: _userSessionKey, value: jsonEncode(newSession.toJson()), iOptions: _getIOSOptions(), aOptions: _getAndroidOptions() ); } } Future getUserName() async { return await _storage.read(key: _userNameKey, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); } // =========================================================================== // 2. 진단 기록 (Assessment) // =========================================================================== Future saveAssessmentResult(Map scores) async { final record = AssessmentRecord( id: _uuid.v4(), date: DateTime.now(), scores: scores, ); final history = await getAssessmentHistory(); history.add(record); final jsonString = jsonEncode(history.map((e) => e.toJson()).toList()); await _storage.write(key: _assessmentHistoryKey, value: jsonString, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); } Future> getAssessmentHistory() async { final jsonString = await _storage.read(key: _assessmentHistoryKey, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); if (jsonString == null) return []; try { final List jsonList = jsonDecode(jsonString); return jsonList.map((e) => AssessmentRecord.fromJson(e)).toList(); } catch (e) { return []; } } /// [Fix] SettingsScreen 에러 해결 Future clearAssessmentHistory() async { await _storage.delete(key: _assessmentHistoryKey, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); } Future?> getCognitiveScores() async { final history = await getAssessmentHistory(); if (history.isEmpty) return null; history.sort((a, b) => b.date.compareTo(a.date)); return history.first.scores; } // =========================================================================== // 3. 게임 데이터 관리 (통합 + 레거시 호환) // =========================================================================== String _getMaxLevelKey(String gameType) => 'max_level_${gameType.toLowerCase()}'; String _getRankMapKey(String gameType) => 'rank_map_${gameType.toLowerCase()}'; Future getMaxUnlockedLevel({String gameType = 'SUDOKU'}) async { final key = _getMaxLevelKey(gameType); String? levelString = await _storage.read(key: key, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); return int.parse(levelString ?? '1'); } /// [Fix] 기존 게임들이 호출하는 메서드 복구 Future saveMaxUnlockedLevel(int level, {String gameType = 'SUDOKU'}) async { await _storage.write( key: _getMaxLevelKey(gameType), value: level.toString(), iOptions: _getIOSOptions(), aOptions: _getAndroidOptions() ); } Future> getLastSavedRankMap({required String gameType}) async { final key = _getRankMapKey(gameType); String? jsonString = await _storage.read(key: key, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); if (jsonString == null) return {}; try { final Map decodedMap = jsonDecode(jsonString); return decodedMap.map((k, v) => MapEntry(int.parse(k), v as int)); } catch (e) { return {}; } } /// [Fix] LobbyHelper 에러 해결 Future saveLastRankMap(Map rankMap, {required String gameType}) async { final String jsonString = jsonEncode(rankMap.map((k, v) => MapEntry(k.toString(), v))); await _storage.write( key: _getRankMapKey(gameType), value: jsonString, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions() ); } /// [신규] 게임 결과 통합 처리 Future submitGameResult({ required String gameType, required int level, required int stars, }) async { final rankMap = await getLastSavedRankMap(gameType: gameType); final int oldStars = rankMap[level] ?? 0; if (stars > oldStars) { rankMap[level] = stars; await saveLastRankMap(rankMap, gameType: gameType); } final int currentMax = await getMaxUnlockedLevel(gameType: gameType); if (level >= currentMax) { await saveMaxUnlockedLevel(level + 1, gameType: gameType); } } }