import 'package:flutter/material.dart'; import 'package:asciineverdie/l10n/app_localizations.dart'; import 'package:asciineverdie/src/shared/retro_colors.dart'; /// 아레나 전투 HP 바 (좌우 대칭 레이아웃) class ArenaHpBars extends StatelessWidget { const ArenaHpBars({ super.key, required this.challengerName, required this.challengerHp, required this.challengerHpMax, required this.challengerFlashAnimation, required this.challengerHpChange, required this.opponentName, required this.opponentHp, required this.opponentHpMax, required this.opponentFlashAnimation, required this.opponentHpChange, }); final String challengerName; final int challengerHp; final int challengerHpMax; final Animation challengerFlashAnimation; final int challengerHpChange; final String opponentName; final int opponentHp; final int opponentHpMax; final Animation opponentFlashAnimation; final int opponentHpChange; @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6), decoration: BoxDecoration( color: RetroColors.panelBgOf(context), border: Border( bottom: BorderSide(color: RetroColors.borderOf(context), width: 2), ), ), child: Row( children: [ Expanded( child: _ArenaHpBar( name: challengerName, hp: challengerHp, hpMax: challengerHpMax, fillColor: RetroColors.mpBlue, accentColor: Colors.blue, flashAnimation: challengerFlashAnimation, hpChange: challengerHpChange, isReversed: false, ), ), Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: Text( 'VS', style: TextStyle( fontFamily: 'PressStart2P', fontSize: 13, color: RetroColors.goldOf(context), fontWeight: FontWeight.bold, ), ), ), Expanded( child: _ArenaHpBar( name: opponentName, hp: opponentHp, hpMax: opponentHpMax, fillColor: RetroColors.hpRed, accentColor: Colors.red, flashAnimation: opponentFlashAnimation, hpChange: opponentHpChange, isReversed: true, ), ), ], ), ); } } /// 레트로 세그먼트 HP 바 (개별) class _ArenaHpBar extends StatelessWidget { const _ArenaHpBar({ required this.name, required this.hp, required this.hpMax, required this.fillColor, required this.accentColor, required this.flashAnimation, required this.hpChange, required this.isReversed, }); final String name; final int hp; final int hpMax; final Color fillColor; final Color accentColor; final Animation flashAnimation; final int hpChange; final bool isReversed; @override Widget build(BuildContext context) { final hpRatio = hpMax > 0 ? hp / hpMax : 0.0; final isLow = hpRatio < 0.2 && hpRatio > 0; return AnimatedBuilder( animation: flashAnimation, builder: (context, child) { final isDamage = hpChange < 0; final flashColor = isDamage ? RetroColors.hpRed.withValues(alpha: flashAnimation.value * 0.4) : RetroColors.expGreen.withValues( alpha: flashAnimation.value * 0.4, ); return Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( color: flashAnimation.value > 0.1 ? flashColor : accentColor.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(4), border: Border.all(color: accentColor, width: 2), ), child: Stack( clipBehavior: Clip.none, children: [ Column( crossAxisAlignment: isReversed ? CrossAxisAlignment.end : CrossAxisAlignment.start, children: [ Text( name, style: TextStyle( fontFamily: 'PressStart2P', fontSize: 11, color: RetroColors.textPrimaryOf(context), ), maxLines: 1, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 4), _buildSegmentBar(context, hpRatio, isLow), const SizedBox(height: 2), Row( mainAxisAlignment: isReversed ? MainAxisAlignment.end : MainAxisAlignment.start, children: [ Text( L10n.of(context).hpLabel, style: TextStyle( fontFamily: 'PressStart2P', fontSize: 12, color: accentColor.withValues(alpha: 0.8), ), ), const SizedBox(width: 4), Text( '$hp/$hpMax', style: TextStyle( fontFamily: 'PressStart2P', fontSize: 12, color: isLow ? RetroColors.hpRed : fillColor, ), ), ], ), ], ), if (hpChange != 0 && flashAnimation.value > 0.05) Positioned( left: isReversed ? null : 0, right: isReversed ? 0 : null, top: -12, child: Transform.translate( offset: Offset(0, -12 * (1 - flashAnimation.value)), child: Opacity( opacity: flashAnimation.value, child: Text( hpChange > 0 ? '+$hpChange' : '$hpChange', style: TextStyle( fontFamily: 'PressStart2P', fontSize: 13, fontWeight: FontWeight.bold, color: isDamage ? RetroColors.hpRed : RetroColors.expGreen, shadows: const [ Shadow(color: Colors.black, blurRadius: 3), Shadow(color: Colors.black, blurRadius: 6), ], ), ), ), ), ), ], ), ); }, ); } /// 세그먼트 바 (8-bit 스타일) Widget _buildSegmentBar(BuildContext context, double ratio, bool isLow) { const segmentCount = 10; final filledSegments = (ratio.clamp(0.0, 1.0) * segmentCount).round(); final segments = List.generate(segmentCount, (index) { final isFilled = isReversed ? index >= segmentCount - filledSegments : index < filledSegments; return Expanded( child: Container( height: 8, decoration: BoxDecoration( color: isFilled ? (isLow ? RetroColors.hpRed : fillColor) : fillColor.withValues(alpha: 0.2), border: Border( right: index < segmentCount - 1 ? BorderSide( color: RetroColors.borderOf( context, ).withValues(alpha: 0.3), width: 1, ) : BorderSide.none, ), ), ), ); }); return Container( decoration: BoxDecoration( border: Border.all(color: RetroColors.borderOf(context), width: 1), ), child: Row(children: isReversed ? segments.reversed.toList() : segments), ); } }