feat(mobile): 모바일 옵션 메뉴에 통계/도움말 추가 및 오버플로우 수정

- MobileCarouselLayout에 onShowStatistics, onShowHelp 콜백 추가
- 옵션 메뉴에 통계, 도움말 메뉴 항목 추가
- SingleChildScrollView로 메뉴 오버플로우 방지
- isScrollControlled와 maxHeight 제약 조건 적용
This commit is contained in:
JiWoong Sul
2025-12-30 16:19:36 +09:00
parent 05a8c03892
commit 0ee6ef8493
2 changed files with 46 additions and 3 deletions

View File

@@ -745,6 +745,9 @@ class _GamePlayScreenState extends State<GamePlayScreen>
setState(() => _sfxVolume = volume); setState(() => _sfxVolume = volume);
widget.audioService?.setSfxVolume(volume); widget.audioService?.setSfxVolume(volume);
}, },
// 통계 및 도움말
onShowStatistics: () => _showStatisticsDialog(context),
onShowHelp: () => HelpDialog.show(context),
), ),
// 사망 오버레이 // 사망 오버레이
if (state.isDead && state.deathInfo != null) if (state.isDead && state.deathInfo != null)

View File

@@ -43,6 +43,8 @@ class MobileCarouselLayout extends StatefulWidget {
this.sfxVolume = 0.8, this.sfxVolume = 0.8,
this.onBgmVolumeChange, this.onBgmVolumeChange,
this.onSfxVolumeChange, this.onSfxVolumeChange,
this.onShowStatistics,
this.onShowHelp,
}); });
final GameState state; final GameState state;
@@ -72,6 +74,12 @@ class MobileCarouselLayout extends StatefulWidget {
/// SFX 볼륨 변경 콜백 /// SFX 볼륨 변경 콜백
final void Function(double volume)? onSfxVolumeChange; final void Function(double volume)? onSfxVolumeChange;
/// 통계 표시 콜백
final VoidCallback? onShowStatistics;
/// 도움말 표시 콜백
final VoidCallback? onShowHelp;
@override @override
State<MobileCarouselLayout> createState() => _MobileCarouselLayoutState(); State<MobileCarouselLayout> createState() => _MobileCarouselLayoutState();
} }
@@ -349,10 +357,15 @@ class _MobileCarouselLayoutState extends State<MobileCarouselLayout> {
showModalBottomSheet<void>( showModalBottomSheet<void>(
context: context, context: context,
isScrollControlled: true,
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.7,
),
builder: (context) => SafeArea( builder: (context) => SafeArea(
child: Column( child: SingleChildScrollView(
mainAxisSize: MainAxisSize.min, child: Column(
children: [ mainAxisSize: MainAxisSize.min,
children: [
// 헤더 // 헤더
Container( Container(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
@@ -410,6 +423,32 @@ class _MobileCarouselLayoutState extends State<MobileCarouselLayout> {
}, },
), ),
const Divider(),
// 통계
if (widget.onShowStatistics != null)
ListTile(
leading: const Icon(Icons.bar_chart, color: Colors.blue),
title: Text(l10n.uiStatistics),
onTap: () {
Navigator.pop(context);
widget.onShowStatistics?.call();
},
),
// 도움말
if (widget.onShowHelp != null)
ListTile(
leading: const Icon(Icons.help_outline, color: Colors.green),
title: Text(l10n.uiHelp),
onTap: () {
Navigator.pop(context);
widget.onShowHelp?.call();
},
),
const Divider(),
// 언어 변경 // 언어 변경
ListTile( ListTile(
leading: const Icon(Icons.language, color: Colors.teal), leading: const Icon(Icons.language, color: Colors.teal),
@@ -506,6 +545,7 @@ class _MobileCarouselLayoutState extends State<MobileCarouselLayout> {
const SizedBox(height: 8), const SizedBox(height: 8),
], ],
), ),
),
), ),
); );
} }