From c95fb7f4b4e1285a1edae41749aa6b18a9054d71 Mon Sep 17 00:00:00 2001 From: JiWoong Sul Date: Fri, 16 Jan 2026 20:10:08 +0900 Subject: [PATCH] =?UTF-8?q?feat(ui):=20=EC=8A=A4=ED=94=BC=EB=93=9C=20?= =?UTF-8?q?=EB=B6=80=EC=8A=A4=ED=8A=B8=20=EB=B2=84=ED=8A=BC=20=EC=9C=84?= =?UTF-8?q?=EC=A0=AF=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5배속 버프 활성화 버튼 - 광고 시청으로 버프 획득 - 남은 시간 표시 --- .../game/widgets/speed_boost_button.dart | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 lib/src/features/game/widgets/speed_boost_button.dart diff --git a/lib/src/features/game/widgets/speed_boost_button.dart b/lib/src/features/game/widgets/speed_boost_button.dart new file mode 100644 index 0000000..2206edf --- /dev/null +++ b/lib/src/features/game/widgets/speed_boost_button.dart @@ -0,0 +1,156 @@ +import 'package:flutter/material.dart'; + +import 'package:asciineverdie/data/game_text_l10n.dart' as l10n; +import 'package:asciineverdie/src/core/engine/iap_service.dart'; +import 'package:asciineverdie/src/shared/retro_colors.dart'; + +/// 속도 부스트 버튼 위젯 (Phase 6) +/// +/// 게임 화면에 표시되는 속도 부스트 활성화 버튼 +class SpeedBoostButton extends StatelessWidget { + const SpeedBoostButton({ + super.key, + required this.isActive, + required this.remainingSeconds, + required this.onActivate, + this.boostMultiplier = 10, + }); + + /// 부스트 활성화 여부 + final bool isActive; + + /// 남은 시간 (초) + final int remainingSeconds; + + /// 부스트 배율 + final int boostMultiplier; + + /// 활성화 콜백 + final VoidCallback onActivate; + + @override + Widget build(BuildContext context) { + final isPaidUser = IAPService.instance.isAdRemovalPurchased; + final gold = RetroColors.goldOf(context); + final goldDark = RetroColors.goldDarkOf(context); + final expColor = RetroColors.expOf(context); + + // 부스트 활성화 중일 때 + if (isActive) { + return _buildActiveButton(context, expColor); + } + + // 부스트 비활성화 상태 + return _buildInactiveButton(context, gold, goldDark, isPaidUser); + } + + Widget _buildActiveButton(BuildContext context, Color expColor) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: expColor.withValues(alpha: 0.3), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: expColor, width: 2), + boxShadow: [ + BoxShadow( + color: expColor.withValues(alpha: 0.5), + blurRadius: 8, + spreadRadius: 1, + ), + ], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + '⚡', + style: TextStyle(fontSize: 18, color: expColor), + ), + const SizedBox(width: 4), + Text( + '${boostMultiplier}x', + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 14, + color: expColor, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + const SizedBox(height: 4), + Text( + l10n.speedBoostRemaining(remainingSeconds), + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 10, + color: expColor.withValues(alpha: 0.8), + ), + ), + ], + ), + ); + } + + Widget _buildInactiveButton( + BuildContext context, + Color gold, + Color goldDark, + bool isPaidUser, + ) { + return GestureDetector( + onTap: onActivate, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: gold.withValues(alpha: 0.2), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: gold, width: 2), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + '⚡', + style: TextStyle(fontSize: 18, color: gold), + ), + const SizedBox(width: 4), + Text( + '${boostMultiplier}x', + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 12, + color: gold, + ), + ), + // 광고 아이콘 (무료 유저만) + if (!isPaidUser) ...[ + const SizedBox(width: 6), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 4, + vertical: 2, + ), + decoration: BoxDecoration( + color: Colors.white.withValues(alpha: 0.2), + borderRadius: BorderRadius.circular(4), + ), + child: const Text( + 'AD', + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 8, + color: Colors.white, + ), + ), + ), + ], + ], + ), + ), + ); + } +}