feat(ui): Phase 8 실시간 피드백 시스템 구현
- StatsPanel: 스탯 변화 애니메이션 (증감 표시) - CombatLog: 전투 이벤트 로그 위젯 - NotificationService: 큐 기반 알림 관리 - NotificationOverlay: 레벨업/퀘스트 완료 팝업 알림 - GamePlayScreen: 새 위젯 통합
This commit is contained in:
149
lib/src/core/notification/notification_service.dart
Normal file
149
lib/src/core/notification/notification_service.dart
Normal file
@@ -0,0 +1,149 @@
|
||||
import 'dart:async';
|
||||
|
||||
/// 알림 타입 (Notification Type)
|
||||
enum NotificationType {
|
||||
levelUp, // 레벨업
|
||||
questComplete, // 퀘스트 완료
|
||||
actComplete, // 막(Act) 완료
|
||||
newSpell, // 새 주문 습득
|
||||
newEquipment, // 새 장비 획득
|
||||
bossDefeat, // 보스 처치
|
||||
}
|
||||
|
||||
/// 게임 알림 데이터 (Game Notification)
|
||||
class GameNotification {
|
||||
const GameNotification({
|
||||
required this.type,
|
||||
required this.title,
|
||||
this.subtitle,
|
||||
this.data,
|
||||
this.duration = const Duration(seconds: 3),
|
||||
});
|
||||
|
||||
final NotificationType type;
|
||||
final String title;
|
||||
final String? subtitle;
|
||||
final Map<String, dynamic>? data;
|
||||
final Duration duration;
|
||||
}
|
||||
|
||||
/// 알림 서비스 (Phase 8: 이벤트 기반 알림 관리)
|
||||
///
|
||||
/// 게임 이벤트(레벨업, 퀘스트 완료 등)를 큐에 추가하고
|
||||
/// 순차적으로 UI에 표시
|
||||
class NotificationService {
|
||||
NotificationService();
|
||||
|
||||
final _notificationController =
|
||||
StreamController<GameNotification>.broadcast();
|
||||
final _dismissController = StreamController<void>.broadcast();
|
||||
|
||||
/// 알림 스트림 (Notification Stream)
|
||||
Stream<GameNotification> get notifications => _notificationController.stream;
|
||||
|
||||
/// 알림 닫기 스트림
|
||||
Stream<void> get dismissals => _dismissController.stream;
|
||||
|
||||
/// 알림 큐 (대기 중인 알림)
|
||||
final List<GameNotification> _queue = [];
|
||||
bool _isShowing = false;
|
||||
|
||||
/// 알림 추가 (Add Notification)
|
||||
void show(GameNotification notification) {
|
||||
_queue.add(notification);
|
||||
_processQueue();
|
||||
}
|
||||
|
||||
/// 레벨업 알림 (Level Up Notification)
|
||||
void showLevelUp(int newLevel) {
|
||||
show(GameNotification(
|
||||
type: NotificationType.levelUp,
|
||||
title: 'LEVEL UP!',
|
||||
subtitle: 'Level $newLevel',
|
||||
data: {'level': newLevel},
|
||||
duration: const Duration(seconds: 2),
|
||||
));
|
||||
}
|
||||
|
||||
/// 퀘스트 완료 알림
|
||||
void showQuestComplete(String questName) {
|
||||
show(GameNotification(
|
||||
type: NotificationType.questComplete,
|
||||
title: 'QUEST COMPLETE!',
|
||||
subtitle: questName,
|
||||
data: {'quest': questName},
|
||||
duration: const Duration(seconds: 2),
|
||||
));
|
||||
}
|
||||
|
||||
/// 막 완료 알림 (Act Complete)
|
||||
void showActComplete(int actNumber) {
|
||||
show(GameNotification(
|
||||
type: NotificationType.actComplete,
|
||||
title: 'ACT $actNumber COMPLETE!',
|
||||
duration: const Duration(seconds: 3),
|
||||
));
|
||||
}
|
||||
|
||||
/// 새 주문 알림
|
||||
void showNewSpell(String spellName) {
|
||||
show(GameNotification(
|
||||
type: NotificationType.newSpell,
|
||||
title: 'NEW SPELL!',
|
||||
subtitle: spellName,
|
||||
data: {'spell': spellName},
|
||||
duration: const Duration(seconds: 2),
|
||||
));
|
||||
}
|
||||
|
||||
/// 새 장비 알림
|
||||
void showNewEquipment(String equipmentName, String slot) {
|
||||
show(GameNotification(
|
||||
type: NotificationType.newEquipment,
|
||||
title: 'NEW EQUIPMENT!',
|
||||
subtitle: equipmentName,
|
||||
data: {'equipment': equipmentName, 'slot': slot},
|
||||
duration: const Duration(seconds: 2),
|
||||
));
|
||||
}
|
||||
|
||||
/// 보스 처치 알림
|
||||
void showBossDefeat(String bossName) {
|
||||
show(GameNotification(
|
||||
type: NotificationType.bossDefeat,
|
||||
title: 'BOSS DEFEATED!',
|
||||
subtitle: bossName,
|
||||
data: {'boss': bossName},
|
||||
duration: const Duration(seconds: 3),
|
||||
));
|
||||
}
|
||||
|
||||
/// 큐 처리 (Process Queue)
|
||||
void _processQueue() {
|
||||
if (_isShowing || _queue.isEmpty) return;
|
||||
|
||||
_isShowing = true;
|
||||
final notification = _queue.removeAt(0);
|
||||
_notificationController.add(notification);
|
||||
|
||||
// 지정된 시간 후 자동 닫기
|
||||
Future.delayed(notification.duration, () {
|
||||
_dismissController.add(null);
|
||||
_isShowing = false;
|
||||
_processQueue(); // 다음 알림 처리
|
||||
});
|
||||
}
|
||||
|
||||
/// 현재 알림 즉시 닫기
|
||||
void dismiss() {
|
||||
_dismissController.add(null);
|
||||
_isShowing = false;
|
||||
_processQueue();
|
||||
}
|
||||
|
||||
/// 서비스 정리 (Dispose)
|
||||
void dispose() {
|
||||
_notificationController.close();
|
||||
_dismissController.close();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user