style: dart format 적용
- 전체 Dart 소스 및 테스트 파일 포매팅 통일 - trailing comma, 줄바꿈, 인덴트 정리
This commit is contained in:
@@ -714,7 +714,10 @@ class _GamePlayScreenState extends State<GamePlayScreen>
|
||||
}
|
||||
|
||||
/// 데스크톱 앱바
|
||||
PreferredSizeWidget _buildDesktopAppBar(BuildContext context, GameState state) {
|
||||
PreferredSizeWidget _buildDesktopAppBar(
|
||||
BuildContext context,
|
||||
GameState state,
|
||||
) {
|
||||
return AppBar(
|
||||
backgroundColor: RetroColors.darkBrown,
|
||||
title: Text(
|
||||
@@ -969,9 +972,7 @@ class _GamePlayScreenState extends State<GamePlayScreen>
|
||||
// Potions (물약 인벤토리)
|
||||
_buildSectionHeader(game_l10n.uiPotions),
|
||||
Expanded(
|
||||
child: PotionInventoryPanel(
|
||||
inventory: state.potionInventory,
|
||||
),
|
||||
child: PotionInventoryPanel(inventory: state.potionInventory),
|
||||
),
|
||||
|
||||
// Encumbrance 바
|
||||
|
||||
@@ -35,8 +35,8 @@ class GameSessionController extends ChangeNotifier {
|
||||
DateTime Function()? now,
|
||||
StatisticsStorage? statisticsStorage,
|
||||
HallOfFameStorage? hallOfFameStorage,
|
||||
}) : _tickInterval = tickInterval,
|
||||
_now = now ?? DateTime.now {
|
||||
}) : _tickInterval = tickInterval,
|
||||
_now = now ?? DateTime.now {
|
||||
// 매니저 초기화
|
||||
_statisticsManager = GameStatisticsManager(
|
||||
statisticsStorage: statisticsStorage,
|
||||
@@ -136,9 +136,9 @@ class GameSessionController extends ChangeNotifier {
|
||||
int get speedBoostDuration => _speedBoostManager.speedBoostDuration;
|
||||
|
||||
int get speedBoostRemainingSeconds => _speedBoostManager.getRemainingSeconds(
|
||||
_monetization,
|
||||
_state?.skillSystem.elapsedMs ?? 0,
|
||||
);
|
||||
_monetization,
|
||||
_state?.skillSystem.elapsedMs ?? 0,
|
||||
);
|
||||
|
||||
int get currentSpeedMultiplier =>
|
||||
_speedBoostManager.getCurrentSpeedMultiplier(_loop);
|
||||
@@ -472,12 +472,12 @@ class GameSessionController extends ChangeNotifier {
|
||||
|
||||
/// 속도 부스트 활성화 (광고 시청 후)
|
||||
Future<bool> activateSpeedBoost() async {
|
||||
final (success, updatedMonetization) =
|
||||
await _speedBoostManager.activateSpeedBoost(
|
||||
loop: _loop,
|
||||
monetization: _monetization,
|
||||
currentElapsedMs: _state?.skillSystem.elapsedMs ?? 0,
|
||||
);
|
||||
final (success, updatedMonetization) = await _speedBoostManager
|
||||
.activateSpeedBoost(
|
||||
loop: _loop,
|
||||
monetization: _monetization,
|
||||
currentElapsedMs: _state?.skillSystem.elapsedMs ?? 0,
|
||||
);
|
||||
|
||||
if (success) {
|
||||
_monetization = updatedMonetization;
|
||||
|
||||
@@ -308,15 +308,14 @@ class _MobileCarouselLayoutState extends State<MobileCarouselLayout> {
|
||||
// 핸들 바
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8, bottom: 4),
|
||||
child: Container(
|
||||
width: 60,
|
||||
height: 4,
|
||||
color: border,
|
||||
),
|
||||
child: Container(width: 60, height: 4, color: border),
|
||||
),
|
||||
// 헤더
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 8,
|
||||
),
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: RetroColors.panelBgOf(context),
|
||||
@@ -515,7 +514,8 @@ class _MobileCarouselLayoutState extends State<MobileCarouselLayout> {
|
||||
],
|
||||
|
||||
// === 디버그 도구 섹션 ===
|
||||
if (kDebugMode && widget.onCreateTestCharacter != null) ...[
|
||||
if (kDebugMode &&
|
||||
widget.onCreateTestCharacter != null) ...[
|
||||
const SizedBox(height: 16),
|
||||
RetroMenuSection(
|
||||
title: L10n.of(context).debugToolsTitle,
|
||||
@@ -526,7 +526,9 @@ class _MobileCarouselLayoutState extends State<MobileCarouselLayout> {
|
||||
icon: Icons.science,
|
||||
iconColor: RetroColors.warningOf(context),
|
||||
label: L10n.of(context).debugCreateTestCharacter,
|
||||
subtitle: L10n.of(context).debugCreateTestCharacterDesc,
|
||||
subtitle: L10n.of(
|
||||
context,
|
||||
).debugCreateTestCharacterDesc,
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
_showTestCharacterDialog(context);
|
||||
|
||||
@@ -9,9 +9,8 @@ import 'package:asciineverdie/src/core/storage/statistics_storage.dart';
|
||||
/// 세션 통계와 누적 통계를 관리하고, 게임 상태 변화에 따라
|
||||
/// 통계를 자동 업데이트합니다.
|
||||
class GameStatisticsManager {
|
||||
GameStatisticsManager({
|
||||
StatisticsStorage? statisticsStorage,
|
||||
}) : _statisticsStorage = statisticsStorage ?? StatisticsStorage();
|
||||
GameStatisticsManager({StatisticsStorage? statisticsStorage})
|
||||
: _statisticsStorage = statisticsStorage ?? StatisticsStorage();
|
||||
|
||||
final StatisticsStorage _statisticsStorage;
|
||||
|
||||
|
||||
@@ -11,9 +11,8 @@ import 'package:flutter/foundation.dart';
|
||||
///
|
||||
/// 게임 클리어 시 캐릭터 등록, 테스트 캐릭터 생성 등을 담당합니다.
|
||||
class HallOfFameManager {
|
||||
HallOfFameManager({
|
||||
HallOfFameStorage? hallOfFameStorage,
|
||||
}) : _hallOfFameStorage = hallOfFameStorage ?? HallOfFameStorage();
|
||||
HallOfFameManager({HallOfFameStorage? hallOfFameStorage})
|
||||
: _hallOfFameStorage = hallOfFameStorage ?? HallOfFameStorage();
|
||||
|
||||
final HallOfFameStorage _hallOfFameStorage;
|
||||
|
||||
|
||||
@@ -107,7 +107,8 @@ class ResurrectionManager {
|
||||
updatedMonetization = monetization.copyWith(autoReviveEndMs: buffEndMs);
|
||||
|
||||
debugPrint(
|
||||
'[Resurrection] Ad revive complete, auto-revive buff until $buffEndMs ms');
|
||||
'[Resurrection] Ad revive complete, auto-revive buff until $buffEndMs ms',
|
||||
);
|
||||
}
|
||||
|
||||
// 유료 유저는 광고 없이 부활
|
||||
|
||||
@@ -49,8 +49,10 @@ class ReturnRewardsManager {
|
||||
|
||||
if (reward.hasReward) {
|
||||
_pendingReturnReward = reward;
|
||||
debugPrint('[ReturnRewards] Reward available: ${reward.chestCount} chests, '
|
||||
'${reward.hoursAway} hours away');
|
||||
debugPrint(
|
||||
'[ReturnRewards] Reward available: ${reward.chestCount} chests, '
|
||||
'${reward.hoursAway} hours away',
|
||||
);
|
||||
|
||||
// UI에서 다이얼로그 표시를 위해 콜백 호출
|
||||
// startNew 후에 호출하도록 딜레이
|
||||
@@ -91,11 +93,13 @@ class ReturnRewardsManager {
|
||||
loop?.replaceState(updatedState); // ProgressLoop 상태도 업데이트
|
||||
|
||||
// 저장
|
||||
unawaited(saveManager.saveState(
|
||||
updatedState,
|
||||
cheatsEnabled: cheatsEnabled,
|
||||
monetization: monetization,
|
||||
));
|
||||
unawaited(
|
||||
saveManager.saveState(
|
||||
updatedState,
|
||||
cheatsEnabled: cheatsEnabled,
|
||||
monetization: monetization,
|
||||
),
|
||||
);
|
||||
|
||||
_pendingReturnReward = null;
|
||||
|
||||
@@ -129,18 +133,19 @@ class ReturnRewardsManager {
|
||||
reward.equipment!.itemWeight > currentItem.itemWeight) {
|
||||
debugPrint('[ReturnRewards] Equipped: ${reward.equipment!.name}');
|
||||
return state.copyWith(
|
||||
equipment: state.equipment.setItemByIndex(
|
||||
slotIndex,
|
||||
reward.equipment!,
|
||||
),
|
||||
equipment: state.equipment.setItemByIndex(slotIndex, reward.equipment!),
|
||||
);
|
||||
}
|
||||
|
||||
// 더 좋지 않으면 판매 (골드로 변환)
|
||||
final sellPrice =
|
||||
(reward.equipment!.level * 50 * 0.3).round().clamp(1, 99999);
|
||||
debugPrint('[ReturnRewards] Sold: ${reward.equipment!.name} '
|
||||
'for $sellPrice gold');
|
||||
final sellPrice = (reward.equipment!.level * 50 * 0.3).round().clamp(
|
||||
1,
|
||||
99999,
|
||||
);
|
||||
debugPrint(
|
||||
'[ReturnRewards] Sold: ${reward.equipment!.name} '
|
||||
'for $sellPrice gold',
|
||||
);
|
||||
return state.copyWith(
|
||||
inventory: state.inventory.copyWith(
|
||||
gold: state.inventory.gold + sellPrice,
|
||||
@@ -152,8 +157,10 @@ class ReturnRewardsManager {
|
||||
GameState _applyPotionReward(GameState state, ChestReward reward) {
|
||||
if (reward.potionId == null) return state;
|
||||
|
||||
debugPrint('[ReturnRewards] Added potion: ${reward.potionId} '
|
||||
'x${reward.potionCount}');
|
||||
debugPrint(
|
||||
'[ReturnRewards] Added potion: ${reward.potionId} '
|
||||
'x${reward.potionCount}',
|
||||
);
|
||||
return state.copyWith(
|
||||
potionInventory: state.potionInventory.addPotion(
|
||||
reward.potionId!,
|
||||
|
||||
@@ -12,8 +12,8 @@ class SpeedBoostManager {
|
||||
SpeedBoostManager({
|
||||
required bool Function() cheatsEnabledGetter,
|
||||
required Future<List<int>> Function() getAvailableSpeeds,
|
||||
}) : _cheatsEnabledGetter = cheatsEnabledGetter,
|
||||
_getAvailableSpeeds = getAvailableSpeeds;
|
||||
}) : _cheatsEnabledGetter = cheatsEnabledGetter,
|
||||
_getAvailableSpeeds = getAvailableSpeeds;
|
||||
|
||||
final bool Function() _cheatsEnabledGetter;
|
||||
final Future<List<int>> Function() _getAvailableSpeeds;
|
||||
@@ -52,7 +52,10 @@ class SpeedBoostManager {
|
||||
int get speedBoostDuration => _speedBoostDuration;
|
||||
|
||||
/// 속도 부스트 남은 시간 (초) - 게임 시간(elapsedMs) 기준 계산
|
||||
int getRemainingSeconds(MonetizationState monetization, int currentElapsedMs) {
|
||||
int getRemainingSeconds(
|
||||
MonetizationState monetization,
|
||||
int currentElapsedMs,
|
||||
) {
|
||||
if (!_isSpeedBoostActive) return 0;
|
||||
final endMs = monetization.speedBoostEndMs;
|
||||
if (endMs == null) return 0;
|
||||
@@ -203,7 +206,10 @@ class SpeedBoostManager {
|
||||
if (_isSpeedBoostActive) {
|
||||
// 부스트 상태: 부스트 배속만 사용, 기본 배속 저장
|
||||
savedSpeedMultiplier = baseSpeed;
|
||||
return (speeds: [speedBoostMultiplier], initialSpeed: speedBoostMultiplier);
|
||||
return (
|
||||
speeds: [speedBoostMultiplier],
|
||||
initialSpeed: speedBoostMultiplier,
|
||||
);
|
||||
}
|
||||
// 일반 상태: 기본 배속 사용
|
||||
return (speeds: baseAvailableSpeeds, initialSpeed: baseSpeed);
|
||||
|
||||
@@ -37,9 +37,7 @@ class InventoryPage extends StatelessWidget {
|
||||
_buildSectionHeader(context, l10n.uiPotions),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: PotionInventoryPanel(
|
||||
inventory: potionInventory,
|
||||
),
|
||||
child: PotionInventoryPanel(inventory: potionInventory),
|
||||
),
|
||||
|
||||
// 무게 (Encumbrance)
|
||||
|
||||
@@ -147,7 +147,11 @@ class _SkillTile extends StatelessWidget {
|
||||
if (isOnCooldown)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(right: 8),
|
||||
child: Icon(Icons.hourglass_empty, size: 14, color: Colors.orange),
|
||||
child: Icon(
|
||||
Icons.hourglass_empty,
|
||||
size: 14,
|
||||
color: Colors.orange,
|
||||
),
|
||||
),
|
||||
_RankBadge(rank: rank),
|
||||
],
|
||||
@@ -273,10 +277,12 @@ class _SkillStatsGrid extends StatelessWidget {
|
||||
|
||||
// 공통: MP, 쿨타임
|
||||
entries.add(_StatEntry(l10n.skillMpCost, '${skill.mpCost}'));
|
||||
entries.add(_StatEntry(
|
||||
l10n.skillCooldown,
|
||||
'${(skill.cooldownMs / 1000).toStringAsFixed(1)}${l10n.skillSeconds}',
|
||||
));
|
||||
entries.add(
|
||||
_StatEntry(
|
||||
l10n.skillCooldown,
|
||||
'${(skill.cooldownMs / 1000).toStringAsFixed(1)}${l10n.skillSeconds}',
|
||||
),
|
||||
);
|
||||
|
||||
// 타입별 스탯 추가
|
||||
switch (skill.type) {
|
||||
@@ -309,33 +315,40 @@ class _SkillStatsGrid extends StatelessWidget {
|
||||
|
||||
// DOT 정보
|
||||
if (skill.isDot && skill.baseDotDamage != null) {
|
||||
final dotDps = skill.baseDotDamage! *
|
||||
final dotDps =
|
||||
skill.baseDotDamage! *
|
||||
(skill.baseDotDurationMs! / skill.baseDotTickMs!);
|
||||
entries.add(_StatEntry(l10n.skillDot, '${dotDps.round()}'));
|
||||
}
|
||||
|
||||
// HP 흡수
|
||||
if (skill.lifestealPercent > 0) {
|
||||
entries.add(_StatEntry(
|
||||
l10n.skillLifesteal,
|
||||
'${(skill.lifestealPercent * 100).round()}%',
|
||||
));
|
||||
entries.add(
|
||||
_StatEntry(
|
||||
l10n.skillLifesteal,
|
||||
'${(skill.lifestealPercent * 100).round()}%',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// 방어 무시
|
||||
if (skill.targetDefReduction > 0) {
|
||||
entries.add(_StatEntry(
|
||||
l10n.skillDefPen,
|
||||
'${(skill.targetDefReduction * 100).round()}%',
|
||||
));
|
||||
entries.add(
|
||||
_StatEntry(
|
||||
l10n.skillDefPen,
|
||||
'${(skill.targetDefReduction * 100).round()}%',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// 자해 데미지
|
||||
if (skill.selfDamagePercent > 0) {
|
||||
entries.add(_StatEntry(
|
||||
l10n.skillSelfDmg,
|
||||
'${(skill.selfDamagePercent * 100).round()}%',
|
||||
));
|
||||
entries.add(
|
||||
_StatEntry(
|
||||
l10n.skillSelfDmg,
|
||||
'${(skill.selfDamagePercent * 100).round()}%',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,10 +360,12 @@ class _SkillStatsGrid extends StatelessWidget {
|
||||
|
||||
// % 회복
|
||||
if (skill.healPercent > 0) {
|
||||
entries.add(_StatEntry(
|
||||
l10n.skillHealPercent,
|
||||
'${(skill.healPercent * 100).round()}%',
|
||||
));
|
||||
entries.add(
|
||||
_StatEntry(
|
||||
l10n.skillHealPercent,
|
||||
'${(skill.healPercent * 100).round()}%',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// MP 회복
|
||||
@@ -361,10 +376,12 @@ class _SkillStatsGrid extends StatelessWidget {
|
||||
// 부가 버프
|
||||
if (skill.buff != null) {
|
||||
final buff = skill.buff!;
|
||||
entries.add(_StatEntry(
|
||||
l10n.skillBuffDuration,
|
||||
'${(buff.durationMs / 1000).round()}${l10n.skillSeconds}',
|
||||
));
|
||||
entries.add(
|
||||
_StatEntry(
|
||||
l10n.skillBuffDuration,
|
||||
'${(buff.durationMs / 1000).round()}${l10n.skillSeconds}',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,39 +390,49 @@ class _SkillStatsGrid extends StatelessWidget {
|
||||
final buff = skill.buff!;
|
||||
|
||||
// 지속시간
|
||||
entries.add(_StatEntry(
|
||||
l10n.skillBuffDuration,
|
||||
'${(buff.durationMs / 1000).round()}${l10n.skillSeconds}',
|
||||
));
|
||||
entries.add(
|
||||
_StatEntry(
|
||||
l10n.skillBuffDuration,
|
||||
'${(buff.durationMs / 1000).round()}${l10n.skillSeconds}',
|
||||
),
|
||||
);
|
||||
|
||||
// 각 보정치
|
||||
if (buff.atkModifier != 0) {
|
||||
final sign = buff.atkModifier > 0 ? '+' : '';
|
||||
entries.add(_StatEntry(
|
||||
l10n.skillAtkMod,
|
||||
'$sign${(buff.atkModifier * 100).round()}%',
|
||||
));
|
||||
entries.add(
|
||||
_StatEntry(
|
||||
l10n.skillAtkMod,
|
||||
'$sign${(buff.atkModifier * 100).round()}%',
|
||||
),
|
||||
);
|
||||
}
|
||||
if (buff.defModifier != 0) {
|
||||
final sign = buff.defModifier > 0 ? '+' : '';
|
||||
entries.add(_StatEntry(
|
||||
l10n.skillDefMod,
|
||||
'$sign${(buff.defModifier * 100).round()}%',
|
||||
));
|
||||
entries.add(
|
||||
_StatEntry(
|
||||
l10n.skillDefMod,
|
||||
'$sign${(buff.defModifier * 100).round()}%',
|
||||
),
|
||||
);
|
||||
}
|
||||
if (buff.criRateModifier != 0) {
|
||||
final sign = buff.criRateModifier > 0 ? '+' : '';
|
||||
entries.add(_StatEntry(
|
||||
l10n.skillCriMod,
|
||||
'$sign${(buff.criRateModifier * 100).round()}%',
|
||||
));
|
||||
entries.add(
|
||||
_StatEntry(
|
||||
l10n.skillCriMod,
|
||||
'$sign${(buff.criRateModifier * 100).round()}%',
|
||||
),
|
||||
);
|
||||
}
|
||||
if (buff.evasionModifier != 0) {
|
||||
final sign = buff.evasionModifier > 0 ? '+' : '';
|
||||
entries.add(_StatEntry(
|
||||
l10n.skillEvaMod,
|
||||
'$sign${(buff.evasionModifier * 100).round()}%',
|
||||
));
|
||||
entries.add(
|
||||
_StatEntry(
|
||||
l10n.skillEvaMod,
|
||||
'$sign${(buff.evasionModifier * 100).round()}%',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,23 +441,23 @@ class _SkillStatsGrid extends StatelessWidget {
|
||||
final buff = skill.buff!;
|
||||
|
||||
// 지속시간
|
||||
entries.add(_StatEntry(
|
||||
l10n.skillBuffDuration,
|
||||
'${(buff.durationMs / 1000).round()}${l10n.skillSeconds}',
|
||||
));
|
||||
entries.add(
|
||||
_StatEntry(
|
||||
l10n.skillBuffDuration,
|
||||
'${(buff.durationMs / 1000).round()}${l10n.skillSeconds}',
|
||||
),
|
||||
);
|
||||
|
||||
// 디버프 효과 (보통 음수)
|
||||
if (buff.atkModifier != 0) {
|
||||
entries.add(_StatEntry(
|
||||
l10n.skillAtkMod,
|
||||
'${(buff.atkModifier * 100).round()}%',
|
||||
));
|
||||
entries.add(
|
||||
_StatEntry(l10n.skillAtkMod, '${(buff.atkModifier * 100).round()}%'),
|
||||
);
|
||||
}
|
||||
if (buff.defModifier != 0) {
|
||||
entries.add(_StatEntry(
|
||||
l10n.skillDefMod,
|
||||
'${(buff.defModifier * 100).round()}%',
|
||||
));
|
||||
entries.add(
|
||||
_StatEntry(l10n.skillDefMod, '${(buff.defModifier * 100).round()}%'),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,7 +333,8 @@ class DeathOverlay extends StatelessWidget {
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '[${_getSlotName(deathInfo.lostItemSlot)}] ',
|
||||
text:
|
||||
'[${_getSlotName(deathInfo.lostItemSlot)}] ',
|
||||
style: TextStyle(color: muted),
|
||||
),
|
||||
TextSpan(
|
||||
@@ -485,7 +486,10 @@ class DeathOverlay extends StatelessWidget {
|
||||
border: Border(
|
||||
top: BorderSide(color: gold, width: 3),
|
||||
left: BorderSide(color: gold, width: 3),
|
||||
bottom: BorderSide(color: goldDark.withValues(alpha: 0.8), width: 3),
|
||||
bottom: BorderSide(
|
||||
color: goldDark.withValues(alpha: 0.8),
|
||||
width: 3,
|
||||
),
|
||||
right: BorderSide(color: goldDark.withValues(alpha: 0.8), width: 3),
|
||||
),
|
||||
),
|
||||
@@ -495,10 +499,7 @@ class DeathOverlay extends StatelessWidget {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'✨',
|
||||
style: TextStyle(fontSize: 20, color: gold),
|
||||
),
|
||||
Text('✨', style: TextStyle(fontSize: 20, color: gold)),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
l10n.deathAdRevive.toUpperCase(),
|
||||
@@ -551,7 +552,8 @@ class DeathOverlay extends StatelessWidget {
|
||||
_buildBenefitRow(
|
||||
context,
|
||||
icon: '🔄',
|
||||
text: '${l10n.deathAdReviveItem}: ${deathInfo.lostItemName}',
|
||||
text:
|
||||
'${l10n.deathAdReviveItem}: ${deathInfo.lostItemName}',
|
||||
color: itemRarityColor,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
|
||||
@@ -83,7 +83,9 @@ class RetroOptionItem extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? gold.withValues(alpha: 0.15) : Colors.transparent,
|
||||
color: isSelected
|
||||
? gold.withValues(alpha: 0.15)
|
||||
: Colors.transparent,
|
||||
border: Border.all(
|
||||
color: isSelected ? gold : border,
|
||||
width: isSelected ? 2 : 1,
|
||||
@@ -101,7 +103,9 @@ class RetroOptionItem extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 18,
|
||||
color: isSelected ? gold : RetroColors.textPrimaryOf(context),
|
||||
color: isSelected
|
||||
? gold
|
||||
: RetroColors.textPrimaryOf(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -300,7 +300,9 @@ class _EnhancedAnimationPanelState extends State<EnhancedAnimationPanel>
|
||||
child: _buildBuffChip(
|
||||
icon: '⚡',
|
||||
label: '${widget.adSpeedMultiplier}x',
|
||||
remainingMs: widget.isPaidUser ? -1 : _speedBoostRemainingMs,
|
||||
remainingMs: widget.isPaidUser
|
||||
? -1
|
||||
: _speedBoostRemainingMs,
|
||||
color: Colors.orange,
|
||||
isPermanent: widget.isPaidUser,
|
||||
),
|
||||
@@ -401,7 +403,9 @@ class _EnhancedAnimationPanelState extends State<EnhancedAnimationPanel>
|
||||
child: SizedBox.expand(
|
||||
child: LinearProgressIndicator(
|
||||
value: ratio.clamp(0.0, 1.0),
|
||||
backgroundColor: Colors.red.withValues(alpha: 0.2),
|
||||
backgroundColor: Colors.red.withValues(
|
||||
alpha: 0.2,
|
||||
),
|
||||
valueColor: AlwaysStoppedAnimation(
|
||||
isLow ? Colors.red : Colors.red.shade600,
|
||||
),
|
||||
@@ -502,7 +506,9 @@ class _EnhancedAnimationPanelState extends State<EnhancedAnimationPanel>
|
||||
child: SizedBox.expand(
|
||||
child: LinearProgressIndicator(
|
||||
value: ratio.clamp(0.0, 1.0),
|
||||
backgroundColor: Colors.blue.withValues(alpha: 0.2),
|
||||
backgroundColor: Colors.blue.withValues(
|
||||
alpha: 0.2,
|
||||
),
|
||||
valueColor: AlwaysStoppedAnimation(
|
||||
Colors.blue.shade600,
|
||||
),
|
||||
@@ -619,7 +625,10 @@ class _EnhancedAnimationPanelState extends State<EnhancedAnimationPanel>
|
||||
color: Colors.black.withValues(alpha: 0.8),
|
||||
blurRadius: 2,
|
||||
),
|
||||
const Shadow(color: Colors.black, blurRadius: 4),
|
||||
const Shadow(
|
||||
color: Colors.black,
|
||||
blurRadius: 4,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -783,8 +792,9 @@ class _EnhancedAnimationPanelState extends State<EnhancedAnimationPanel>
|
||||
),
|
||||
TextSpan(
|
||||
text: _getStatusMessage(),
|
||||
style:
|
||||
gradeColor != null ? TextStyle(color: gradeColor) : null,
|
||||
style: gradeColor != null
|
||||
? TextStyle(color: gradeColor)
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -844,10 +854,7 @@ class _EnhancedAnimationPanelState extends State<EnhancedAnimationPanel>
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
icon,
|
||||
style: TextStyle(fontSize: 12, color: color),
|
||||
),
|
||||
Text(icon, style: TextStyle(fontSize: 12, color: color)),
|
||||
if (label != null) ...[
|
||||
const SizedBox(width: 2),
|
||||
Text(
|
||||
|
||||
@@ -326,8 +326,10 @@ class _HpMpBarState extends State<HpMpBar> with TickerProviderStateMixin {
|
||||
height: 14,
|
||||
decoration: BoxDecoration(
|
||||
color: emptyColor.withValues(alpha: 0.3),
|
||||
border:
|
||||
Border.all(color: RetroColors.panelBorderOuter, width: 1),
|
||||
border: Border.all(
|
||||
color: RetroColors.panelBorderOuter,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: List.generate(segmentCount, (index) {
|
||||
@@ -341,10 +343,8 @@ class _HpMpBarState extends State<HpMpBar> with TickerProviderStateMixin {
|
||||
border: Border(
|
||||
right: index < segmentCount - 1
|
||||
? BorderSide(
|
||||
color:
|
||||
RetroColors.panelBorderOuter.withValues(
|
||||
alpha: 0.3,
|
||||
),
|
||||
color: RetroColors.panelBorderOuter
|
||||
.withValues(alpha: 0.3),
|
||||
width: 1,
|
||||
)
|
||||
: BorderSide.none,
|
||||
|
||||
@@ -4,11 +4,7 @@ import 'package:asciineverdie/src/shared/retro_colors.dart';
|
||||
|
||||
/// 메뉴 섹션 타이틀
|
||||
class RetroMenuSection extends StatelessWidget {
|
||||
const RetroMenuSection({
|
||||
super.key,
|
||||
required this.title,
|
||||
this.color,
|
||||
});
|
||||
const RetroMenuSection({super.key, required this.title, this.color});
|
||||
|
||||
final String title;
|
||||
final Color? color;
|
||||
@@ -182,10 +178,7 @@ class RetroSpeedChip extends StatelessWidget {
|
||||
if (isAdBased && !isSelected && !isDisabled)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 2),
|
||||
child: Text(
|
||||
'▶',
|
||||
style: TextStyle(fontSize: 7, color: warning),
|
||||
),
|
||||
child: Text('▶', style: TextStyle(fontSize: 7, color: warning)),
|
||||
),
|
||||
Text(
|
||||
'${speed}x',
|
||||
|
||||
@@ -9,10 +9,7 @@ import 'package:asciineverdie/src/core/model/potion.dart';
|
||||
/// 보유 중인 물약 목록과 수량을 표시.
|
||||
/// HP 물약은 빨간색, MP 물약은 파란색으로 구분.
|
||||
class PotionInventoryPanel extends StatelessWidget {
|
||||
const PotionInventoryPanel({
|
||||
super.key,
|
||||
required this.inventory,
|
||||
});
|
||||
const PotionInventoryPanel({super.key, required this.inventory});
|
||||
|
||||
final PotionInventory inventory;
|
||||
|
||||
@@ -38,10 +35,7 @@ class PotionInventoryPanel extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
itemBuilder: (context, index) {
|
||||
final entry = potionEntries[index];
|
||||
return _PotionRow(
|
||||
potion: entry.potion,
|
||||
quantity: entry.quantity,
|
||||
);
|
||||
return _PotionRow(potion: entry.potion, quantity: entry.quantity);
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -82,10 +76,7 @@ class _PotionEntry {
|
||||
|
||||
/// 물약 행 위젯
|
||||
class _PotionRow extends StatelessWidget {
|
||||
const _PotionRow({
|
||||
required this.potion,
|
||||
required this.quantity,
|
||||
});
|
||||
const _PotionRow({required this.potion, required this.quantity});
|
||||
|
||||
final Potion potion;
|
||||
final int quantity;
|
||||
|
||||
@@ -264,7 +264,8 @@ class _ReturnRewardsDialogState extends State<ReturnRewardsDialog>
|
||||
return Transform.translate(
|
||||
offset: isOpening
|
||||
? Offset(
|
||||
_shakeAnimation.value * 2 *
|
||||
_shakeAnimation.value *
|
||||
2 *
|
||||
((_animController.value * 10).round() % 2 == 0
|
||||
? 1
|
||||
: -1),
|
||||
@@ -314,8 +315,8 @@ class _ReturnRewardsDialogState extends State<ReturnRewardsDialog>
|
||||
isGold
|
||||
? l10n.returnRewardOpenChests
|
||||
: (isPaidUser
|
||||
? l10n.returnRewardClaimBonusFree
|
||||
: l10n.returnRewardClaimBonus),
|
||||
? l10n.returnRewardClaimBonusFree
|
||||
: l10n.returnRewardClaimBonus),
|
||||
style: TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 10,
|
||||
@@ -365,10 +366,7 @@ class _ReturnRewardsDialogState extends State<ReturnRewardsDialog>
|
||||
count,
|
||||
(index) => Text(
|
||||
'📦',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
color: enabled ? null : muted,
|
||||
),
|
||||
style: TextStyle(fontSize: 24, color: enabled ? null : muted),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -387,7 +385,9 @@ class _ReturnRewardsDialogState extends State<ReturnRewardsDialog>
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: rewards.map((reward) => _buildRewardItem(context, reward)).toList(),
|
||||
children: rewards
|
||||
.map((reward) => _buildRewardItem(context, reward))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,10 +65,7 @@ class SpeedBoostButton extends StatelessWidget {
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'⚡',
|
||||
style: TextStyle(fontSize: 18, color: expColor),
|
||||
),
|
||||
Text('⚡', style: TextStyle(fontSize: 18, color: expColor)),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'${boostMultiplier}x',
|
||||
@@ -113,10 +110,7 @@ class SpeedBoostButton extends StatelessWidget {
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'⚡',
|
||||
style: TextStyle(fontSize: 18, color: gold),
|
||||
),
|
||||
Text('⚡', style: TextStyle(fontSize: 18, color: gold)),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'${boostMultiplier}x',
|
||||
@@ -130,10 +124,7 @@ class SpeedBoostButton extends StatelessWidget {
|
||||
if (!isPaidUser) ...[
|
||||
const SizedBox(width: 6),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 4,
|
||||
vertical: 2,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withValues(alpha: 0.2),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
|
||||
@@ -257,7 +257,11 @@ class _NewCharacterScreenState extends State<NewCharacterScreen> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (!isPaidUser) ...[
|
||||
const Icon(Icons.play_circle, size: 14, color: RetroColors.gold),
|
||||
const Icon(
|
||||
Icons.play_circle,
|
||||
size: 14,
|
||||
color: RetroColors.gold,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
],
|
||||
Text(
|
||||
|
||||
@@ -105,8 +105,9 @@ class _ClassInfo extends StatelessWidget {
|
||||
final percent = (passive.value * 100).round();
|
||||
return switch (passive.type) {
|
||||
ClassPassiveType.hpBonus => game_l10n.passiveHpBonus(percent),
|
||||
ClassPassiveType.physicalDamageBonus =>
|
||||
game_l10n.passivePhysicalBonus(percent),
|
||||
ClassPassiveType.physicalDamageBonus => game_l10n.passivePhysicalBonus(
|
||||
percent,
|
||||
),
|
||||
ClassPassiveType.defenseBonus => game_l10n.passiveDefenseBonus(percent),
|
||||
ClassPassiveType.magicDamageBonus => game_l10n.passiveMagicBonus(percent),
|
||||
ClassPassiveType.evasionBonus => game_l10n.passiveEvasionBonus(percent),
|
||||
|
||||
@@ -62,9 +62,15 @@ class StatsSection extends StatelessWidget {
|
||||
// 스탯 그리드
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: _StatTile(label: l10n.statStr, value: str)),
|
||||
Expanded(child: _StatTile(label: l10n.statCon, value: con)),
|
||||
Expanded(child: _StatTile(label: l10n.statDex, value: dex)),
|
||||
Expanded(
|
||||
child: _StatTile(label: l10n.statStr, value: str),
|
||||
),
|
||||
Expanded(
|
||||
child: _StatTile(label: l10n.statCon, value: con),
|
||||
),
|
||||
Expanded(
|
||||
child: _StatTile(label: l10n.statDex, value: dex),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@@ -73,8 +79,12 @@ class StatsSection extends StatelessWidget {
|
||||
Expanded(
|
||||
child: _StatTile(label: l10n.statInt, value: intelligence),
|
||||
),
|
||||
Expanded(child: _StatTile(label: l10n.statWis, value: wis)),
|
||||
Expanded(child: _StatTile(label: l10n.statCha, value: cha)),
|
||||
Expanded(
|
||||
child: _StatTile(label: l10n.statWis, value: wis),
|
||||
),
|
||||
Expanded(
|
||||
child: _StatTile(label: l10n.statCha, value: cha),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -116,10 +126,7 @@ class StatsSection extends StatelessWidget {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
_UndoButton(
|
||||
canUndo: canUndo,
|
||||
onPressed: onUndo,
|
||||
),
|
||||
_UndoButton(canUndo: canUndo, onPressed: onUndo),
|
||||
const SizedBox(width: 16),
|
||||
_RollButton(
|
||||
canRoll: canRoll,
|
||||
@@ -222,11 +229,7 @@ class _UndoButton extends StatelessWidget {
|
||||
children: [
|
||||
// 무료 유저는 광고 아이콘 표시
|
||||
if (!isPaidUser && canUndo) ...[
|
||||
const Icon(
|
||||
Icons.play_circle,
|
||||
size: 14,
|
||||
color: RetroColors.gold,
|
||||
),
|
||||
const Icon(Icons.play_circle, size: 14, color: RetroColors.gold),
|
||||
const SizedBox(width: 4),
|
||||
],
|
||||
Icon(
|
||||
@@ -240,7 +243,9 @@ class _UndoButton extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 11,
|
||||
color: canUndo ? RetroColors.textLight : RetroColors.textDisabled,
|
||||
color: canUndo
|
||||
? RetroColors.textLight
|
||||
: RetroColors.textDisabled,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user