feat(ui): 게임 화면 및 설정 화면 개선

- GamePlayScreen 개선
- GameSessionController 확장
- MobileCarouselLayout 기능 추가
- SettingsScreen 테스트 기능 추가
This commit is contained in:
JiWoong Sul
2026-01-12 20:02:54 +09:00
parent 12f195bed7
commit 1d855b64a2
5 changed files with 275 additions and 32 deletions

View File

@@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:asciineverdie/data/game_text_l10n.dart' as game_l10n;
@@ -15,6 +16,7 @@ class SettingsScreen extends StatefulWidget {
this.onLocaleChange,
this.onBgmVolumeChange,
this.onSfxVolumeChange,
this.onCreateTestCharacter,
});
final SettingsRepository settingsRepository;
@@ -28,6 +30,11 @@ class SettingsScreen extends StatefulWidget {
/// SFX 볼륨 변경 콜백 (AudioService 연동용)
final void Function(double volume)? onSfxVolumeChange;
/// 테스트 캐릭터 생성 콜백 (디버그 모드 전용)
///
/// 현재 캐릭터를 레벨 100으로 만들어 명예의 전당에 등록하고 세이브 삭제
final Future<void> Function()? onCreateTestCharacter;
@override
State<SettingsScreen> createState() => _SettingsScreenState();
@@ -40,6 +47,7 @@ class SettingsScreen extends StatefulWidget {
void Function(String locale)? onLocaleChange,
void Function(double volume)? onBgmVolumeChange,
void Function(double volume)? onSfxVolumeChange,
Future<void> Function()? onCreateTestCharacter,
}) {
return showModalBottomSheet<void>(
context: context,
@@ -57,6 +65,7 @@ class SettingsScreen extends StatefulWidget {
onLocaleChange: onLocaleChange,
onBgmVolumeChange: onBgmVolumeChange,
onSfxVolumeChange: onSfxVolumeChange,
onCreateTestCharacter: onCreateTestCharacter,
),
),
);
@@ -180,6 +189,13 @@ class _SettingsScreenState extends State<SettingsScreen> {
// 정보
_buildSectionTitle(game_l10n.uiAbout),
_buildAboutCard(),
// 디버그 섹션 (디버그 모드에서만 표시)
if (kDebugMode && widget.onCreateTestCharacter != null) ...[
const SizedBox(height: 24),
_buildSectionTitle('Debug'),
_buildDebugSection(),
],
],
),
),
@@ -188,6 +204,90 @@ class _SettingsScreenState extends State<SettingsScreen> {
);
}
Widget _buildDebugSection() {
return Card(
color: Theme.of(context).colorScheme.errorContainer.withValues(alpha: 0.3),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.bug_report,
color: Theme.of(context).colorScheme.error,
),
const SizedBox(width: 8),
Text(
'Developer Tools',
style: Theme.of(context).textTheme.titleSmall?.copyWith(
color: Theme.of(context).colorScheme.error,
),
),
],
),
const SizedBox(height: 12),
Text(
'현재 캐릭터를 레벨 100으로 수정하여 명예의 전당에 등록합니다. '
'등록 후 현재 세이브 파일이 삭제됩니다.',
style: Theme.of(context).textTheme.bodySmall,
),
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: _handleCreateTestCharacter,
icon: const Icon(Icons.science),
label: const Text('Create Test Character'),
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.error,
foregroundColor: Theme.of(context).colorScheme.onError,
),
),
),
],
),
),
);
}
Future<void> _handleCreateTestCharacter() async {
// 확인 다이얼로그 표시
final confirmed = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Create Test Character?'),
content: const Text(
'현재 캐릭터가 레벨 100으로 변환되어 명예의 전당에 등록됩니다.\n\n'
'⚠️ 현재 세이브 파일이 삭제됩니다.\n'
'이 작업은 되돌릴 수 없습니다.',
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: const Text('Cancel'),
),
ElevatedButton(
onPressed: () => Navigator.of(context).pop(true),
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.error,
foregroundColor: Theme.of(context).colorScheme.onError,
),
child: const Text('Create'),
),
],
),
);
if (confirmed == true && mounted) {
await widget.onCreateTestCharacter?.call();
if (mounted) {
Navigator.of(context).pop(); // 설정 화면 닫기
}
}
}
Widget _buildSectionTitle(String title) {
return Padding(
padding: const EdgeInsets.only(bottom: 8),