refactor(ui): 위젯 분리 및 화면 개선
- game_play_screen에서 desktop 패널 위젯 분리 - death_overlay에서 death_buttons, death_combat_log 분리 - mobile_carousel_layout에서 mobile_options_menu 분리 - 아레나 위젯 개선 (arena_hp_bar, result_panel 등) - settings_screen에서 retro_settings_widgets 분리 - 기타 위젯 리팩토링 및 import 경로 업데이트
This commit is contained in:
212
lib/src/features/game/widgets/desktop_quest_panel.dart
Normal file
212
lib/src/features/game/widgets/desktop_quest_panel.dart
Normal file
@@ -0,0 +1,212 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:asciineverdie/l10n/app_localizations.dart';
|
||||
import 'package:asciineverdie/src/core/model/game_state.dart';
|
||||
import 'package:asciineverdie/src/core/util/pq_logic.dart' as pq_logic;
|
||||
import 'package:asciineverdie/src/core/util/roman.dart' show intToRoman;
|
||||
import 'package:asciineverdie/src/features/game/widgets/desktop_panel_widgets.dart';
|
||||
import 'package:asciineverdie/src/shared/retro_colors.dart';
|
||||
|
||||
/// 데스크톱 우측 패널: Plot/Quest
|
||||
///
|
||||
/// Plot Development, Quests 목록 및 프로그레스 바 표시
|
||||
class DesktopQuestPanel extends StatelessWidget {
|
||||
const DesktopQuestPanel({super.key, required this.state});
|
||||
|
||||
final GameState state;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = L10n.of(context);
|
||||
return Card(
|
||||
margin: const EdgeInsets.all(4),
|
||||
color: RetroColors.panelBg,
|
||||
shape: RoundedRectangleBorder(
|
||||
side: const BorderSide(
|
||||
color: RetroColors.panelBorderOuter,
|
||||
width: 2,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
DesktopPanelHeader(title: l10n.plotDevelopment),
|
||||
Expanded(child: _PlotList(state: state)),
|
||||
DesktopSegmentProgressBar(
|
||||
position: state.progress.plot.position,
|
||||
max: state.progress.plot.max,
|
||||
color: Colors.purple,
|
||||
tooltip: state.progress.plot.max > 0
|
||||
? '${pq_logic.roughTime(state.progress.plot.max - state.progress.plot.position)} remaining'
|
||||
: null,
|
||||
),
|
||||
DesktopPanelHeader(title: l10n.quests),
|
||||
Expanded(child: _QuestList(state: state)),
|
||||
DesktopSegmentProgressBar(
|
||||
position: state.progress.quest.position,
|
||||
max: state.progress.quest.max,
|
||||
color: Colors.green,
|
||||
tooltip: state.progress.quest.max > 0
|
||||
? l10n.percentComplete(
|
||||
100 *
|
||||
state.progress.quest.position ~/
|
||||
state.progress.quest.max,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Plot 목록 위젯
|
||||
class _PlotList extends StatelessWidget {
|
||||
const _PlotList({required this.state});
|
||||
|
||||
final GameState state;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = L10n.of(context);
|
||||
final plotCount = state.progress.plotStageCount;
|
||||
if (plotCount == 0) {
|
||||
return Center(
|
||||
child: Text(
|
||||
l10n.prologue.toUpperCase(),
|
||||
style: const TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 14,
|
||||
color: RetroColors.textDisabled,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: plotCount,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
itemBuilder: (context, index) {
|
||||
final isCompleted = index < plotCount - 1;
|
||||
final isCurrent = index == plotCount - 1;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 1),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
isCompleted
|
||||
? Icons.check_box
|
||||
: (isCurrent
|
||||
? Icons.arrow_right
|
||||
: Icons.check_box_outline_blank),
|
||||
size: 12,
|
||||
color: isCompleted
|
||||
? RetroColors.expGreen
|
||||
: (isCurrent
|
||||
? RetroColors.gold
|
||||
: RetroColors.textDisabled),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Expanded(
|
||||
child: Text(
|
||||
index == 0
|
||||
? l10n.prologue
|
||||
: l10n.actNumber(intToRoman(index)),
|
||||
style: TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 13,
|
||||
color: isCompleted
|
||||
? RetroColors.textDisabled
|
||||
: (isCurrent
|
||||
? RetroColors.gold
|
||||
: RetroColors.textLight),
|
||||
decoration: isCompleted
|
||||
? TextDecoration.lineThrough
|
||||
: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Quest 목록 위젯
|
||||
class _QuestList extends StatelessWidget {
|
||||
const _QuestList({required this.state});
|
||||
|
||||
final GameState state;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = L10n.of(context);
|
||||
final questHistory = state.progress.questHistory;
|
||||
|
||||
if (questHistory.isEmpty) {
|
||||
return Center(
|
||||
child: Text(
|
||||
l10n.noActiveQuests.toUpperCase(),
|
||||
style: const TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 14,
|
||||
color: RetroColors.textDisabled,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: questHistory.length,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
itemBuilder: (context, index) {
|
||||
final quest = questHistory[index];
|
||||
final isCurrentQuest =
|
||||
index == questHistory.length - 1 && !quest.isComplete;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 1),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
isCurrentQuest
|
||||
? Icons.arrow_right
|
||||
: (quest.isComplete
|
||||
? Icons.check_box
|
||||
: Icons.check_box_outline_blank),
|
||||
size: 12,
|
||||
color: isCurrentQuest
|
||||
? RetroColors.gold
|
||||
: (quest.isComplete
|
||||
? RetroColors.expGreen
|
||||
: RetroColors.textDisabled),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Expanded(
|
||||
child: Text(
|
||||
quest.caption,
|
||||
style: TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 13,
|
||||
color: isCurrentQuest
|
||||
? RetroColors.gold
|
||||
: (quest.isComplete
|
||||
? RetroColors.textDisabled
|
||||
: RetroColors.textLight),
|
||||
decoration: quest.isComplete
|
||||
? TextDecoration.lineThrough
|
||||
: TextDecoration.none,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user