fix(ui): 모든 화면에 SafeArea 적용
- new_character_screen: SafeArea(top: false) 추가 - mobile_carousel_layout: SafeArea(top: false) 추가 - hall_of_fame_screen: SafeArea(top: false) 추가 - 안드로이드 네비게이션 바에 UI가 가려지는 문제 해결
This commit is contained in:
@@ -1,16 +1,13 @@
|
||||
import 'package:flutter/foundation.dart' show kDebugMode;
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:askiineverdie/data/game_text_l10n.dart' as l10n;
|
||||
import 'package:askiineverdie/src/core/l10n/game_data_l10n.dart';
|
||||
import 'package:askiineverdie/src/core/model/combat_stats.dart';
|
||||
import 'package:askiineverdie/src/core/model/equipment_item.dart';
|
||||
import 'package:askiineverdie/src/core/model/equipment_slot.dart';
|
||||
import 'package:askiineverdie/src/core/model/game_state.dart';
|
||||
import 'package:askiineverdie/src/core/model/hall_of_fame.dart';
|
||||
import 'package:askiineverdie/src/core/model/item_stats.dart';
|
||||
import 'package:askiineverdie/src/core/storage/hall_of_fame_storage.dart';
|
||||
import 'package:askiineverdie/src/features/game/widgets/ascii_animation_card.dart';
|
||||
import 'package:asciineverdie/data/game_text_l10n.dart' as l10n;
|
||||
import 'package:asciineverdie/src/core/l10n/game_data_l10n.dart';
|
||||
import 'package:asciineverdie/src/core/model/equipment_slot.dart';
|
||||
import 'package:asciineverdie/src/core/model/game_state.dart';
|
||||
import 'package:asciineverdie/src/core/model/hall_of_fame.dart';
|
||||
import 'package:asciineverdie/src/core/model/item_stats.dart';
|
||||
import 'package:asciineverdie/src/core/storage/hall_of_fame_storage.dart';
|
||||
import 'package:asciineverdie/src/features/game/widgets/ascii_animation_card.dart';
|
||||
|
||||
/// 명예의 전당 화면 (Phase 10: Hall of Fame Screen)
|
||||
class HallOfFameScreen extends StatefulWidget {
|
||||
@@ -32,13 +29,7 @@ class _HallOfFameScreenState extends State<HallOfFameScreen> {
|
||||
}
|
||||
|
||||
Future<void> _loadHallOfFame() async {
|
||||
var hallOfFame = await _storage.load();
|
||||
|
||||
// 디버그 모드일 때 샘플 엔트리 추가 (빈 경우에만)
|
||||
if (kDebugMode && hallOfFame.isEmpty) {
|
||||
hallOfFame = hallOfFame.addEntry(_createDebugSampleEntry());
|
||||
hallOfFame = hallOfFame.addEntry(_createDebugSampleEntry2());
|
||||
}
|
||||
final hallOfFame = await _storage.load();
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
@@ -52,9 +43,12 @@ class _HallOfFameScreenState extends State<HallOfFameScreen> {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text(l10n.uiHallOfFame), centerTitle: true),
|
||||
body: _isLoading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: _buildContent(),
|
||||
body: SafeArea(
|
||||
top: false, // AppBar가 상단 처리
|
||||
child: _isLoading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: _buildContent(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -148,333 +142,6 @@ class _HallOfFameScreenState extends State<HallOfFameScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 디버그 모드 샘플 엔트리 생성 (kDebugMode에서만 사용)
|
||||
HallOfFameEntry _createDebugSampleEntry() {
|
||||
return HallOfFameEntry(
|
||||
id: 'debug_sample_001',
|
||||
characterName: 'Debug Hero',
|
||||
race: 'byte_human',
|
||||
klass: 'recursion_master',
|
||||
level: 100,
|
||||
totalPlayTimeMs: 10 * 60 * 60 * 1000, // 10시간
|
||||
totalDeaths: 3,
|
||||
monstersKilled: 1234,
|
||||
questsCompleted: 42,
|
||||
clearedAt: DateTime.now(),
|
||||
finalEquipment: [
|
||||
// 무기: Universe Simulator|15, 레벨 100 → plus=85
|
||||
const EquipmentItem(
|
||||
name: '+85 AI-Augmented Universe Simulator',
|
||||
slot: EquipmentSlot.weapon,
|
||||
level: 100,
|
||||
weight: 15,
|
||||
rarity: ItemRarity.legendary,
|
||||
stats: ItemStats(atk: 180, magAtk: 120, criRate: 0.15, attackSpeed: 600),
|
||||
),
|
||||
// 방패: Entropy Shield|65, 레벨 100 → plus=35
|
||||
const EquipmentItem(
|
||||
name: '+35 Air-gapped Entropy Shield',
|
||||
slot: EquipmentSlot.shield,
|
||||
level: 100,
|
||||
weight: 12,
|
||||
rarity: ItemRarity.legendary,
|
||||
stats: ItemStats(def: 85, magDef: 60, blockRate: 0.25),
|
||||
),
|
||||
// 방어구: Multiverse Armor|60, 레벨 100 → plus=40
|
||||
const EquipmentItem(
|
||||
name: '+40 Containerized Multiverse Armor',
|
||||
slot: EquipmentSlot.helm,
|
||||
level: 100,
|
||||
weight: 8,
|
||||
rarity: ItemRarity.legendary,
|
||||
stats: ItemStats(def: 45, magDef: 55, intBonus: 5),
|
||||
),
|
||||
// Singularity Barrier|55, 레벨 100 → plus=45
|
||||
const EquipmentItem(
|
||||
name: '+45 Quantum-safe Singularity Barrier',
|
||||
slot: EquipmentSlot.hauberk,
|
||||
level: 100,
|
||||
weight: 20,
|
||||
rarity: ItemRarity.legendary,
|
||||
stats: ItemStats(def: 95, magDef: 40, hpBonus: 200),
|
||||
),
|
||||
// AI Firewall|45, 레벨 100 → plus=55
|
||||
const EquipmentItem(
|
||||
name: '+55 Hardened AI Firewall',
|
||||
slot: EquipmentSlot.brassairts,
|
||||
level: 100,
|
||||
weight: 6,
|
||||
rarity: ItemRarity.epic,
|
||||
stats: ItemStats(def: 35, magDef: 25),
|
||||
),
|
||||
// Neural Network Mesh|40, 레벨 100 → plus=60
|
||||
const EquipmentItem(
|
||||
name: '+60 Encrypted Neural Network Mesh',
|
||||
slot: EquipmentSlot.vambraces,
|
||||
level: 100,
|
||||
weight: 5,
|
||||
rarity: ItemRarity.epic,
|
||||
stats: ItemStats(def: 30, magDef: 20, dexBonus: 3),
|
||||
),
|
||||
// Zero-Day Aegis|30, 레벨 100 → plus=70
|
||||
const EquipmentItem(
|
||||
name: '+70 Patched Zero-Day Aegis',
|
||||
slot: EquipmentSlot.gauntlets,
|
||||
level: 100,
|
||||
weight: 4,
|
||||
rarity: ItemRarity.epic,
|
||||
stats: ItemStats(def: 25, atk: 15, criRate: 0.05),
|
||||
),
|
||||
// Blockchain Platemail|35, 레벨 100 → plus=65
|
||||
const EquipmentItem(
|
||||
name: '+65 Certified Blockchain Platemail',
|
||||
slot: EquipmentSlot.gambeson,
|
||||
level: 100,
|
||||
weight: 10,
|
||||
rarity: ItemRarity.epic,
|
||||
stats: ItemStats(def: 40, magDef: 30),
|
||||
),
|
||||
// Container Suit|19, 레벨 100 → plus=81
|
||||
const EquipmentItem(
|
||||
name: '+81 Sandboxed Container Suit',
|
||||
slot: EquipmentSlot.cuisses,
|
||||
level: 100,
|
||||
weight: 8,
|
||||
rarity: ItemRarity.epic,
|
||||
stats: ItemStats(def: 35, evasion: 0.05),
|
||||
),
|
||||
// Virtualization Mail|20, 레벨 100 → plus=80
|
||||
const EquipmentItem(
|
||||
name: '+80 Patched Virtualization Mail',
|
||||
slot: EquipmentSlot.greaves,
|
||||
level: 100,
|
||||
weight: 7,
|
||||
rarity: ItemRarity.epic,
|
||||
stats: ItemStats(def: 30, dexBonus: 2),
|
||||
),
|
||||
// Sandbox Shell|18, 레벨 100 → plus=82
|
||||
const EquipmentItem(
|
||||
name: '+82 Hardened Sandbox Shell',
|
||||
slot: EquipmentSlot.sollerets,
|
||||
level: 100,
|
||||
weight: 5,
|
||||
rarity: ItemRarity.epic,
|
||||
stats: ItemStats(def: 20, evasion: 0.03),
|
||||
),
|
||||
],
|
||||
// 레벨 100 캐릭터의 스펠: randomLow 분포로 낮은 인덱스 스펠이 높은 랭크
|
||||
// 100번의 레벨업 = 100번 스펠 학습 기회, 초반 스펠은 여러 번 학습되어 랭크 상승
|
||||
finalSpells: [
|
||||
{'name': 'Garbage Collection', 'rank': 'XIV'}, // 인덱스 0 - 가장 많이 학습
|
||||
{'name': 'Memory Optimization', 'rank': 'XII'}, // 인덱스 1
|
||||
{'name': 'Debug Mode', 'rank': 'XI'}, // 인덱스 2
|
||||
{'name': 'Breakpoint', 'rank': 'X'}, // 인덱스 3
|
||||
{'name': 'Step Over', 'rank': 'IX'}, // 인덱스 4
|
||||
{'name': 'Step Into', 'rank': 'VIII'}, // 인덱스 5
|
||||
{'name': 'Watch Variable', 'rank': 'VII'}, // 인덱스 6
|
||||
{'name': 'Hot Reload', 'rank': 'VI'}, // 인덱스 7
|
||||
{'name': 'Cold Boot', 'rank': 'V'}, // 인덱스 8
|
||||
{'name': 'Safe Mode', 'rank': 'IV'}, // 인덱스 9
|
||||
{'name': 'Kernel Panic', 'rank': 'III'}, // 인덱스 10
|
||||
{'name': 'Blue Screen', 'rank': 'II'}, // 인덱스 11
|
||||
{'name': 'Stack Trace', 'rank': 'I'}, // 인덱스 12
|
||||
],
|
||||
// 레벨 100 기본 스탯: 시작 ~60 + 99레벨 × 2스탯 = ~258 총합
|
||||
// recursion_master (마법사 계열): INT/WIS 집중 빌드
|
||||
// CombatStats는 게임 공식 CombatStats.fromStats()에 따라 계산
|
||||
// baseAtk = STR*2 + level + equipStats.atk = 32*2 + 100 + 195 = 359
|
||||
// baseDef = CON + level/2 + equipStats.def = 38 + 50 + 440 = 528
|
||||
// baseMagAtk = INT*2 + level + equipStats.magAtk = 65*2 + 100 + 120 = 350
|
||||
// baseMagDef = WIS + level/2 + equipStats.magDef = 55 + 50 + 210 = 315
|
||||
finalStats: const CombatStats(
|
||||
str: 32,
|
||||
con: 38,
|
||||
dex: 45,
|
||||
intelligence: 65,
|
||||
wis: 55,
|
||||
cha: 23,
|
||||
atk: 359,
|
||||
def: 528,
|
||||
magAtk: 350,
|
||||
magDef: 315,
|
||||
criRate: 0.32,
|
||||
criDamage: 1.95,
|
||||
evasion: 0.30,
|
||||
accuracy: 0.89,
|
||||
blockRate: 0.37,
|
||||
parryRate: 0.15,
|
||||
attackDelayMs: 650,
|
||||
hpMax: 1850,
|
||||
hpCurrent: 1850,
|
||||
mpMax: 2100,
|
||||
mpCurrent: 2100,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 디버그 모드 샘플 엔트리 2 (전사 계열 캐릭터)
|
||||
HallOfFameEntry _createDebugSampleEntry2() {
|
||||
return HallOfFameEntry(
|
||||
id: 'debug_sample_002',
|
||||
characterName: 'Binary Knight',
|
||||
race: 'null_elf',
|
||||
klass: 'overflow_warrior',
|
||||
level: 95,
|
||||
totalPlayTimeMs: 8 * 60 * 60 * 1000 + 30 * 60 * 1000, // 8시간 30분
|
||||
totalDeaths: 7,
|
||||
monstersKilled: 2156,
|
||||
questsCompleted: 38,
|
||||
clearedAt: DateTime.now().subtract(const Duration(days: 3)),
|
||||
finalEquipment: [
|
||||
// 무기: Quantum Entangler|10, 레벨 95 → plus=85
|
||||
const EquipmentItem(
|
||||
name: '+85 GPU-Powered Quantum Entangler',
|
||||
slot: EquipmentSlot.weapon,
|
||||
level: 95,
|
||||
weight: 18,
|
||||
rarity: ItemRarity.legendary,
|
||||
stats: ItemStats(atk: 220, criRate: 0.12, parryRate: 0.08, attackSpeed: 850),
|
||||
),
|
||||
// 방패: Multiverse Barrier|50, 레벨 95 → plus=45
|
||||
const EquipmentItem(
|
||||
name: '+45 Air-gapped Multiverse Barrier',
|
||||
slot: EquipmentSlot.shield,
|
||||
level: 95,
|
||||
weight: 16,
|
||||
rarity: ItemRarity.legendary,
|
||||
stats: ItemStats(def: 120, magDef: 45, blockRate: 0.35, hpBonus: 150),
|
||||
),
|
||||
// Multiverse Armor|60, 레벨 95 → plus=35
|
||||
const EquipmentItem(
|
||||
name: '+35 Certified Multiverse Armor',
|
||||
slot: EquipmentSlot.helm,
|
||||
level: 95,
|
||||
weight: 10,
|
||||
rarity: ItemRarity.legendary,
|
||||
stats: ItemStats(def: 55, conBonus: 4),
|
||||
),
|
||||
// Quantum Shield Matrix|50, 레벨 95 → plus=45
|
||||
const EquipmentItem(
|
||||
name: '+45 Containerized Quantum Shield Matrix',
|
||||
slot: EquipmentSlot.hauberk,
|
||||
level: 95,
|
||||
weight: 25,
|
||||
rarity: ItemRarity.legendary,
|
||||
stats: ItemStats(def: 110, hpBonus: 300, conBonus: 3),
|
||||
),
|
||||
// ASLR Armor|17, 레벨 95 → plus=78
|
||||
const EquipmentItem(
|
||||
name: '+78 Patched ASLR Armor',
|
||||
slot: EquipmentSlot.brassairts,
|
||||
level: 95,
|
||||
weight: 8,
|
||||
rarity: ItemRarity.epic,
|
||||
stats: ItemStats(def: 40, strBonus: 2),
|
||||
),
|
||||
// Stack Protector|15, 레벨 95 → plus=80
|
||||
const EquipmentItem(
|
||||
name: '+80 Encrypted Stack Protector',
|
||||
slot: EquipmentSlot.vambraces,
|
||||
level: 95,
|
||||
weight: 6,
|
||||
rarity: ItemRarity.epic,
|
||||
stats: ItemStats(def: 35, atk: 10),
|
||||
),
|
||||
// Heap Guard|16, 레벨 95 → plus=79
|
||||
const EquipmentItem(
|
||||
name: '+79 Hardened Heap Guard',
|
||||
slot: EquipmentSlot.gauntlets,
|
||||
level: 95,
|
||||
weight: 5,
|
||||
rarity: ItemRarity.epic,
|
||||
stats: ItemStats(def: 30, atk: 25, criRate: 0.03),
|
||||
),
|
||||
// Memory Barrier|14, 레벨 95 → plus=81
|
||||
const EquipmentItem(
|
||||
name: '+81 Quantum-safe Memory Barrier',
|
||||
slot: EquipmentSlot.gambeson,
|
||||
level: 95,
|
||||
weight: 12,
|
||||
rarity: ItemRarity.epic,
|
||||
stats: ItemStats(def: 45, magDef: 20),
|
||||
),
|
||||
// Kernel Guard|12, 레벨 95 → plus=83
|
||||
const EquipmentItem(
|
||||
name: '+83 Certified Kernel Guard',
|
||||
slot: EquipmentSlot.cuisses,
|
||||
level: 95,
|
||||
weight: 10,
|
||||
rarity: ItemRarity.epic,
|
||||
stats: ItemStats(def: 42, strBonus: 2),
|
||||
),
|
||||
// Protocol Suit|10, 레벨 95 → plus=85
|
||||
const EquipmentItem(
|
||||
name: '+85 Sandboxed Protocol Suit',
|
||||
slot: EquipmentSlot.greaves,
|
||||
level: 95,
|
||||
weight: 8,
|
||||
rarity: ItemRarity.epic,
|
||||
stats: ItemStats(def: 38, dexBonus: 2),
|
||||
),
|
||||
// Encryption Layer|6, 레벨 95 → plus=89
|
||||
const EquipmentItem(
|
||||
name: '+89 Patched Encryption Layer',
|
||||
slot: EquipmentSlot.sollerets,
|
||||
level: 95,
|
||||
weight: 6,
|
||||
rarity: ItemRarity.epic,
|
||||
stats: ItemStats(def: 25, evasion: 0.02),
|
||||
),
|
||||
],
|
||||
// 레벨 95 캐릭터의 스펠: randomLow 분포 적용
|
||||
// 95번의 레벨업 기회, 전사 계열이라 WIS가 낮아 학습 가능 스펠 범위 제한
|
||||
// WIS 30 + level 95 = 125 → 대부분의 스펠 접근 가능
|
||||
finalSpells: [
|
||||
{'name': 'Garbage Collection', 'rank': 'XIII'}, // 인덱스 0
|
||||
{'name': 'Memory Optimization', 'rank': 'XI'}, // 인덱스 1
|
||||
{'name': 'Debug Mode', 'rank': 'X'}, // 인덱스 2
|
||||
{'name': 'Breakpoint', 'rank': 'IX'}, // 인덱스 3
|
||||
{'name': 'Step Over', 'rank': 'VIII'}, // 인덱스 4
|
||||
{'name': 'Step Into', 'rank': 'VII'}, // 인덱스 5
|
||||
{'name': 'Watch Variable', 'rank': 'VI'}, // 인덱스 6
|
||||
{'name': 'Hot Reload', 'rank': 'V'}, // 인덱스 7
|
||||
{'name': 'Cold Boot', 'rank': 'IV'}, // 인덱스 8
|
||||
{'name': 'Safe Mode', 'rank': 'III'}, // 인덱스 9
|
||||
{'name': 'Kernel Panic', 'rank': 'II'}, // 인덱스 10
|
||||
],
|
||||
// 레벨 95 기본 스탯: 시작 ~60 + 94레벨 × 2스탯 = ~248 총합
|
||||
// overflow_warrior (전사 계열): STR/CON 집중 빌드
|
||||
// CombatStats는 게임 공식에 따라 계산
|
||||
// baseAtk = STR*2 + level + equipStats.atk = 58*2 + 95 + 255 = 466
|
||||
// baseDef = CON + level/2 + equipStats.def = 55 + 47 + 577 = 679
|
||||
// baseMagAtk = INT*2 + level + equipStats.magAtk = 28*2 + 95 + 0 = 151
|
||||
// baseMagDef = WIS + level/2 + equipStats.magDef = 30 + 47 + 65 = 142
|
||||
finalStats: const CombatStats(
|
||||
str: 58,
|
||||
con: 55,
|
||||
dex: 42,
|
||||
intelligence: 28,
|
||||
wis: 30,
|
||||
cha: 35,
|
||||
atk: 466,
|
||||
def: 679,
|
||||
magAtk: 151,
|
||||
magDef: 142,
|
||||
criRate: 0.26,
|
||||
criDamage: 1.92,
|
||||
evasion: 0.23,
|
||||
accuracy: 0.88,
|
||||
blockRate: 0.47,
|
||||
parryRate: 0.28,
|
||||
attackDelayMs: 800,
|
||||
hpMax: 2200,
|
||||
hpCurrent: 2200,
|
||||
mpMax: 1100,
|
||||
mpCurrent: 1100,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 명예의 전당 엔트리 카드
|
||||
class _HallOfFameEntryCard extends StatelessWidget {
|
||||
const _HallOfFameEntryCard({required this.entry, required this.rank});
|
||||
|
||||
Reference in New Issue
Block a user