From 0ee6ef8493dfb694b94092d2671b5de99b2d3755 Mon Sep 17 00:00:00 2001 From: JiWoong Sul Date: Tue, 30 Dec 2025 16:19:36 +0900 Subject: [PATCH] =?UTF-8?q?feat(mobile):=20=EB=AA=A8=EB=B0=94=EC=9D=BC=20?= =?UTF-8?q?=EC=98=B5=EC=85=98=20=EB=A9=94=EB=89=B4=EC=97=90=20=ED=86=B5?= =?UTF-8?q?=EA=B3=84/=EB=8F=84=EC=9B=80=EB=A7=90=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20=EC=98=A4=EB=B2=84=ED=94=8C=EB=A1=9C=EC=9A=B0=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - MobileCarouselLayout에 onShowStatistics, onShowHelp 콜백 추가 - 옵션 메뉴에 통계, 도움말 메뉴 항목 추가 - SingleChildScrollView로 메뉴 오버플로우 방지 - isScrollControlled와 maxHeight 제약 조건 적용 --- lib/src/features/game/game_play_screen.dart | 3 ++ .../game/layouts/mobile_carousel_layout.dart | 46 +++++++++++++++++-- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/lib/src/features/game/game_play_screen.dart b/lib/src/features/game/game_play_screen.dart index 4e19868..7a2670f 100644 --- a/lib/src/features/game/game_play_screen.dart +++ b/lib/src/features/game/game_play_screen.dart @@ -745,6 +745,9 @@ class _GamePlayScreenState extends State setState(() => _sfxVolume = volume); widget.audioService?.setSfxVolume(volume); }, + // 통계 및 도움말 + onShowStatistics: () => _showStatisticsDialog(context), + onShowHelp: () => HelpDialog.show(context), ), // 사망 오버레이 if (state.isDead && state.deathInfo != null) diff --git a/lib/src/features/game/layouts/mobile_carousel_layout.dart b/lib/src/features/game/layouts/mobile_carousel_layout.dart index 1716deb..784950b 100644 --- a/lib/src/features/game/layouts/mobile_carousel_layout.dart +++ b/lib/src/features/game/layouts/mobile_carousel_layout.dart @@ -43,6 +43,8 @@ class MobileCarouselLayout extends StatefulWidget { this.sfxVolume = 0.8, this.onBgmVolumeChange, this.onSfxVolumeChange, + this.onShowStatistics, + this.onShowHelp, }); final GameState state; @@ -72,6 +74,12 @@ class MobileCarouselLayout extends StatefulWidget { /// SFX 볼륨 변경 콜백 final void Function(double volume)? onSfxVolumeChange; + /// 통계 표시 콜백 + final VoidCallback? onShowStatistics; + + /// 도움말 표시 콜백 + final VoidCallback? onShowHelp; + @override State createState() => _MobileCarouselLayoutState(); } @@ -349,10 +357,15 @@ class _MobileCarouselLayoutState extends State { showModalBottomSheet( context: context, + isScrollControlled: true, + constraints: BoxConstraints( + maxHeight: MediaQuery.of(context).size.height * 0.7, + ), builder: (context) => SafeArea( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ // 헤더 Container( padding: const EdgeInsets.all(16), @@ -410,6 +423,32 @@ class _MobileCarouselLayoutState extends State { }, ), + 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( leading: const Icon(Icons.language, color: Colors.teal), @@ -506,6 +545,7 @@ class _MobileCarouselLayoutState extends State { const SizedBox(height: 8), ], ), + ), ), ); }