From af837fde8a6accbc5be802c225403899661620a9 Mon Sep 17 00:00:00 2001 From: JiWoong Sul Date: Tue, 30 Dec 2025 19:03:43 +0900 Subject: [PATCH] =?UTF-8?q?feat(theme):=20=EC=95=B1=20=ED=85=8C=EB=A7=88?= =?UTF-8?q?=20=EB=A0=88=ED=8A=B8=EB=A1=9C=20=EC=8A=A4=ED=83=80=EC=9D=BC=20?= =?UTF-8?q?=ED=99=95=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 라이트/다크 테마 모두 레트로 색상 적용 - 다이얼로그, 바텀시트 테마 추가 - 슬라이더, 스위치 테마 커스터마이징 - 입력 필드 테마 추가 --- lib/src/app.dart | 199 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 185 insertions(+), 14 deletions(-) diff --git a/lib/src/app.dart b/lib/src/app.dart index 657636f..0bebeb9 100644 --- a/lib/src/app.dart +++ b/lib/src/app.dart @@ -381,23 +381,73 @@ class _AskiiNeverDieAppState extends State { } } -/// 스플래시 화면 (세이브 파일 확인 중) +/// 스플래시 화면 (세이브 파일 확인 중) - 레트로 스타일 class _SplashScreen extends StatelessWidget { const _SplashScreen(); @override Widget build(BuildContext context) { - return const Scaffold( + return Scaffold( + backgroundColor: RetroColors.deepBrown, body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( - 'ASCII NEVER DIE', - style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), + // 타이틀 로고 + Container( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), + decoration: BoxDecoration( + color: RetroColors.panelBg, + border: Border.all(color: RetroColors.gold, width: 3), + ), + child: Column( + children: [ + // 아이콘 + const Icon( + Icons.auto_awesome, + size: 32, + color: RetroColors.gold, + ), + const SizedBox(height: 12), + // 타이틀 + const Text( + 'ASCII', + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 20, + color: RetroColors.gold, + shadows: [ + Shadow( + color: RetroColors.goldDark, + offset: Offset(2, 2), + ), + ], + ), + ), + const SizedBox(height: 4), + const Text( + 'NEVER DIE', + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 14, + color: RetroColors.cream, + shadows: [ + Shadow( + color: RetroColors.brown, + offset: Offset(1, 1), + ), + ], + ), + ), + ], + ), + ), + const SizedBox(height: 32), + // 레트로 로딩 바 + SizedBox( + width: 160, + child: _RetroLoadingBar(), ), - SizedBox(height: 16), - CircularProgressIndicator(), ], ), ), @@ -405,7 +455,7 @@ class _SplashScreen extends StatelessWidget { } } -/// 자동 로드 화면 (세이브 파일 자동 로드) +/// 자동 로드 화면 (세이브 파일 자동 로드) - 레트로 스타일 class _AutoLoadScreen extends StatefulWidget { const _AutoLoadScreen({ required this.controller, @@ -460,21 +510,142 @@ class _AutoLoadScreenState extends State<_AutoLoadScreen> { @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: RetroColors.deepBrown, body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - const Text( - 'ASCII NEVER DIE', - style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), + // 타이틀 로고 + Container( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), + decoration: BoxDecoration( + color: RetroColors.panelBg, + border: Border.all(color: RetroColors.gold, width: 3), + ), + child: Column( + children: [ + // 아이콘 + const Icon( + Icons.auto_awesome, + size: 32, + color: RetroColors.gold, + ), + const SizedBox(height: 12), + // 타이틀 + const Text( + 'ASCII', + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 20, + color: RetroColors.gold, + shadows: [ + Shadow( + color: RetroColors.goldDark, + offset: Offset(2, 2), + ), + ], + ), + ), + const SizedBox(height: 4), + const Text( + 'NEVER DIE', + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 14, + color: RetroColors.cream, + shadows: [ + Shadow( + color: RetroColors.brown, + offset: Offset(1, 1), + ), + ], + ), + ), + ], + ), + ), + const SizedBox(height: 32), + // 레트로 로딩 바 + SizedBox( + width: 160, + child: _RetroLoadingBar(), ), const SizedBox(height: 16), - const CircularProgressIndicator(), - const SizedBox(height: 16), - Text(game_l10n.uiLoading), + // 로딩 텍스트 + Text( + game_l10n.uiLoading, + style: const TextStyle( + fontFamily: 'PressStart2P', + fontSize: 8, + color: RetroColors.textDisabled, + ), + ), ], ), ), ); } } + +/// 레트로 스타일 로딩 바 (애니메이션) +class _RetroLoadingBar extends StatefulWidget { + @override + State<_RetroLoadingBar> createState() => _RetroLoadingBarState(); +} + +class _RetroLoadingBarState extends State<_RetroLoadingBar> + with SingleTickerProviderStateMixin { + late AnimationController _controller; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + duration: const Duration(milliseconds: 1500), + vsync: this, + )..repeat(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + const segmentCount = 10; + + return AnimatedBuilder( + animation: _controller, + builder: (context, child) { + // 웨이브 효과: 각 세그먼트가 순차적으로 켜지고 꺼짐 + return Container( + height: 16, + decoration: BoxDecoration( + color: RetroColors.panelBg, + border: Border.all(color: RetroColors.panelBorderOuter, width: 2), + ), + child: Row( + children: List.generate(segmentCount, (index) { + // 웨이브 패턴 계산 + final progress = _controller.value * segmentCount; + final distance = (index - progress).abs(); + final isLit = distance < 2 || (segmentCount - distance) < 2; + final opacity = isLit ? 1.0 : 0.2; + + return Expanded( + child: Container( + margin: const EdgeInsets.all(1), + decoration: BoxDecoration( + color: RetroColors.gold.withValues(alpha: opacity), + ), + ), + ); + }), + ), + ); + }, + ); + } +}