import 'package:flutter/material.dart'; import 'package:asciineverdie/data/game_text_l10n.dart' as l10n; import 'package:asciineverdie/src/core/model/skill.dart'; /// 활성 버프 패널 위젯 /// /// 현재 적용 중인 버프 목록과 남은 시간을 표시. class ActiveBuffPanel extends StatelessWidget { const ActiveBuffPanel({ super.key, required this.activeBuffs, required this.currentMs, }); final List activeBuffs; final int currentMs; @override Widget build(BuildContext context) { if (activeBuffs.isEmpty) { return Center( child: Text( l10n.uiNoActiveBuffs, style: const TextStyle( fontSize: 11, color: Colors.grey, fontStyle: FontStyle.italic, ), ), ); } return ListView.builder( itemCount: activeBuffs.length, padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), itemBuilder: (context, index) { final buff = activeBuffs[index]; return _BuffRow(buff: buff, currentMs: currentMs); }, ); } } /// 개별 버프 행 위젯 class _BuffRow extends StatelessWidget { const _BuffRow({required this.buff, required this.currentMs}); final ActiveBuff buff; final int currentMs; @override Widget build(BuildContext context) { final remainingMs = buff.remainingDuration(currentMs); final remainingSec = (remainingMs / 1000).toStringAsFixed(1); final progress = remainingMs / buff.effect.durationMs; final modifiers = _buildModifierList(); return Padding( padding: const EdgeInsets.symmetric(vertical: 2), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ // 버프 아이콘 const Icon(Icons.trending_up, size: 14, color: Colors.lightBlue), const SizedBox(width: 4), // 버프 이름 Expanded( child: Text( buff.effect.name, style: const TextStyle( fontSize: 11, fontWeight: FontWeight.w500, color: Colors.lightBlue, ), overflow: TextOverflow.ellipsis, ), ), // 남은 시간 Text( '${remainingSec}s', style: TextStyle( fontSize: 10, color: remainingMs < 3000 ? Colors.orange : Colors.grey, fontWeight: remainingMs < 3000 ? FontWeight.bold : FontWeight.normal, ), ), ], ), const SizedBox(height: 2), // 남은 시간 프로그레스 바 ClipRRect( borderRadius: BorderRadius.circular(2), child: LinearProgressIndicator( value: progress.clamp(0.0, 1.0), minHeight: 3, backgroundColor: Colors.grey.shade800, valueColor: AlwaysStoppedAnimation( progress > 0.3 ? Colors.lightBlue : Colors.orange, ), ), ), // 효과 목록 if (modifiers.isNotEmpty) ...[ const SizedBox(height: 2), Wrap(spacing: 6, runSpacing: 2, children: modifiers), ], ], ), ); } /// 버프 효과 목록 생성 List _buildModifierList() { final modifiers = []; final effect = buff.effect; if (effect.atkModifier != 0) { modifiers.add( _ModifierChip( label: l10n.statAtk, value: effect.atkModifier, isPositive: effect.atkModifier > 0, ), ); } if (effect.defModifier != 0) { modifiers.add( _ModifierChip( label: l10n.statDef, value: effect.defModifier, isPositive: effect.defModifier > 0, ), ); } if (effect.criRateModifier != 0) { modifiers.add( _ModifierChip( label: l10n.statCri, value: effect.criRateModifier, isPositive: effect.criRateModifier > 0, ), ); } if (effect.evasionModifier != 0) { modifiers.add( _ModifierChip( label: l10n.statEva, value: effect.evasionModifier, isPositive: effect.evasionModifier > 0, ), ); } return modifiers; } } /// 효과 칩 위젯 class _ModifierChip extends StatelessWidget { const _ModifierChip({ required this.label, required this.value, required this.isPositive, }); final String label; final double value; final bool isPositive; @override Widget build(BuildContext context) { final color = isPositive ? Colors.green : Colors.red; final sign = isPositive ? '+' : ''; final percent = (value * 100).round(); return Container( padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1), decoration: BoxDecoration( color: color.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(3), ), child: Text( '$label: $sign$percent%', style: TextStyle( fontSize: 8, color: color, fontWeight: FontWeight.w500, ), ), ); } }