feat(ui): 반응형 레이아웃 및 저장 시스템 개선

## 반응형 레이아웃
- app.dart: 화면 크기별 레이아웃 분기 로직 추가 (+173 라인)
- game_play_screen.dart: 반응형 UI 구조 개선
- layouts/, pages/ 디렉토리 추가 (새 레이아웃 시스템)
- carousel_nav_bar.dart: 캐러셀 네비게이션 바 추가
- enhanced_animation_panel.dart: 향상된 애니메이션 패널

## 저장 시스템
- save_manager.dart: 저장 관리 기능 확장
- save_repository.dart: 저장소 인터페이스 개선
- save_service.dart: 저장 서비스 로직 추가

## UI 개선
- notification_service.dart: 알림 시스템 기능 확장
- notification_overlay.dart: 오버레이 UI 개선
- equipment_stats_panel.dart: 장비 스탯 패널 개선
- cinematic_view.dart: 시네마틱 뷰 개선
- new_character_screen.dart: 캐릭터 생성 화면 개선

## 다국어
- game_text_l10n.dart: 텍스트 추가 (+182 라인)

## 테스트
- 관련 테스트 파일 업데이트
This commit is contained in:
JiWoong Sul
2025-12-23 17:52:43 +09:00
parent 1da6fa7a2b
commit e6af7dd91a
28 changed files with 2734 additions and 73 deletions

View File

@@ -8,6 +8,9 @@ enum NotificationType {
newSpell, // 새 주문 습득
newEquipment, // 새 장비 획득
bossDefeat, // 보스 처치
gameSaved, // 게임 저장됨
info, // 일반 정보
warning, // 경고
}
/// 게임 알림 데이터 (Game Notification)
@@ -134,6 +137,41 @@ class NotificationService {
);
}
/// 게임 저장 완료 알림 (Game Saved)
void showGameSaved(String message) {
show(
GameNotification(
type: NotificationType.gameSaved,
title: message,
duration: const Duration(seconds: 2),
),
);
}
/// 일반 정보 알림 (Info)
void showInfo(String message, {String? subtitle}) {
show(
GameNotification(
type: NotificationType.info,
title: message,
subtitle: subtitle,
duration: const Duration(seconds: 2),
),
);
}
/// 경고 알림 (Warning)
void showWarning(String message, {String? subtitle}) {
show(
GameNotification(
type: NotificationType.warning,
title: message,
subtitle: subtitle,
duration: const Duration(seconds: 3),
),
);
}
/// 큐 처리 (Process Queue)
void _processQueue() {
if (_isShowing || _queue.isEmpty) return;

View File

@@ -30,4 +30,14 @@ class SaveManager {
/// 저장 파일 목록 조회
Future<List<SaveFileInfo>> listSaves() => _repo.listSaves();
/// 저장 파일 삭제
Future<SaveOutcome> deleteSave({String? fileName}) {
return _repo.deleteSave(fileName ?? defaultFileName);
}
/// 저장 파일 존재 여부 확인
Future<bool> saveExists({String? fileName}) {
return _repo.saveExists(fileName ?? defaultFileName);
}
}

View File

@@ -61,4 +61,28 @@ class SaveRepository {
return [];
}
}
/// 저장 파일 삭제
Future<SaveOutcome> deleteSave(String fileName) async {
try {
await _ensureService();
await _service!.deleteSave(fileName);
return const SaveOutcome.success();
} on FileSystemException catch (e) {
final reason = e.osError?.message ?? e.message;
return SaveOutcome.failure('Unable to delete save: $reason');
} catch (e) {
return SaveOutcome.failure(e.toString());
}
}
/// 저장 파일 존재 여부 확인
Future<bool> saveExists(String fileName) async {
try {
await _ensureService();
return await _service!.exists(fileName);
} catch (e) {
return false;
}
}
}

View File

@@ -37,6 +37,22 @@ class SaveService {
return '${baseDir.path}/$normalized';
}
/// 저장 파일 삭제
Future<void> deleteSave(String fileName) async {
final path = _resolvePath(fileName);
final file = File(path);
if (await file.exists()) {
await file.delete();
}
}
/// 저장 파일 존재 여부 확인
Future<bool> exists(String fileName) async {
final path = _resolvePath(fileName);
final file = File(path);
return file.exists();
}
/// 저장 디렉토리의 모든 .pqf 파일 목록 반환
Future<List<SaveFileInfo>> listSaves() async {
if (!await baseDir.exists()) {