Files
asciinevrdie/lib/src/features/arena/widgets/arena_rank_card.dart
JiWoong Sul a2e93efc97 feat(arena): 아레나 화면 구현
- ArenaScreen: 아레나 메인 화면
- ArenaSetupScreen: 전투 설정 화면
- ArenaBattleScreen: 전투 진행 화면
- 관련 위젯 추가
2026-01-06 17:55:02 +09:00

209 lines
5.4 KiB
Dart

import 'package:flutter/material.dart';
import 'package:asciineverdie/src/core/l10n/game_data_l10n.dart';
import 'package:asciineverdie/src/core/model/hall_of_fame.dart';
import 'package:asciineverdie/src/shared/retro_colors.dart';
/// 아레나 순위 카드 위젯
///
/// 명예의 전당 캐릭터를 순위와 함께 표시
class ArenaRankCard extends StatelessWidget {
const ArenaRankCard({
super.key,
required this.entry,
required this.rank,
required this.score,
this.isSelected = false,
this.isHighlighted = false,
this.compact = false,
this.onTap,
});
/// 캐릭터 엔트리
final HallOfFameEntry entry;
/// 순위 (1-based)
final int rank;
/// 아레나 점수
final int score;
/// 선택 상태 (상대로 선택됨)
final bool isSelected;
/// 하이라이트 상태 (내 캐릭터 표시)
final bool isHighlighted;
/// 컴팩트 모드 (작은 사이즈)
final bool compact;
/// 탭 콜백
final VoidCallback? onTap;
@override
Widget build(BuildContext context) {
final rankColor = _getRankColor(rank);
final rankIcon = _getRankIcon(rank);
// 배경색 결정
Color bgColor;
Color borderColor;
if (isSelected) {
bgColor = Colors.red.withValues(alpha: 0.15);
borderColor = Colors.red;
} else if (isHighlighted) {
bgColor = Colors.blue.withValues(alpha: 0.15);
borderColor = Colors.blue;
} else {
bgColor = RetroColors.panelBgOf(context);
borderColor = RetroColors.borderOf(context);
}
return Card(
margin: EdgeInsets.symmetric(
vertical: compact ? 2 : 4,
horizontal: compact ? 0 : 8,
),
color: bgColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(compact ? 6 : 8),
side: BorderSide(
color: borderColor,
width: (isSelected || isHighlighted) ? 2 : 1,
),
),
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(compact ? 6 : 8),
child: Padding(
padding: EdgeInsets.all(compact ? 8 : 12),
child: Row(
children: [
// 순위 배지
_buildRankBadge(rankColor, rankIcon),
SizedBox(width: compact ? 8 : 12),
// 캐릭터 정보
Expanded(child: _buildCharacterInfo(context)),
// 점수
if (!compact) _buildScoreColumn(context),
],
),
),
),
);
}
Widget _buildRankBadge(Color color, IconData? icon) {
final size = compact ? 24.0 : 36.0;
final iconSize = compact ? 12.0 : 18.0;
final fontSize = compact ? 7.0 : 10.0;
return Container(
width: size,
height: size,
decoration: BoxDecoration(
color: color.withValues(alpha: 0.2),
shape: BoxShape.circle,
border: Border.all(color: color, width: compact ? 1.5 : 2),
),
child: Center(
child: icon != null
? Icon(icon, color: color, size: iconSize)
: Text(
'$rank',
style: TextStyle(
fontFamily: 'PressStart2P',
fontSize: fontSize,
color: color,
fontWeight: FontWeight.bold,
),
),
),
);
}
Widget _buildCharacterInfo(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 이름
Text(
entry.characterName,
style: TextStyle(
fontFamily: 'PressStart2P',
fontSize: compact ? 6 : 9,
color: RetroColors.textPrimaryOf(context),
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
SizedBox(height: compact ? 2 : 4),
// 종족/클래스 + 레벨
Text(
compact
? 'Lv.${entry.level}'
: '${GameDataL10n.getRaceName(context, entry.race)} '
'${GameDataL10n.getKlassName(context, entry.klass)} '
'Lv.${entry.level}',
style: TextStyle(
fontFamily: 'PressStart2P',
fontSize: compact ? 5 : 7,
color: RetroColors.textSecondaryOf(context),
),
),
],
);
}
Widget _buildScoreColumn(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'$score',
style: TextStyle(
fontFamily: 'PressStart2P',
fontSize: 10,
color: RetroColors.goldOf(context),
fontWeight: FontWeight.bold,
),
),
Text(
'SCORE',
style: TextStyle(
fontFamily: 'PressStart2P',
fontSize: 6,
color: RetroColors.textMutedOf(context),
),
),
],
);
}
Color _getRankColor(int rank) {
switch (rank) {
case 1:
return Colors.amber.shade700;
case 2:
return Colors.grey.shade500;
case 3:
return Colors.brown.shade400;
default:
return Colors.blue.shade400;
}
}
IconData? _getRankIcon(int rank) {
switch (rank) {
case 1:
return Icons.emoji_events;
case 2:
return Icons.workspace_premium;
case 3:
return Icons.military_tech;
default:
return null;
}
}
}