diff --git a/lib/src/features/game/widgets/death_overlay.dart b/lib/src/features/game/widgets/death_overlay.dart index 7a959f2..7e4dc4f 100644 --- a/lib/src/features/game/widgets/death_overlay.dart +++ b/lib/src/features/game/widgets/death_overlay.dart @@ -94,10 +94,11 @@ class DeathOverlay extends StatelessWidget { ], ), ), - // 본문 - SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( + // 본문 (스크롤 가능) + Flexible( + child: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( mainAxisSize: MainAxisSize.min, children: [ // 사망 타이틀 @@ -134,6 +135,7 @@ class DeathOverlay extends StatelessWidget { ], ), ), + ), ], ), ), diff --git a/lib/src/features/hall_of_fame/hall_of_fame_screen.dart b/lib/src/features/hall_of_fame/hall_of_fame_screen.dart index 1d6bc35..be6a66f 100644 --- a/lib/src/features/hall_of_fame/hall_of_fame_screen.dart +++ b/lib/src/features/hall_of_fame/hall_of_fame_screen.dart @@ -8,6 +8,8 @@ import 'package:asciineverdie/src/core/model/hall_of_fame.dart'; import 'package:asciineverdie/src/core/model/item_stats.dart'; import 'package:asciineverdie/src/core/storage/hall_of_fame_storage.dart'; import 'package:asciineverdie/src/features/game/widgets/ascii_animation_card.dart'; +import 'package:asciineverdie/src/shared/retro_colors.dart'; +import 'package:asciineverdie/src/shared/widgets/retro_dialog.dart'; /// 명예의 전당 화면 (Phase 10: Hall of Fame Screen) class HallOfFameScreen extends StatefulWidget { @@ -42,11 +44,28 @@ class _HallOfFameScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text(l10n.uiHallOfFame), centerTitle: true), + backgroundColor: RetroColors.backgroundOf(context), + appBar: AppBar( + title: Text( + l10n.uiHallOfFame.toUpperCase(), + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 10, + color: RetroColors.goldOf(context), + ), + ), + centerTitle: true, + backgroundColor: RetroColors.panelBgOf(context), + iconTheme: IconThemeData(color: RetroColors.goldOf(context)), + ), body: SafeArea( - top: false, // AppBar가 상단 처리 + top: false, child: _isLoading - ? const Center(child: CircularProgressIndicator()) + ? Center( + child: CircularProgressIndicator( + color: RetroColors.goldOf(context), + ), + ) : _buildContent(), ), ); @@ -68,18 +87,26 @@ class _HallOfFameScreenState extends State { children: [ Icon( Icons.emoji_events_outlined, - size: 80, - color: Colors.grey.shade400, + size: 64, + color: RetroColors.textMutedOf(context), ), const SizedBox(height: 16), Text( - l10n.hofNoHeroes, - style: TextStyle(fontSize: 20, color: Colors.grey.shade600), + l10n.hofNoHeroes.toUpperCase(), + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 10, + color: RetroColors.textSecondaryOf(context), + ), ), - const SizedBox(height: 8), + const SizedBox(height: 12), Text( l10n.hofDefeatGlitchGod, - style: TextStyle(fontSize: 14, color: Colors.grey.shade500), + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 7, + color: RetroColors.textMutedOf(context), + ), textAlign: TextAlign.center, ), ], @@ -88,40 +115,47 @@ class _HallOfFameScreenState extends State { } Widget _buildHallOfFameList(HallOfFame hallOfFame) { + final goldColor = RetroColors.goldOf(context); + final borderColor = RetroColors.borderOf(context); + return Container( decoration: BoxDecoration( - border: Border.all(color: Colors.amber.shade700, width: 2), - borderRadius: BorderRadius.circular(8), + color: RetroColors.panelBgOf(context), + border: Border( + top: BorderSide(color: goldColor, width: 3), + left: BorderSide(color: goldColor, width: 3), + bottom: BorderSide(color: borderColor, width: 3), + right: BorderSide(color: borderColor, width: 3), + ), ), - margin: const EdgeInsets.all(16), + margin: const EdgeInsets.all(12), child: Column( children: [ // 헤더 Container( - padding: const EdgeInsets.symmetric(vertical: 12), + padding: const EdgeInsets.symmetric(vertical: 10), decoration: BoxDecoration( - color: Colors.amber.shade700, - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(6), - topRight: Radius.circular(6), + color: goldColor.withValues(alpha: 0.2), + border: Border( + bottom: BorderSide(color: goldColor, width: 2), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon(Icons.emoji_events, color: Colors.white), + Icon(Icons.emoji_events, color: goldColor, size: 18), const SizedBox(width: 8), Text( l10n.uiHallOfFame.toUpperCase(), - style: const TextStyle( - color: Colors.white, - fontSize: 18, - fontWeight: FontWeight.bold, - letterSpacing: 2, + style: TextStyle( + fontFamily: 'PressStart2P', + color: goldColor, + fontSize: 10, + letterSpacing: 1, ), ), const SizedBox(width: 8), - const Icon(Icons.emoji_events, color: Colors.white), + Icon(Icons.emoji_events, color: goldColor, size: 18), ], ), ), @@ -158,163 +192,192 @@ class _HallOfFameEntryCard extends StatelessWidget { @override Widget build(BuildContext context) { - final rankColor = _getRankColor(rank); + final rankColor = _getRankColor(context, rank); final rankIcon = _getRankIcon(rank); + final borderColor = RetroColors.borderOf(context); + final panelBg = RetroColors.panelBgOf(context); - return Card( + return Container( margin: const EdgeInsets.symmetric(vertical: 4), - child: InkWell( - onTap: () => _showDetailDialog(context), - borderRadius: BorderRadius.circular(12), - child: Padding( - padding: const EdgeInsets.all(12), - child: Row( - children: [ - // 순위 표시 - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: rankColor.withValues(alpha: 0.2), - shape: BoxShape.circle, - border: Border.all(color: rankColor, width: 2), - ), - child: Center( - child: rankIcon != null - ? Icon(rankIcon, color: rankColor, size: 20) - : Text( - '$rank', - style: TextStyle( - color: rankColor, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ), - ), - const SizedBox(width: 12), - // 캐릭터 정보 - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // 이름과 레벨 - Row( - children: [ - Expanded( - child: Text( - '"${entry.characterName}"', - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - overflow: TextOverflow.ellipsis, - ), - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 2, - ), - decoration: BoxDecoration( - color: Colors.blue.shade100, - borderRadius: BorderRadius.circular(4), - ), - child: Text( - l10n.uiLevel(entry.level), - style: TextStyle( - color: Colors.blue.shade800, - fontWeight: FontWeight.bold, - fontSize: 12, - ), - ), - ), - ], - ), - const SizedBox(height: 4), - // 종족/클래스 - Text( - '${GameDataL10n.getRaceName(context, entry.race)} ' - '${GameDataL10n.getKlassName(context, entry.klass)}', - style: TextStyle(fontSize: 13, color: Colors.grey.shade700), - ), - const SizedBox(height: 4), - // 통계 - Row( - children: [ - _buildStatChip( - Icons.timer, - entry.formattedPlayTime, - Colors.green, - ), - const SizedBox(width: 8), - _buildStatChip( - Icons.heart_broken, - '${entry.totalDeaths}', - Colors.red, - ), - const SizedBox(width: 8), - _buildStatChip( - Icons.check_circle, - '${entry.questsCompleted}Q', - Colors.orange, - ), - ], - ), - ], - ), - ), - // 클리어 날짜 - Column( - crossAxisAlignment: CrossAxisAlignment.end, + decoration: BoxDecoration( + color: panelBg, + border: Border.all(color: borderColor, width: 1), + ), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () => _showDetailDialog(context), + child: Padding( + padding: const EdgeInsets.all(10), + child: Row( children: [ - Icon( - Icons.calendar_today, - size: 14, - color: Colors.grey.shade500, + // 순위 표시 + Container( + width: 36, + height: 36, + decoration: BoxDecoration( + color: rankColor.withValues(alpha: 0.2), + shape: BoxShape.circle, + border: Border.all(color: rankColor, width: 2), + ), + child: Center( + child: rankIcon != null + ? Icon(rankIcon, color: rankColor, size: 16) + : Text( + '$rank', + style: TextStyle( + fontFamily: 'PressStart2P', + color: rankColor, + fontSize: 10, + ), + ), + ), ), - const SizedBox(height: 4), - Text( - entry.formattedClearedDate, - style: TextStyle(fontSize: 11, color: Colors.grey.shade600), + const SizedBox(width: 10), + // 캐릭터 정보 + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 이름과 레벨 + Row( + children: [ + Expanded( + child: Text( + entry.characterName, + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 8, + color: RetroColors.textPrimaryOf(context), + ), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 6, + vertical: 2, + ), + decoration: BoxDecoration( + color: RetroColors.mpOf(context) + .withValues(alpha: 0.2), + border: Border.all( + color: RetroColors.mpOf(context), + width: 1, + ), + ), + child: Text( + 'Lv.${entry.level}', + style: TextStyle( + fontFamily: 'PressStart2P', + color: RetroColors.mpOf(context), + fontSize: 6, + ), + ), + ), + ], + ), + const SizedBox(height: 4), + // 종족/클래스 + Text( + '${GameDataL10n.getRaceName(context, entry.race)} ' + '${GameDataL10n.getKlassName(context, entry.klass)}', + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 6, + color: RetroColors.textSecondaryOf(context), + ), + ), + const SizedBox(height: 6), + // 통계 + Row( + children: [ + _buildStatChip( + context, + Icons.timer, + entry.formattedPlayTime, + RetroColors.expOf(context), + ), + const SizedBox(width: 6), + _buildStatChip( + context, + Icons.heart_broken, + '${entry.totalDeaths}', + RetroColors.hpOf(context), + ), + const SizedBox(width: 6), + _buildStatChip( + context, + Icons.check_circle, + '${entry.questsCompleted}Q', + RetroColors.warningOf(context), + ), + ], + ), + ], + ), + ), + // 클리어 날짜 + Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Icon( + Icons.calendar_today, + size: 12, + color: RetroColors.textMutedOf(context), + ), + const SizedBox(height: 4), + Text( + entry.formattedClearedDate, + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 5, + color: RetroColors.textMutedOf(context), + ), + ), + ], ), ], ), - ], + ), ), ), - ), - ); + ); } - Widget _buildStatChip(IconData icon, String value, Color color) { + Widget _buildStatChip( + BuildContext context, + IconData icon, + String value, + Color color, + ) { return Row( mainAxisSize: MainAxisSize.min, children: [ - Icon(icon, size: 12, color: color), + Icon(icon, size: 10, color: color), const SizedBox(width: 2), Text( value, style: TextStyle( - fontSize: 11, + fontFamily: 'PressStart2P', + fontSize: 5, color: color, - fontWeight: FontWeight.w500, ), ), ], ); } - Color _getRankColor(int rank) { + Color _getRankColor(BuildContext context, int rank) { switch (rank) { case 1: - return Colors.amber.shade700; + return RetroColors.goldOf(context); case 2: - return Colors.grey.shade500; + return Colors.grey.shade400; case 3: return Colors.brown.shade400; default: - return Colors.blue.shade400; + return RetroColors.mpOf(context); } } @@ -364,91 +427,211 @@ class _GameClearDialog extends StatelessWidget { @override Widget build(BuildContext context) { - return AlertDialog( - title: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon(Icons.emoji_events, color: Colors.amber, size: 32), - const SizedBox(width: 8), - Text(l10n.hofVictory), - const SizedBox(width: 8), - const Icon(Icons.emoji_events, color: Colors.amber, size: 32), - ], - ), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - l10n.hofDefeatedGlitchGod, - style: const TextStyle(fontSize: 16), - textAlign: TextAlign.center, + final goldColor = RetroColors.goldOf(context); + final panelBg = RetroColors.panelBgOf(context); + final borderColor = RetroColors.borderOf(context); + + return Dialog( + backgroundColor: Colors.transparent, + child: Container( + constraints: const BoxConstraints(maxWidth: 400), + decoration: BoxDecoration( + color: panelBg, + border: Border( + top: BorderSide(color: goldColor, width: 3), + left: BorderSide(color: goldColor, width: 3), + bottom: BorderSide(color: borderColor, width: 3), + right: BorderSide(color: borderColor, width: 3), ), - const SizedBox(height: 16), - const Divider(), - const SizedBox(height: 16), - // 캐릭터 정보 - Text( - '"${entry.characterName}"', - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 4), - Text( - '${GameDataL10n.getRaceName(context, entry.race)} ${GameDataL10n.getKlassName(context, entry.klass)}', - style: TextStyle(color: Colors.grey.shade600), - ), - const SizedBox(height: 16), - // 통계 - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - _buildStat(l10n.hofLevel, '${entry.level}'), - _buildStat(l10n.hofTime, entry.formattedPlayTime), - _buildStat(l10n.hofDeaths, '${entry.totalDeaths}'), - _buildStat(l10n.hofQuests, '${entry.questsCompleted}'), - ], - ), - const SizedBox(height: 16), - Text( - l10n.hofLegendEnshrined, - style: const TextStyle( - fontStyle: FontStyle.italic, - color: Colors.amber, + boxShadow: [ + BoxShadow( + color: goldColor.withValues(alpha: 0.4), + blurRadius: 24, + spreadRadius: 4, ), - textAlign: TextAlign.center, - ), - ], + ], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // 헤더 + Container( + padding: const EdgeInsets.symmetric(vertical: 12), + decoration: BoxDecoration( + color: goldColor.withValues(alpha: 0.2), + border: Border( + bottom: BorderSide(color: goldColor, width: 2), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.emoji_events, color: goldColor, size: 20), + const SizedBox(width: 8), + Text( + l10n.hofVictory.toUpperCase(), + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 12, + color: goldColor, + ), + ), + const SizedBox(width: 8), + Icon(Icons.emoji_events, color: goldColor, size: 20), + ], + ), + ), + // 컨텐츠 + Padding( + padding: const EdgeInsets.all(16), + child: Column( + children: [ + Text( + l10n.hofDefeatedGlitchGod, + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 7, + color: RetroColors.textPrimaryOf(context), + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + Container( + height: 2, + color: borderColor, + ), + const SizedBox(height: 16), + // 캐릭터 정보 + Text( + entry.characterName, + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 10, + color: goldColor, + ), + ), + const SizedBox(height: 6), + Text( + '${GameDataL10n.getRaceName(context, entry.race)} ' + '${GameDataL10n.getKlassName(context, entry.klass)}', + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 6, + color: RetroColors.textSecondaryOf(context), + ), + ), + const SizedBox(height: 16), + // 통계 + Wrap( + spacing: 12, + runSpacing: 8, + alignment: WrapAlignment.center, + children: [ + _buildStat(context, l10n.hofLevel, '${entry.level}'), + _buildStat(context, l10n.hofTime, entry.formattedPlayTime), + _buildStat(context, l10n.hofDeaths, '${entry.totalDeaths}'), + _buildStat(context, l10n.hofQuests, '${entry.questsCompleted}'), + ], + ), + const SizedBox(height: 16), + Text( + l10n.hofLegendEnshrined, + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 6, + fontStyle: FontStyle.italic, + color: goldColor, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + // 버튼 + Padding( + padding: const EdgeInsets.fromLTRB(16, 0, 16, 16), + child: Row( + children: [ + Expanded( + child: OutlinedButton( + onPressed: () { + Navigator.of(context).pop(); + onViewHallOfFame(); + }, + style: OutlinedButton.styleFrom( + side: BorderSide(color: borderColor, width: 2), + padding: const EdgeInsets.symmetric(vertical: 10), + ), + child: Text( + l10n.hofViewHallOfFame.toUpperCase(), + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 6, + color: RetroColors.textSecondaryOf(context), + ), + ), + ), + ), + const SizedBox(width: 12), + Expanded( + child: FilledButton( + onPressed: () { + Navigator.of(context).pop(); + onNewGame(); + }, + style: FilledButton.styleFrom( + backgroundColor: goldColor, + padding: const EdgeInsets.symmetric(vertical: 10), + ), + child: Text( + l10n.hofNewGame.toUpperCase(), + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 6, + color: RetroColors.backgroundOf(context), + ), + ), + ), + ), + ], + ), + ), + ], + ), ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - onViewHallOfFame(); - }, - child: Text(l10n.hofViewHallOfFame), - ), - FilledButton( - onPressed: () { - Navigator.of(context).pop(); - onNewGame(); - }, - child: Text(l10n.hofNewGame), - ), - ], ); } - Widget _buildStat(String label, String value) { - return Column( - children: [ - Text( - value, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), - ), - Text( - label, - style: TextStyle(fontSize: 11, color: Colors.grey.shade600), - ), - ], + Widget _buildStat(BuildContext context, String label, String value) { + final goldColor = RetroColors.goldOf(context); + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: goldColor.withValues(alpha: 0.1), + border: Border.all(color: goldColor.withValues(alpha: 0.3), width: 1), + ), + child: Column( + children: [ + Text( + value, + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 8, + color: goldColor, + ), + ), + const SizedBox(height: 2), + Text( + label, + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 5, + color: RetroColors.textMutedOf(context), + ), + ), + ], + ), ); } } @@ -461,99 +644,124 @@ class _HallOfFameDetailDialog extends StatelessWidget { @override Widget build(BuildContext context) { - return AlertDialog( - title: Column( + return RetroDialog( + title: entry.characterName, + titleIcon: '👑', + maxWidth: 420, + maxHeight: 600, + child: Column( + mainAxisSize: MainAxisSize.min, children: [ - Text( - '"${entry.characterName}"', - style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + // 서브 타이틀 + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Text( + '${GameDataL10n.getRaceName(context, entry.race)} ' + '${GameDataL10n.getKlassName(context, entry.klass)} - ' + 'Lv.${entry.level}', + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 6, + color: RetroColors.textSecondaryOf(context), + ), + ), ), - const SizedBox(height: 4), - Text( - '${GameDataL10n.getRaceName(context, entry.race)} ' - '${GameDataL10n.getKlassName(context, entry.klass)} - ' - '${l10n.uiLevel(entry.level)}', - style: TextStyle(fontSize: 14, color: Colors.grey.shade600), + // 스크롤 가능한 컨텐츠 + Flexible( + child: SingleChildScrollView( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + // 캐릭터 애니메이션 섹션 + _buildSection( + context, + icon: Icons.movie, + title: l10n.hofCharacterPreview, + child: _buildAnimationPreview(context), + ), + const SizedBox(height: 12), + // 통계 섹션 + _buildSection( + context, + icon: Icons.analytics, + title: l10n.hofStats, + child: _buildStatsGrid(context), + ), + const SizedBox(height: 12), + // 전투 스탯 섹션 + if (entry.finalStats != null) ...[ + _buildSection( + context, + icon: Icons.sports_mma, + title: l10n.hofCombatStats, + child: _buildCombatStatsGrid(context), + ), + const SizedBox(height: 12), + ], + // 장비 섹션 + if (entry.finalEquipment != null) ...[ + _buildSection( + context, + icon: Icons.shield, + title: l10n.navEquipment, + child: _buildEquipmentList(context), + ), + const SizedBox(height: 12), + ], + // 스킬 섹션 (스킬이 없어도 표시) + _buildSection( + context, + icon: Icons.auto_fix_high, + title: l10n.hofSkills, + child: _buildSkillList(context), + ), + ], + ), + ), ), ], ), - content: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 400, maxHeight: 500), - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - // 캐릭터 애니메이션 섹션 (Character Animation Section) - _buildSection( - icon: Icons.movie, - title: l10n.hofCharacterPreview, - child: _buildAnimationPreview(), - ), - const SizedBox(height: 16), - // 통계 섹션 (Statistics Section) - _buildSection( - icon: Icons.analytics, - title: l10n.hofStats, - child: _buildStatsGrid(), - ), - const SizedBox(height: 16), - // 전투 스탯 섹션 (Combat Stats Section) - if (entry.finalStats != null) ...[ - _buildSection( - icon: Icons.sports_mma, - title: l10n.hofCombatStats, - child: _buildCombatStatsGrid(), - ), - const SizedBox(height: 16), - ], - // 장비 섹션 (Equipment Section) - if (entry.finalEquipment != null) ...[ - _buildSection( - icon: Icons.shield, - title: l10n.navEquipment, - child: _buildEquipmentList(context), - ), - const SizedBox(height: 16), - ], - // 스킬 섹션 (Skills Section) - if (entry.finalSkills != null && entry.finalSkills!.isNotEmpty) - _buildSection( - icon: Icons.auto_fix_high, - title: l10n.hofSpells, - child: _buildSkillList(context), - ), - ], - ), - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.of(context).pop(), - child: Text(l10n.buttonClose), - ), - ], ); } - Widget _buildSection({ + Widget _buildSection( + BuildContext context, { required IconData icon, required String title, required Widget child, }) { + final goldColor = RetroColors.goldOf(context); + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ - Icon(icon, size: 18, color: Colors.amber.shade700), - const SizedBox(width: 8), + Icon(icon, size: 14, color: goldColor), + const SizedBox(width: 6), Text( - title, + title.toUpperCase(), style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.amber.shade700, + fontFamily: 'PressStart2P', + fontSize: 7, + color: goldColor, + ), + ), + const SizedBox(width: 8), + Expanded( + child: Container( + height: 1, + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + goldColor, + goldColor.withValues(alpha: 0.3), + Colors.transparent, + ], + ), + ), ), ), ], @@ -565,7 +773,7 @@ class _HallOfFameDetailDialog extends StatelessWidget { } /// 캐릭터 애니메이션 미리보기 위젯 - Widget _buildAnimationPreview() { + Widget _buildAnimationPreview(BuildContext context) { // 장비에서 무기와 방패 이름 추출 String? weaponName; String? shieldName; @@ -580,53 +788,56 @@ class _HallOfFameDetailDialog extends StatelessWidget { } } - // AsciiCanvasWidget은 60x8 그리드 사용 - // 다이얼로그 내에서 적절한 크기: 360x80 (비율 7.5:1 유지) + final borderColor = RetroColors.borderOf(context); + return Center( child: Container( decoration: BoxDecoration( - border: Border.all(color: Colors.amber.shade300), - borderRadius: BorderRadius.circular(8), + border: Border.all(color: borderColor, width: 1), ), child: SizedBox( width: 360, height: 80, child: AsciiAnimationCard( - taskType: TaskType.kill, // 전투 애니메이션 표시 + taskType: TaskType.kill, raceId: entry.race, weaponName: weaponName, shieldName: shieldName, characterLevel: entry.level, - monsterLevel: entry.level, // 레벨에 맞는 몬스터 크기 - monsterBaseName: 'Glitch God', // 최종 보스 + monsterLevel: entry.level, + monsterBaseName: 'Glitch God', ), ), ), ); } - Widget _buildStatsGrid() { + Widget _buildStatsGrid(BuildContext context) { return Wrap( - spacing: 16, - runSpacing: 8, + spacing: 8, + runSpacing: 6, children: [ - _buildStatItem(Icons.timer, l10n.hofTime, entry.formattedPlayTime), + _buildStatItem(context, Icons.timer, l10n.hofTime, entry.formattedPlayTime), _buildStatItem( + context, Icons.pest_control, l10n.hofMonsters, '${entry.monstersKilled}', ), _buildStatItem( + context, Icons.heart_broken, l10n.hofDeaths, '${entry.totalDeaths}', ), _buildStatItem( + context, Icons.check_circle, l10n.hofQuests, '${entry.questsCompleted}', ), _buildStatItem( + context, Icons.calendar_today, l10n.hofCleared, entry.formattedClearedDate, @@ -635,13 +846,15 @@ class _HallOfFameDetailDialog extends StatelessWidget { ); } - Widget _buildCombatStatsGrid() { + Widget _buildCombatStatsGrid(BuildContext context) { final stats = entry.finalStats!; + final borderColor = RetroColors.borderOf(context); + return Column( children: [ - // 기본 스탯 행 (Basic Stats Row) + // 기본 스탯 행 Wrap( - spacing: 8, + spacing: 6, runSpacing: 4, children: [ _buildCombatStatChip(l10n.statStr, '${stats.str}', Colors.red), @@ -652,12 +865,12 @@ class _HallOfFameDetailDialog extends StatelessWidget { _buildCombatStatChip(l10n.statCha, '${stats.cha}', Colors.pink), ], ), - const SizedBox(height: 8), - const Divider(height: 1), - const SizedBox(height: 8), - // 공격 스탯 행 (Attack Stats Row) + const SizedBox(height: 6), + Container(height: 1, color: borderColor), + const SizedBox(height: 6), + // 공격 스탯 행 Wrap( - spacing: 8, + spacing: 6, runSpacing: 4, children: [ _buildCombatStatChip(l10n.statAtk, '${stats.atk}', Colors.red.shade700), @@ -669,10 +882,10 @@ class _HallOfFameDetailDialog extends StatelessWidget { ), ], ), - const SizedBox(height: 8), - // 방어 스탯 행 (Defense Stats Row) + const SizedBox(height: 6), + // 방어 스탯 행 Wrap( - spacing: 8, + spacing: 6, runSpacing: 4, children: [ _buildCombatStatChip(l10n.statDef, '${stats.def}', Colors.brown), @@ -689,10 +902,10 @@ class _HallOfFameDetailDialog extends StatelessWidget { ), ], ), - const SizedBox(height: 8), - // HP/MP 행 (Resource Stats Row) + const SizedBox(height: 6), + // HP/MP 행 Wrap( - spacing: 8, + spacing: 6, runSpacing: 4, children: [ _buildCombatStatChip(l10n.statHp, '${stats.hpMax}', Colors.red.shade400), @@ -705,24 +918,27 @@ class _HallOfFameDetailDialog extends StatelessWidget { Widget _buildCombatStatChip(String label, String value, Color color) { return Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 3), decoration: BoxDecoration( color: color.withValues(alpha: 0.1), - borderRadius: BorderRadius.circular(6), - border: Border.all(color: color.withValues(alpha: 0.3)), + border: Border.all(color: color.withValues(alpha: 0.3), width: 1), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Text( '$label ', - style: TextStyle(fontSize: 11, color: color), + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 5, + color: color, + ), ), Text( value, style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.bold, + fontFamily: 'PressStart2P', + fontSize: 5, color: color, ), ), @@ -731,33 +947,43 @@ class _HallOfFameDetailDialog extends StatelessWidget { ); } - Widget _buildStatItem(IconData icon, String label, String value) { + Widget _buildStatItem( + BuildContext context, + IconData icon, + String label, + String value, + ) { + final goldColor = RetroColors.goldOf(context); + return Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( - color: Colors.amber.shade700.withValues(alpha: 0.15), - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Colors.amber.shade700.withValues(alpha: 0.3)), + color: goldColor.withValues(alpha: 0.1), + border: Border.all(color: goldColor.withValues(alpha: 0.3), width: 1), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ - Icon(icon, size: 14, color: Colors.amber.shade600), - const SizedBox(width: 6), + Icon(icon, size: 12, color: goldColor), + const SizedBox(width: 4), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( value, style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 13, - color: Colors.amber.shade300, + fontFamily: 'PressStart2P', + fontSize: 6, + color: goldColor, ), ), Text( label, - style: TextStyle(fontSize: 10, color: Colors.amber.shade400), + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 4, + color: RetroColors.textMutedOf(context), + ), ), ], ), @@ -768,6 +994,7 @@ class _HallOfFameDetailDialog extends StatelessWidget { Widget _buildEquipmentList(BuildContext context) { final equipment = entry.finalEquipment!; + final mutedColor = RetroColors.textMutedOf(context); return Column( children: equipment.map((item) { @@ -789,45 +1016,48 @@ class _HallOfFameDetailDialog extends StatelessWidget { final statSummary = _buildStatSummary(item.stats, item.slot); return Padding( - padding: const EdgeInsets.symmetric(vertical: 4), + padding: const EdgeInsets.symmetric(vertical: 3), child: Container( - padding: const EdgeInsets.all(8), + padding: const EdgeInsets.all(6), decoration: BoxDecoration( color: rarityColor.withValues(alpha: 0.1), - borderRadius: BorderRadius.circular(6), - border: Border.all(color: rarityColor.withValues(alpha: 0.3)), + border: Border.all(color: rarityColor.withValues(alpha: 0.3), width: 1), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // 슬롯 + 이름 + 희귀도 표시 + // 슬롯 + 희귀도 표시 Row( children: [ - Icon(slotIcon, size: 14, color: rarityColor), - const SizedBox(width: 6), + Icon(slotIcon, size: 12, color: rarityColor), + const SizedBox(width: 4), Text( slotLabel, style: TextStyle( - fontSize: 10, - color: Colors.grey.shade500, + fontFamily: 'PressStart2P', + fontSize: 5, + color: mutedColor, ), ), const Spacer(), Container( padding: const EdgeInsets.symmetric( - horizontal: 6, + horizontal: 4, vertical: 1, ), decoration: BoxDecoration( color: rarityColor.withValues(alpha: 0.2), - borderRadius: BorderRadius.circular(4), + border: Border.all( + color: rarityColor.withValues(alpha: 0.4), + width: 1, + ), ), child: Text( _getRarityLabel(item.rarity), style: TextStyle( - fontSize: 9, + fontFamily: 'PressStart2P', + fontSize: 4, color: rarityColor, - fontWeight: FontWeight.bold, ), ), ), @@ -838,8 +1068,8 @@ class _HallOfFameDetailDialog extends StatelessWidget { Text( translatedName, style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, + fontFamily: 'PressStart2P', + fontSize: 6, color: rarityColor, ), ), @@ -927,7 +1157,11 @@ class _HallOfFameDetailDialog extends StatelessWidget { widgets.add( Text( '$label $value', - style: TextStyle(fontSize: 10, color: color), + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 5, + color: color, + ), ), ); } @@ -984,9 +1218,33 @@ class _HallOfFameDetailDialog extends StatelessWidget { } Widget _buildSkillList(BuildContext context) { - final skills = entry.finalSkills!; + final skills = entry.finalSkills; + const skillColor = Colors.purple; + + // 스킬이 없는 경우 빈 상태 표시 + if (skills == null || skills.isEmpty) { + return Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: RetroColors.backgroundOf(context), + border: Border.all( + color: RetroColors.borderOf(context), + width: 1, + ), + ), + child: Text( + l10n.hofNoSkills.toUpperCase(), + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 6, + color: RetroColors.textMutedOf(context), + ), + ), + ); + } + return Wrap( - spacing: 8, + spacing: 6, runSpacing: 4, children: skills.map((skill) { final name = skill['name'] ?? ''; @@ -994,15 +1252,18 @@ class _HallOfFameDetailDialog extends StatelessWidget { // 스킬 이름 번역 적용 final translatedName = GameDataL10n.getSpellName(context, name); return Container( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 3), decoration: BoxDecoration( - color: Colors.purple.shade50, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: Colors.purple.shade200), + color: skillColor.withValues(alpha: 0.1), + border: Border.all(color: skillColor.withValues(alpha: 0.3), width: 1), ), child: Text( '$translatedName $rank', - style: TextStyle(fontSize: 12, color: Colors.purple.shade700), + style: TextStyle( + fontFamily: 'PressStart2P', + fontSize: 5, + color: skillColor.shade400, + ), ), ); }).toList(),