- game_text_l10n.dart: 스탯/UI 텍스트 추가 (+61 라인) - 한국어/일본어 번역 업데이트 - game_data_l10n.dart: 텍스트 접근자 추가 - equipment_stats_panel: l10n 적용 및 레이아웃 개선 - active_buff_panel, potion_inventory_panel: 코드 정리 - new_character_screen: 코드 정리 - progress_service: 마이너 개선
233 lines
5.9 KiB
Dart
233 lines
5.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import 'package:askiineverdie/data/game_text_l10n.dart' as l10n;
|
|
import 'package:askiineverdie/data/potion_data.dart';
|
|
import 'package:askiineverdie/src/core/model/potion.dart';
|
|
|
|
/// 물약 인벤토리 패널
|
|
///
|
|
/// 보유 중인 물약 목록과 수량을 표시.
|
|
/// HP 물약은 빨간색, MP 물약은 파란색으로 구분.
|
|
class PotionInventoryPanel extends StatelessWidget {
|
|
const PotionInventoryPanel({
|
|
super.key,
|
|
required this.inventory,
|
|
this.usedInBattle = const {},
|
|
});
|
|
|
|
final PotionInventory inventory;
|
|
final Set<PotionType> usedInBattle;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final potionEntries = _buildPotionEntries();
|
|
|
|
if (potionEntries.isEmpty) {
|
|
return Center(
|
|
child: Text(
|
|
l10n.uiNoPotions,
|
|
style: const TextStyle(
|
|
fontSize: 11,
|
|
color: Colors.grey,
|
|
fontStyle: FontStyle.italic,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
return ListView.builder(
|
|
itemCount: potionEntries.length,
|
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
|
itemBuilder: (context, index) {
|
|
final entry = potionEntries[index];
|
|
return _PotionRow(
|
|
potion: entry.potion,
|
|
quantity: entry.quantity,
|
|
isUsedThisBattle: usedInBattle.contains(entry.potion.type),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
/// 물약 엔트리 목록 생성
|
|
///
|
|
/// HP 물약 먼저, MP 물약 나중에 정렬
|
|
List<_PotionEntry> _buildPotionEntries() {
|
|
final entries = <_PotionEntry>[];
|
|
|
|
for (final potionId in inventory.potions.keys) {
|
|
final quantity = inventory.potions[potionId] ?? 0;
|
|
if (quantity <= 0) continue;
|
|
|
|
final potion = PotionData.getById(potionId);
|
|
if (potion == null) continue;
|
|
|
|
entries.add(_PotionEntry(potion: potion, quantity: quantity));
|
|
}
|
|
|
|
// HP 물약 우선, 같은 타입 내에서는 티어순
|
|
entries.sort((a, b) {
|
|
final typeCompare = a.potion.type.index.compareTo(b.potion.type.index);
|
|
if (typeCompare != 0) return typeCompare;
|
|
return a.potion.tier.compareTo(b.potion.tier);
|
|
});
|
|
|
|
return entries;
|
|
}
|
|
}
|
|
|
|
/// 물약 엔트리
|
|
class _PotionEntry {
|
|
const _PotionEntry({required this.potion, required this.quantity});
|
|
final Potion potion;
|
|
final int quantity;
|
|
}
|
|
|
|
/// 물약 행 위젯
|
|
class _PotionRow extends StatelessWidget {
|
|
const _PotionRow({
|
|
required this.potion,
|
|
required this.quantity,
|
|
this.isUsedThisBattle = false,
|
|
});
|
|
|
|
final Potion potion;
|
|
final int quantity;
|
|
final bool isUsedThisBattle;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final color = _getPotionColor();
|
|
final opacity = isUsedThisBattle ? 0.5 : 1.0;
|
|
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 2),
|
|
child: Opacity(
|
|
opacity: opacity,
|
|
child: Row(
|
|
children: [
|
|
// 물약 아이콘
|
|
_PotionIcon(type: potion.type, tier: potion.tier),
|
|
const SizedBox(width: 4),
|
|
|
|
// 물약 이름 (번역 적용)
|
|
Expanded(
|
|
child: Text(
|
|
l10n.translateSpell(potion.name),
|
|
style: TextStyle(
|
|
fontSize: 11,
|
|
color: color,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
|
|
// 회복량 표시
|
|
_HealBadge(potion: potion),
|
|
const SizedBox(width: 4),
|
|
|
|
// 수량
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
|
decoration: BoxDecoration(
|
|
color: color.withValues(alpha: 0.2),
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Text(
|
|
'x$quantity',
|
|
style: TextStyle(
|
|
fontSize: 10,
|
|
fontWeight: FontWeight.bold,
|
|
color: color,
|
|
),
|
|
),
|
|
),
|
|
|
|
// 전투 중 사용 불가 표시
|
|
if (isUsedThisBattle) ...[
|
|
const SizedBox(width: 4),
|
|
const Icon(Icons.block, size: 12, color: Colors.grey),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Color _getPotionColor() {
|
|
return switch (potion.type) {
|
|
PotionType.hp => Colors.red.shade700,
|
|
PotionType.mp => Colors.blue.shade700,
|
|
};
|
|
}
|
|
}
|
|
|
|
/// 물약 아이콘
|
|
class _PotionIcon extends StatelessWidget {
|
|
const _PotionIcon({required this.type, required this.tier});
|
|
|
|
final PotionType type;
|
|
final int tier;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final color = type == PotionType.hp
|
|
? Colors.red.shade400
|
|
: Colors.blue.shade400;
|
|
|
|
// 티어에 따른 아이콘 크기 조절
|
|
final size = 12.0 + tier * 1.0;
|
|
|
|
return Container(
|
|
width: 18,
|
|
height: 18,
|
|
alignment: Alignment.center,
|
|
child: Icon(
|
|
type == PotionType.hp ? Icons.favorite : Icons.bolt,
|
|
size: size.clamp(12, 18),
|
|
color: color,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 회복량 배지
|
|
class _HealBadge extends StatelessWidget {
|
|
const _HealBadge({required this.potion});
|
|
|
|
final Potion potion;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final healText = _buildHealText();
|
|
|
|
return Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey.shade200,
|
|
borderRadius: BorderRadius.circular(4),
|
|
),
|
|
child: Text(
|
|
healText,
|
|
style: TextStyle(fontSize: 9, color: Colors.grey.shade700),
|
|
),
|
|
);
|
|
}
|
|
|
|
String _buildHealText() {
|
|
final parts = <String>[];
|
|
|
|
if (potion.healAmount > 0) {
|
|
parts.add('+${potion.healAmount}');
|
|
}
|
|
|
|
if (potion.healPercent > 0) {
|
|
final percent = (potion.healPercent * 100).round();
|
|
parts.add('+$percent%');
|
|
}
|
|
|
|
return parts.join(' ');
|
|
}
|
|
}
|