// packages/service_api/lib/services/identity_service.dart import 'dart:convert'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:uuid/uuid.dart'; class UserSession { final String userId; final String? userName; final String loginProvider; final String? email; UserSession({ required this.userId, this.userName, this.loginProvider = "guest", this.email, }); bool get isGuest => loginProvider == "guest"; } class IdentityService { static const String _userIdKey = 'app_user_id'; static const String _userNameKey = 'app_user_name'; static const String _loginProviderKey = 'app_login_provider'; static const String _userEmailKey = 'app_user_email'; // 기존 게임 키들 static const String _sudokuMaxLevelKey = 'max_unlocked_level'; static const String _sudokuRankMapKey = 'last_checked_rank_map'; static const String _spiderMaxLevelKey = 'max_unlocked_spider_level'; static const String _spiderRankMapKey = 'last_checked_spider_rank_map'; static const String _mathQuizMaxLevelKey = 'max_unlocked_mathquiz_level'; static const String _mathQuizRankMapKey = 'last_checked_mathquiz_rank_map'; static const String _colorMatchMaxLevelKey = 'max_unlocked_colormatch_level'; static const String _colorMatchRankMapKey = 'last_checked_colormatch_rank_map'; static const String _sequenceMaxLevelKey = 'max_unlocked_sequence_level'; static const String _sequenceRankMapKey = 'last_checked_sequence_rank_map'; static const String _cardFlipMaxLevelKey = 'max_unlocked_cardflip_level'; static const String _cardFlipRankMapKey = 'last_checked_cardflip_rank_map'; // 🔽 [🔥 신규] 다른 그림 찾기 키 추가 static const String _findDiffMaxLevelKey = 'max_unlocked_finddiff_level'; static const String _findDiffRankMapKey = 'last_checked_finddiff_rank_map'; final _storage = const FlutterSecureStorage(); IOSOptions _getIOSOptions() => const IOSOptions(); AndroidOptions _getAndroidOptions() => const AndroidOptions(encryptedSharedPreferences: true); Future getUserSession() async { final userId = await getOrCreateUserId(); final userName = await getSavedUserName(); final loginProvider = await _storage.read(key: _loginProviderKey, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()) ?? "guest"; final email = await _storage.read(key: _userEmailKey, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); return UserSession(userId: userId, userName: userName, loginProvider: loginProvider, email: email); } Future getOrCreateUserId() async { String? userId = await _storage.read(key: _userIdKey, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); if (userId == null) { userId = const Uuid().v4(); await _storage.write(key: _userIdKey, value: userId, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); } return userId; } Future getSavedUserName() async { return await _storage.read(key: _userNameKey, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); } Future saveUserName(String name) async { await _storage.write(key: _userNameKey, value: name, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); } Future saveSocialLogin({required String newUserId, required String newUserName, required String newEmail, required String provider}) async { await _storage.write(key: _userIdKey, value: newUserId, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); await _storage.write(key: _userNameKey, value: newUserName, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); await _storage.write(key: _userEmailKey, value: newEmail, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); await _storage.write(key: _loginProviderKey, value: provider, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); return UserSession(userId: newUserId, userName: newUserName, loginProvider: provider, email: newEmail); } Future logout() async { await _storage.delete(key: _userNameKey, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); await _storage.delete(key: _userEmailKey, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); await _storage.delete(key: _loginProviderKey, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); return await getUserSession(); } // 7. [수정] 최대 레벨 가져오기 Future getMaxUnlockedLevel({String gameType = 'SUDOKU'}) async { String key; switch (gameType) { case 'SPIDER': key = _spiderMaxLevelKey; break; case 'MATH_QUIZ': key = _mathQuizMaxLevelKey; break; case 'COLOR_MATCH': key = _colorMatchMaxLevelKey; break; case 'SEQUENCE': key = _sequenceMaxLevelKey; break; case 'CARD_FLIP': key = _cardFlipMaxLevelKey; break; case 'FIND_DIFF': key = _findDiffMaxLevelKey; break; // 👈 추가 default: key = _sudokuMaxLevelKey; } String? levelString = await _storage.read(key: key, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); return int.parse(levelString ?? '1'); } // 8. [수정] 최대 레벨 저장하기 Future saveMaxUnlockedLevel(int level, {String gameType = 'SUDOKU'}) async { String key; switch (gameType) { case 'SPIDER': key = _spiderMaxLevelKey; break; case 'MATH_QUIZ': key = _mathQuizMaxLevelKey; break; case 'COLOR_MATCH': key = _colorMatchMaxLevelKey; break; case 'SEQUENCE': key = _sequenceMaxLevelKey; break; case 'CARD_FLIP': key = _cardFlipMaxLevelKey; break; case 'FIND_DIFF': key = _findDiffMaxLevelKey; break; // 👈 추가 default: key = _sudokuMaxLevelKey; } await _storage.write(key: key, value: level.toString(), iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); } // 9. [수정] 마지막 랭킹 맵 가져오기 Future> getLastSavedRankMap({String gameType = 'SUDOKU'}) async { String key; switch (gameType) { case 'SPIDER': key = _spiderRankMapKey; break; case 'MATH_QUIZ': key = _mathQuizRankMapKey; break; case 'COLOR_MATCH': key = _colorMatchRankMapKey; break; case 'SEQUENCE': key = _sequenceRankMapKey; break; case 'CARD_FLIP': key = _cardFlipRankMapKey; break; case 'FIND_DIFF': key = _findDiffRankMapKey; break; // 👈 추가 default: key = _sudokuRankMapKey; } String? jsonString = await _storage.read(key: key, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); if (jsonString == null) return {}; try { final Map decodedMap = jsonDecode(jsonString); return decodedMap.map((key, value) => MapEntry(int.parse(key), value as int)); } catch (e) { return {}; } } // 10. [수정] 마지막 랭킹 맵 저장하기 Future saveLastRankMap(Map rankMap, {String gameType = 'SUDOKU'}) async { String key; switch (gameType) { case 'SPIDER': key = _spiderRankMapKey; break; case 'MATH_QUIZ': key = _mathQuizRankMapKey; break; case 'COLOR_MATCH': key = _colorMatchRankMapKey; break; case 'SEQUENCE': key = _sequenceRankMapKey; break; case 'CARD_FLIP': key = _cardFlipRankMapKey; break; case 'FIND_DIFF': key = _findDiffRankMapKey; break; // 👈 추가 default: key = _sudokuRankMapKey; } final Map stringKeyMap = rankMap.map((key, value) => MapEntry(key.toString(), value)); String jsonString = jsonEncode(stringKeyMap); await _storage.write(key: key, value: jsonString, iOptions: _getIOSOptions(), aOptions: _getAndroidOptions()); } }