feat(ui): 게임 위젯들 레트로 UI 적용
- death_overlay: 사망 화면 레트로 스타일로 재디자인 - help_dialog: RetroDialog 사용으로 통일 - hp_mp_bar: 레트로 프로그레스 바 스타일 적용 - notification_overlay: 레트로 패널 스타일 적용 - statistics_dialog: RetroDialog로 변경
This commit is contained in:
@@ -3,6 +3,7 @@ import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:askiineverdie/src/core/notification/notification_service.dart';
|
||||
import 'package:askiineverdie/src/shared/retro_colors.dart';
|
||||
|
||||
/// 알림 오버레이 위젯 (Phase 8: 팝업/토스트 알림)
|
||||
///
|
||||
@@ -106,7 +107,7 @@ class _NotificationOverlayState extends State<NotificationOverlay>
|
||||
}
|
||||
}
|
||||
|
||||
/// 알림 카드 위젯
|
||||
/// 레트로 스타일 알림 카드 위젯
|
||||
class _NotificationCard extends StatelessWidget {
|
||||
const _NotificationCard({
|
||||
required this.notification,
|
||||
@@ -118,118 +119,191 @@ class _NotificationCard extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final (bgColor, icon, iconColor) = _getStyleForType(notification.type);
|
||||
final (accentColor, icon, asciiIcon) = _getStyleForType(notification.type);
|
||||
|
||||
return Material(
|
||||
elevation: 8,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: bgColor,
|
||||
child: InkWell(
|
||||
onTap: onDismiss,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
// 아이콘
|
||||
Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: iconColor.withValues(alpha: 0.2),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(icon, color: iconColor, size: 24),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
// 텍스트
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
notification.title,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
return GestureDetector(
|
||||
onTap: onDismiss,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: RetroColors.panelBg,
|
||||
border: Border(
|
||||
top: BorderSide(color: accentColor, width: 3),
|
||||
left: BorderSide(color: accentColor, width: 3),
|
||||
bottom: const BorderSide(color: RetroColors.panelBorderOuter, width: 3),
|
||||
right: const BorderSide(color: RetroColors.panelBorderOuter, width: 3),
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: accentColor.withValues(alpha: 0.4),
|
||||
blurRadius: 12,
|
||||
spreadRadius: 2,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// 헤더 바
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
color: accentColor.withValues(alpha: 0.3),
|
||||
child: Row(
|
||||
children: [
|
||||
// ASCII 아이콘
|
||||
Text(
|
||||
asciiIcon,
|
||||
style: TextStyle(
|
||||
fontFamily: 'JetBrainsMono',
|
||||
fontSize: 12,
|
||||
color: accentColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
// 타입 표시
|
||||
Expanded(
|
||||
child: Text(
|
||||
_getTypeLabel(notification.type),
|
||||
style: TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 7,
|
||||
color: accentColor,
|
||||
letterSpacing: 1,
|
||||
),
|
||||
),
|
||||
if (notification.subtitle != null) ...[
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
notification.subtitle!,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Colors.white.withValues(alpha: 0.8),
|
||||
),
|
||||
),
|
||||
// 닫기 버튼
|
||||
GestureDetector(
|
||||
onTap: onDismiss,
|
||||
child: const Text(
|
||||
'[X]',
|
||||
style: TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 7,
|
||||
color: RetroColors.textDisabled,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// 닫기 버튼
|
||||
IconButton(
|
||||
icon: const Icon(Icons.close, color: Colors.white70, size: 20),
|
||||
onPressed: onDismiss,
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(minWidth: 32, minHeight: 32),
|
||||
),
|
||||
// 본문
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
children: [
|
||||
// 아이콘 박스
|
||||
Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: RetroColors.panelBgLight,
|
||||
border: Border.all(color: accentColor, width: 2),
|
||||
),
|
||||
child: Icon(icon, color: accentColor, size: 20),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
// 텍스트
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
notification.title,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 9,
|
||||
color: RetroColors.textLight,
|
||||
),
|
||||
),
|
||||
if (notification.subtitle != null) ...[
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
notification.subtitle!,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 7,
|
||||
color: RetroColors.textDisabled,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
(Color, IconData, Color) _getStyleForType(NotificationType type) {
|
||||
/// 알림 타입별 레트로 스타일 (강조 색상, 아이콘, ASCII 아이콘)
|
||||
(Color, IconData, String) _getStyleForType(NotificationType type) {
|
||||
return switch (type) {
|
||||
NotificationType.levelUp => (
|
||||
const Color(0xFF1565C0),
|
||||
Icons.trending_up,
|
||||
Colors.amber,
|
||||
RetroColors.gold,
|
||||
Icons.arrow_upward,
|
||||
'★',
|
||||
),
|
||||
NotificationType.questComplete => (
|
||||
const Color(0xFF2E7D32),
|
||||
Icons.check_circle,
|
||||
Colors.lightGreen,
|
||||
RetroColors.expGreen,
|
||||
Icons.check,
|
||||
'☑',
|
||||
),
|
||||
NotificationType.actComplete => (
|
||||
const Color(0xFF6A1B9A),
|
||||
RetroColors.mpBlue,
|
||||
Icons.flag,
|
||||
Colors.purpleAccent,
|
||||
'⚑',
|
||||
),
|
||||
NotificationType.newSpell => (
|
||||
const Color(0xFF4527A0),
|
||||
const Color(0xFF9966FF),
|
||||
Icons.auto_fix_high,
|
||||
Colors.deepPurpleAccent,
|
||||
'✧',
|
||||
),
|
||||
NotificationType.newEquipment => (
|
||||
const Color(0xFFE65100),
|
||||
const Color(0xFFFF9933),
|
||||
Icons.shield,
|
||||
Colors.orange,
|
||||
'⚔',
|
||||
),
|
||||
NotificationType.bossDefeat => (
|
||||
const Color(0xFFC62828),
|
||||
RetroColors.hpRed,
|
||||
Icons.whatshot,
|
||||
Colors.redAccent,
|
||||
'☠',
|
||||
),
|
||||
NotificationType.gameSaved => (
|
||||
const Color(0xFF00695C),
|
||||
RetroColors.expGreen,
|
||||
Icons.save,
|
||||
Colors.tealAccent,
|
||||
'💾',
|
||||
),
|
||||
NotificationType.info => (
|
||||
const Color(0xFF0277BD),
|
||||
RetroColors.mpBlue,
|
||||
Icons.info_outline,
|
||||
Colors.lightBlueAccent,
|
||||
'ℹ',
|
||||
),
|
||||
NotificationType.warning => (
|
||||
const Color(0xFFF57C00),
|
||||
Icons.warning_amber,
|
||||
Colors.amber,
|
||||
const Color(0xFFFFCC00),
|
||||
Icons.warning,
|
||||
'⚠',
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/// 알림 타입 라벨
|
||||
String _getTypeLabel(NotificationType type) {
|
||||
return switch (type) {
|
||||
NotificationType.levelUp => 'LEVEL UP',
|
||||
NotificationType.questComplete => 'QUEST DONE',
|
||||
NotificationType.actComplete => 'ACT CLEAR',
|
||||
NotificationType.newSpell => 'NEW SPELL',
|
||||
NotificationType.newEquipment => 'NEW ITEM',
|
||||
NotificationType.bossDefeat => 'BOSS SLAIN',
|
||||
NotificationType.gameSaved => 'SAVED',
|
||||
NotificationType.info => 'INFO',
|
||||
NotificationType.warning => 'WARNING',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user