refactoring : barrel pattern

This commit is contained in:
2025-12-09 14:40:25 +09:00
parent ac4df02654
commit bb3b34c9b1
36 changed files with 708 additions and 497 deletions
+71
View File
@@ -0,0 +1,71 @@
import 'package:flutter/material.dart';
import '../../game/enums.dart';
import '../../game/config.dart';
class BattleControls extends StatelessWidget {
final bool isAttackEnabled;
final bool isDefendEnabled;
final VoidCallback onAttackPressed;
final VoidCallback onDefendPressed;
const BattleControls({
super.key,
required this.isAttackEnabled,
required this.isDefendEnabled,
required this.onAttackPressed,
required this.onDefendPressed,
});
Widget _buildFloatingActionButton({
required String label,
required Color color,
required ActionType actionType,
required bool isEnabled,
required VoidCallback onPressed,
}) {
String iconPath;
if (actionType == ActionType.attack) {
iconPath = 'assets/data/icon/icon_weapon.png';
} else {
iconPath = 'assets/data/icon/icon_shield.png';
}
return FloatingActionButton(
heroTag: label,
onPressed: isEnabled ? onPressed : null,
backgroundColor: isEnabled ? color : ThemeConfig.btnDisabled,
child: Image.asset(
iconPath,
width: 32,
height: 32,
color: ThemeConfig.textColorWhite, // Tint icon white
fit: BoxFit.contain,
filterQuality: FilterQuality.high,
),
);
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
_buildFloatingActionButton(
label: "ATK",
color: ThemeConfig.btnActionActive,
actionType: ActionType.attack,
isEnabled: isAttackEnabled,
onPressed: onAttackPressed,
),
const SizedBox(height: 16),
_buildFloatingActionButton(
label: "DEF",
color: ThemeConfig.btnDefendActive,
actionType: ActionType.defend,
isEnabled: isDefendEnabled,
onPressed: onDefendPressed,
),
],
);
}
}
+73
View File
@@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import '../../providers.dart';
import '../../game/config.dart';
import 'package:provider/provider.dart';
class BattleHeader extends StatelessWidget {
const BattleHeader({super.key});
String _getStageDisplayString(int stage) {
// 3 Stages per Tier logic
// Tier 1: 1, 2, 3 -> Underground Illegal Arena
// Tier 2: 4, 5, 6 -> Colosseum
// Tier 3: 7, 8, 9 -> King's Arena
final int tier = (stage - 1) ~/ 3 + 1;
final int round = (stage - 1) % 3 + 1;
String tierName = "";
switch (tier) {
case 1:
tierName = "지하 불법 투기장";
break;
case 2:
tierName = "콜로세움";
break;
case 3:
default:
tierName = "왕의 투기장";
break;
}
return "Tier $tier $tierName - $round";
}
@override
Widget build(BuildContext context) {
final battleProvider = context.watch<BattleProvider>();
return Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: FittedBox(
fit: BoxFit.scaleDown,
child: Text(
_getStageDisplayString(battleProvider.stage),
style: const TextStyle(
color: ThemeConfig.textColorWhite,
fontSize: ThemeConfig.fontSizeLarge,
fontWeight: ThemeConfig.fontWeightBold,
),
),
),
),
Flexible(
child: FittedBox(
fit: BoxFit.scaleDown,
child: Text(
"${AppStrings.turn} ${battleProvider.turnCount}",
style: const TextStyle(
color: ThemeConfig.textColorWhite,
fontSize: ThemeConfig.fontSizeHeader,
),
),
),
),
],
),
);
}
}
@@ -1,11 +1,10 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../game/model/entity.dart';
import '../../game/models.dart';
import '../../game/enums.dart';
import '../../providers/battle_provider.dart';
import '../../providers.dart';
import 'battle_animation_widget.dart';
import '../../game/config/theme_config.dart';
import '../../game/config/animation_config.dart';
import '../../game/config.dart';
class CharacterStatusCard extends StatelessWidget {
final Character character;
@@ -1,7 +1,6 @@
import 'package:flutter/material.dart';
import '../../game/config/theme_config.dart';
import '../../game/config/animation_config.dart';
import '../../game/config.dart';
class FloatingDamageText extends StatefulWidget {
final String damage;
@@ -0,0 +1,92 @@
import 'package:flutter/material.dart';
import '../../game/enums.dart';
import '../../game/models.dart';
import '../../game/config.dart';
class RiskSelectionDialog extends StatelessWidget {
final ActionType actionType;
final Character player;
final Function(RiskLevel) onSelected;
const RiskSelectionDialog({
super.key,
required this.actionType,
required this.player,
required this.onSelected,
});
@override
Widget build(BuildContext context) {
final baseValue = actionType == ActionType.attack
? player.totalAtk
: player.totalDefense;
return SimpleDialog(
title: Text("Select Risk Level for ${actionType.name}"),
children: RiskLevel.values.map((risk) {
String infoText = "";
Color infoColor = Colors.black;
double efficiency = 0.0;
int expectedValue = 0;
switch (risk) {
case RiskLevel.safe:
efficiency = actionType == ActionType.attack
? BattleConfig.attackSafeEfficiency
: BattleConfig.defendSafeEfficiency;
infoColor = ThemeConfig.riskSafe;
break;
case RiskLevel.normal:
efficiency = actionType == ActionType.attack
? BattleConfig.attackNormalEfficiency
: BattleConfig.defendNormalEfficiency;
infoColor = ThemeConfig.riskNormal;
break;
case RiskLevel.risky:
efficiency = actionType == ActionType.attack
? BattleConfig.attackRiskyEfficiency
: BattleConfig.defendRiskyEfficiency;
infoColor = ThemeConfig.riskRisky;
break;
}
expectedValue = (baseValue * efficiency).toInt();
String valueUnit = actionType == ActionType.attack ? "Dmg" : "Armor";
double baseChance = 0.0;
switch (risk) {
case RiskLevel.safe:
baseChance = BattleConfig.safeBaseChance;
break;
case RiskLevel.normal:
baseChance = BattleConfig.normalBaseChance;
break;
case RiskLevel.risky:
baseChance = BattleConfig.riskyBaseChance;
break;
}
double finalChance = baseChance + (player.totalLuck / 100.0);
if (finalChance > 1.0) finalChance = 1.0;
String successRate = "${(finalChance * 100).toInt()}%";
infoText =
"Success: $successRate, Eff: ${(efficiency * 100).toInt()}% ($expectedValue $valueUnit)";
return SimpleDialogOption(
onPressed: () => onSelected(risk),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
risk.name,
style: const TextStyle(fontWeight: FontWeight.bold),
),
Text(infoText, style: TextStyle(fontSize: 12, color: infoColor)),
],
),
);
}).toList(),
);
}
}