feat(ui): 화면들에 레트로 UI 스타일 적용
- front_screen: 레트로 패널 및 버튼 스타일 - game_play_screen: 레트로 색상 및 초기 BGM 로직 개선 - mobile_carousel_layout: 레트로 테마 적용 - carousel_nav_bar: 골드 액센트 색상 적용
This commit is contained in:
@@ -3,6 +3,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:askiineverdie/data/game_text_l10n.dart' as game_l10n;
|
import 'package:askiineverdie/data/game_text_l10n.dart' as game_l10n;
|
||||||
import 'package:askiineverdie/l10n/app_localizations.dart';
|
import 'package:askiineverdie/l10n/app_localizations.dart';
|
||||||
import 'package:askiineverdie/src/features/front/widgets/hero_vs_boss_animation.dart';
|
import 'package:askiineverdie/src/features/front/widgets/hero_vs_boss_animation.dart';
|
||||||
|
import 'package:askiineverdie/src/shared/retro_colors.dart';
|
||||||
|
import 'package:askiineverdie/src/shared/widgets/retro_widgets.dart';
|
||||||
|
|
||||||
class FrontScreen extends StatelessWidget {
|
class FrontScreen extends StatelessWidget {
|
||||||
const FrontScreen({
|
const FrontScreen({
|
||||||
@@ -60,142 +62,120 @@ class FrontScreen extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
|
||||||
final colorScheme = theme.colorScheme;
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Container(
|
backgroundColor: RetroColors.deepBrown,
|
||||||
decoration: BoxDecoration(
|
body: SafeArea(
|
||||||
gradient: LinearGradient(
|
child: Column(
|
||||||
colors: [colorScheme.surfaceContainerHighest, colorScheme.surface],
|
children: [
|
||||||
begin: Alignment.topLeft,
|
// 스크롤 영역 (헤더, 애니메이션, 버튼)
|
||||||
end: Alignment.bottomRight,
|
Expanded(
|
||||||
),
|
child: Center(
|
||||||
),
|
child: ConstrainedBox(
|
||||||
child: SafeArea(
|
constraints: const BoxConstraints(maxWidth: 800),
|
||||||
child: Column(
|
child: SingleChildScrollView(
|
||||||
children: [
|
padding: const EdgeInsets.all(16),
|
||||||
// 스크롤 영역 (헤더, 애니메이션, 버튼)
|
child: Column(
|
||||||
Expanded(
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
child: Center(
|
children: [
|
||||||
child: ConstrainedBox(
|
const _RetroHeader(),
|
||||||
constraints: const BoxConstraints(maxWidth: 960),
|
const SizedBox(height: 16),
|
||||||
child: SingleChildScrollView(
|
const _AnimationPanel(),
|
||||||
padding: const EdgeInsets.all(24),
|
const SizedBox(height: 16),
|
||||||
child: Column(
|
_ActionButtons(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
onNewCharacter: onNewCharacter != null
|
||||||
children: [
|
? () => _handleNewCharacter(context)
|
||||||
_HeroHeader(theme: theme, colorScheme: colorScheme),
|
: null,
|
||||||
const SizedBox(height: 20),
|
onLoadSave: onLoadSave != null
|
||||||
const HeroVsBossAnimation(),
|
? () => onLoadSave!(context)
|
||||||
const SizedBox(height: 24),
|
: null,
|
||||||
_ActionButtons(
|
onHallOfFame: onHallOfFame != null
|
||||||
onNewCharacter: onNewCharacter != null
|
? () => onHallOfFame!(context)
|
||||||
? () => _handleNewCharacter(context)
|
: null,
|
||||||
: null,
|
),
|
||||||
onLoadSave: onLoadSave != null
|
],
|
||||||
? () => onLoadSave!(context)
|
|
||||||
: null,
|
|
||||||
onHallOfFame: onHallOfFame != null
|
|
||||||
? () => onHallOfFame!(context)
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// 카피라이트 푸터 (하단 고정)
|
),
|
||||||
const _CopyrightFooter(),
|
// 카피라이트 푸터 (하단 고정)
|
||||||
],
|
const _CopyrightFooter(),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 헤더 (타이틀 + 태그) - 중앙 정렬
|
/// 레트로 스타일 헤더 (타이틀 + 태그)
|
||||||
class _HeroHeader extends StatelessWidget {
|
class _RetroHeader extends StatelessWidget {
|
||||||
const _HeroHeader({required this.theme, required this.colorScheme});
|
const _RetroHeader();
|
||||||
|
|
||||||
final ThemeData theme;
|
|
||||||
final ColorScheme colorScheme;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return DecoratedBox(
|
final l10n = L10n.of(context);
|
||||||
decoration: BoxDecoration(
|
return RetroGoldPanel(
|
||||||
borderRadius: BorderRadius.circular(18),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
|
||||||
gradient: LinearGradient(
|
child: Column(
|
||||||
colors: [
|
children: [
|
||||||
colorScheme.primary.withValues(alpha: 0.9),
|
// 타이틀 (픽셀 폰트)
|
||||||
colorScheme.primaryContainer,
|
Row(
|
||||||
],
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
begin: Alignment.topLeft,
|
children: [
|
||||||
end: Alignment.bottomRight,
|
const Icon(Icons.auto_awesome, color: RetroColors.gold, size: 20),
|
||||||
),
|
const SizedBox(width: 12),
|
||||||
boxShadow: [
|
Text(
|
||||||
BoxShadow(
|
l10n.appTitle,
|
||||||
color: colorScheme.primary.withValues(alpha: 0.18),
|
style: const TextStyle(
|
||||||
blurRadius: 18,
|
fontFamily: 'PressStart2P',
|
||||||
offset: const Offset(0, 10),
|
fontSize: 14,
|
||||||
),
|
color: RetroColors.gold,
|
||||||
],
|
shadows: [
|
||||||
),
|
Shadow(
|
||||||
child: Padding(
|
color: RetroColors.goldDark,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24),
|
offset: Offset(2, 2),
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
// 타이틀 (중앙 정렬)
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Icon(Icons.auto_awesome, color: colorScheme.onPrimary),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Text(
|
|
||||||
L10n.of(context).appTitle,
|
|
||||||
style: theme.textTheme.headlineSmall?.copyWith(
|
|
||||||
color: colorScheme.onPrimary,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 14),
|
|
||||||
// 태그 (중앙 정렬)
|
|
||||||
Builder(
|
|
||||||
builder: (context) {
|
|
||||||
final l10n = L10n.of(context);
|
|
||||||
return Wrap(
|
|
||||||
alignment: WrapAlignment.center,
|
|
||||||
spacing: 8,
|
|
||||||
runSpacing: 8,
|
|
||||||
children: [
|
|
||||||
_Tag(
|
|
||||||
icon: Icons.cloud_off_outlined,
|
|
||||||
label: l10n.tagNoNetwork,
|
|
||||||
),
|
|
||||||
_Tag(icon: Icons.timer_outlined, label: l10n.tagIdleRpg),
|
|
||||||
_Tag(
|
|
||||||
icon: Icons.storage_rounded,
|
|
||||||
label: l10n.tagLocalSaves,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
),
|
||||||
},
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
const SizedBox(height: 16),
|
||||||
|
// 태그 (레트로 스타일)
|
||||||
|
Wrap(
|
||||||
|
alignment: WrapAlignment.center,
|
||||||
|
spacing: 8,
|
||||||
|
runSpacing: 8,
|
||||||
|
children: [
|
||||||
|
_RetroTag(icon: Icons.cloud_off_outlined, label: l10n.tagNoNetwork),
|
||||||
|
_RetroTag(icon: Icons.timer_outlined, label: l10n.tagIdleRpg),
|
||||||
|
_RetroTag(icon: Icons.storage_rounded, label: l10n.tagLocalSaves),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 액션 버튼 (세로 배치)
|
/// 애니메이션 패널
|
||||||
|
class _AnimationPanel extends StatelessWidget {
|
||||||
|
const _AnimationPanel();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return RetroPanel(
|
||||||
|
title: 'BATTLE',
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: const AspectRatio(
|
||||||
|
aspectRatio: 16 / 9,
|
||||||
|
child: HeroVsBossAnimation(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 액션 버튼 (레트로 스타일)
|
||||||
class _ActionButtons extends StatelessWidget {
|
class _ActionButtons extends StatelessWidget {
|
||||||
const _ActionButtons({
|
const _ActionButtons({
|
||||||
this.onNewCharacter,
|
this.onNewCharacter,
|
||||||
@@ -209,48 +189,39 @@ class _ActionButtons extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
|
||||||
final l10n = L10n.of(context);
|
final l10n = L10n.of(context);
|
||||||
|
|
||||||
return Column(
|
return RetroPanel(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
title: 'MENU',
|
||||||
children: [
|
padding: const EdgeInsets.all(12),
|
||||||
// 새 캐릭터 (Primary)
|
child: Column(
|
||||||
FilledButton.icon(
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
onPressed: onNewCharacter,
|
children: [
|
||||||
icon: const Icon(Icons.casino_outlined),
|
// 새 캐릭터 (Primary)
|
||||||
label: Text(l10n.newCharacter),
|
RetroTextButton(
|
||||||
style: FilledButton.styleFrom(
|
text: l10n.newCharacter,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
icon: Icons.casino_outlined,
|
||||||
textStyle: theme.textTheme.titleMedium?.copyWith(
|
onPressed: onNewCharacter,
|
||||||
fontWeight: FontWeight.w600,
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
// 불러오기 (Secondary)
|
||||||
|
RetroTextButton(
|
||||||
|
text: l10n.loadSave,
|
||||||
|
icon: Icons.folder_open,
|
||||||
|
onPressed: onLoadSave,
|
||||||
|
isPrimary: false,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
// 명예의 전당
|
||||||
|
if (onHallOfFame != null)
|
||||||
|
RetroTextButton(
|
||||||
|
text: game_l10n.uiHallOfFame,
|
||||||
|
icon: Icons.emoji_events_outlined,
|
||||||
|
onPressed: onHallOfFame,
|
||||||
|
isPrimary: false,
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
|
||||||
// 불러오기 (Secondary)
|
|
||||||
OutlinedButton.icon(
|
|
||||||
onPressed: onLoadSave,
|
|
||||||
icon: const Icon(Icons.folder_open),
|
|
||||||
label: Text(l10n.loadSave),
|
|
||||||
style: OutlinedButton.styleFrom(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
|
||||||
textStyle: theme.textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 12),
|
|
||||||
// 명예의 전당 (Tertiary)
|
|
||||||
if (onHallOfFame != null)
|
|
||||||
TextButton.icon(
|
|
||||||
onPressed: onHallOfFame,
|
|
||||||
icon: const Icon(Icons.emoji_events_outlined),
|
|
||||||
label: Text(game_l10n.uiHallOfFame),
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
|
|
||||||
textStyle: theme.textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,43 +232,51 @@ class _CopyrightFooter extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
child: Text(
|
child: Text(
|
||||||
game_l10n.copyrightText,
|
game_l10n.copyrightText,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: theme.textTheme.bodySmall?.copyWith(
|
style: const TextStyle(
|
||||||
color: theme.colorScheme.onSurface.withValues(alpha: 0.5),
|
fontFamily: 'PressStart2P',
|
||||||
|
fontSize: 6,
|
||||||
|
color: RetroColors.textDisabled,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 태그 칩
|
/// 레트로 태그 칩
|
||||||
class _Tag extends StatelessWidget {
|
class _RetroTag extends StatelessWidget {
|
||||||
const _Tag({required this.icon, required this.label});
|
const _RetroTag({required this.icon, required this.label});
|
||||||
|
|
||||||
final IconData icon;
|
final IconData icon;
|
||||||
final String label;
|
final String label;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final colorScheme = Theme.of(context).colorScheme;
|
return Container(
|
||||||
// 어두운 배경에 잘 보이도록 대비되는 색상 사용
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
|
||||||
final tagColor = colorScheme.onPrimaryContainer;
|
decoration: BoxDecoration(
|
||||||
return Chip(
|
color: RetroColors.panelBgLight,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
border: Border.all(color: RetroColors.panelBorderInner, width: 1),
|
||||||
backgroundColor: colorScheme.primaryContainer.withValues(alpha: 0.8),
|
),
|
||||||
avatar: Icon(icon, color: tagColor, size: 16),
|
child: Row(
|
||||||
label: Text(
|
mainAxisSize: MainAxisSize.min,
|
||||||
label,
|
children: [
|
||||||
style: TextStyle(color: tagColor, fontWeight: FontWeight.w600),
|
Icon(icon, color: RetroColors.gold, size: 12),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'PressStart2P',
|
||||||
|
fontSize: 7,
|
||||||
|
color: RetroColors.textLight,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
side: BorderSide.none,
|
|
||||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
|
||||||
visualDensity: VisualDensity.compact,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import 'package:askiineverdie/src/features/game/widgets/statistics_dialog.dart';
|
|||||||
import 'package:askiineverdie/src/features/game/widgets/help_dialog.dart';
|
import 'package:askiineverdie/src/features/game/widgets/help_dialog.dart';
|
||||||
import 'package:askiineverdie/src/core/storage/settings_repository.dart';
|
import 'package:askiineverdie/src/core/storage/settings_repository.dart';
|
||||||
import 'package:askiineverdie/src/core/audio/audio_service.dart';
|
import 'package:askiineverdie/src/core/audio/audio_service.dart';
|
||||||
|
import 'package:askiineverdie/src/shared/retro_colors.dart';
|
||||||
|
|
||||||
/// 게임 진행 화면 (Main.dfm 기반 3패널 레이아웃)
|
/// 게임 진행 화면 (Main.dfm 기반 3패널 레이아웃)
|
||||||
///
|
///
|
||||||
@@ -829,7 +830,7 @@ class _GamePlayScreenState extends State<GamePlayScreen>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 기존 데스크톱 레이아웃
|
// 기존 데스크톱 레이아웃 (레트로 스타일)
|
||||||
return NotificationOverlay(
|
return NotificationOverlay(
|
||||||
key: localeKey,
|
key: localeKey,
|
||||||
notificationService: _notificationService,
|
notificationService: _notificationService,
|
||||||
@@ -846,8 +847,17 @@ class _GamePlayScreenState extends State<GamePlayScreen>
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
|
backgroundColor: RetroColors.deepBrown,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(L10n.of(context).progressQuestTitle(state.traits.name)),
|
backgroundColor: RetroColors.darkBrown,
|
||||||
|
title: Text(
|
||||||
|
L10n.of(context).progressQuestTitle(state.traits.name),
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'PressStart2P',
|
||||||
|
fontSize: 12,
|
||||||
|
color: RetroColors.gold,
|
||||||
|
),
|
||||||
|
),
|
||||||
actions: [
|
actions: [
|
||||||
// 치트 버튼 (디버그용)
|
// 치트 버튼 (디버그용)
|
||||||
if (widget.controller.cheatsEnabled) ...[
|
if (widget.controller.cheatsEnabled) ...[
|
||||||
@@ -955,6 +965,11 @@ class _GamePlayScreenState extends State<GamePlayScreen>
|
|||||||
final l10n = L10n.of(context);
|
final l10n = L10n.of(context);
|
||||||
return Card(
|
return Card(
|
||||||
margin: const EdgeInsets.all(4),
|
margin: const EdgeInsets.all(4),
|
||||||
|
color: RetroColors.panelBg,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
side: const BorderSide(color: RetroColors.panelBorderOuter, width: 2),
|
||||||
|
borderRadius: BorderRadius.circular(0),
|
||||||
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
@@ -1023,6 +1038,11 @@ class _GamePlayScreenState extends State<GamePlayScreen>
|
|||||||
final l10n = L10n.of(context);
|
final l10n = L10n.of(context);
|
||||||
return Card(
|
return Card(
|
||||||
margin: const EdgeInsets.all(4),
|
margin: const EdgeInsets.all(4),
|
||||||
|
color: RetroColors.panelBg,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
side: const BorderSide(color: RetroColors.panelBorderOuter, width: 2),
|
||||||
|
borderRadius: BorderRadius.circular(0),
|
||||||
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
@@ -1069,6 +1089,11 @@ class _GamePlayScreenState extends State<GamePlayScreen>
|
|||||||
final l10n = L10n.of(context);
|
final l10n = L10n.of(context);
|
||||||
return Card(
|
return Card(
|
||||||
margin: const EdgeInsets.all(4),
|
margin: const EdgeInsets.all(4),
|
||||||
|
color: RetroColors.panelBg,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
side: const BorderSide(color: RetroColors.panelBorderOuter, width: 2),
|
||||||
|
borderRadius: BorderRadius.circular(0),
|
||||||
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
@@ -1112,13 +1137,20 @@ class _GamePlayScreenState extends State<GamePlayScreen>
|
|||||||
|
|
||||||
Widget _buildPanelHeader(String title) {
|
Widget _buildPanelHeader(String title) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||||
color: Theme.of(context).colorScheme.primaryContainer,
|
decoration: const BoxDecoration(
|
||||||
|
color: RetroColors.darkBrown,
|
||||||
|
border: Border(
|
||||||
|
bottom: BorderSide(color: RetroColors.gold, width: 2),
|
||||||
|
),
|
||||||
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
title,
|
title.toUpperCase(),
|
||||||
style: TextStyle(
|
style: const TextStyle(
|
||||||
|
fontFamily: 'PressStart2P',
|
||||||
|
fontSize: 8,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
color: RetroColors.gold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -1126,8 +1158,15 @@ class _GamePlayScreenState extends State<GamePlayScreen>
|
|||||||
|
|
||||||
Widget _buildSectionHeader(String title) {
|
Widget _buildSectionHeader(String title) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||||
child: Text(title, style: Theme.of(context).textTheme.labelSmall),
|
child: Text(
|
||||||
|
title.toUpperCase(),
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'PressStart2P',
|
||||||
|
fontSize: 6,
|
||||||
|
color: RetroColors.textDisabled,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import 'package:askiineverdie/src/features/game/pages/story_page.dart';
|
|||||||
import 'package:askiineverdie/src/features/game/widgets/carousel_nav_bar.dart';
|
import 'package:askiineverdie/src/features/game/widgets/carousel_nav_bar.dart';
|
||||||
import 'package:askiineverdie/src/features/game/widgets/combat_log.dart';
|
import 'package:askiineverdie/src/features/game/widgets/combat_log.dart';
|
||||||
import 'package:askiineverdie/src/features/game/widgets/enhanced_animation_panel.dart';
|
import 'package:askiineverdie/src/features/game/widgets/enhanced_animation_panel.dart';
|
||||||
|
import 'package:askiineverdie/src/shared/retro_colors.dart';
|
||||||
|
|
||||||
/// 모바일 캐로셀 레이아웃
|
/// 모바일 캐로셀 레이아웃
|
||||||
///
|
///
|
||||||
@@ -358,6 +359,7 @@ class _MobileCarouselLayoutState extends State<MobileCarouselLayout> {
|
|||||||
showModalBottomSheet<void>(
|
showModalBottomSheet<void>(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
|
backgroundColor: RetroColors.panelBg,
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
maxHeight: MediaQuery.of(context).size.height * 0.7,
|
maxHeight: MediaQuery.of(context).size.height * 0.7,
|
||||||
),
|
),
|
||||||
@@ -366,19 +368,22 @@ class _MobileCarouselLayoutState extends State<MobileCarouselLayout> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
// 헤더
|
// 헤더 (레트로 스타일)
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
decoration: BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.primaryContainer,
|
color: RetroColors.darkBrown,
|
||||||
|
border: Border(
|
||||||
|
bottom: BorderSide(color: RetroColors.gold, width: 2),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: const Text(
|
||||||
l10n.menuOptions,
|
'OPTIONS',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontFamily: 'PressStart2P',
|
||||||
fontSize: 16,
|
fontSize: 12,
|
||||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
color: RetroColors.gold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -555,12 +560,21 @@ class _MobileCarouselLayoutState extends State<MobileCarouselLayout> {
|
|||||||
final state = widget.state;
|
final state = widget.state;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
backgroundColor: RetroColors.deepBrown,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(L10n.of(context).progressQuestTitle(state.traits.name)),
|
backgroundColor: RetroColors.darkBrown,
|
||||||
|
title: Text(
|
||||||
|
L10n.of(context).progressQuestTitle(state.traits.name),
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'PressStart2P',
|
||||||
|
fontSize: 10,
|
||||||
|
color: RetroColors.gold,
|
||||||
|
),
|
||||||
|
),
|
||||||
actions: [
|
actions: [
|
||||||
// 옵션 버튼
|
// 옵션 버튼
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.settings),
|
icon: const Icon(Icons.settings, color: RetroColors.gold),
|
||||||
onPressed: () => _showOptionsMenu(context),
|
onPressed: () => _showOptionsMenu(context),
|
||||||
tooltip: l10n.menuOptions,
|
tooltip: l10n.menuOptions,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:askiineverdie/data/game_text_l10n.dart' as l10n;
|
import 'package:askiineverdie/data/game_text_l10n.dart' as l10n;
|
||||||
|
import 'package:askiineverdie/src/shared/retro_colors.dart';
|
||||||
|
|
||||||
/// 캐로셀 페이지 인덱스
|
/// 캐로셀 페이지 인덱스
|
||||||
enum CarouselPage {
|
enum CarouselPage {
|
||||||
@@ -13,7 +14,7 @@ enum CarouselPage {
|
|||||||
story, // 6: 스토리
|
story, // 6: 스토리
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 캐로셀 네비게이션 바
|
/// 캐로셀 네비게이션 바 (레트로 스타일)
|
||||||
///
|
///
|
||||||
/// 7개의 페이지 버튼을 표시하고 현재 페이지를 하이라이트.
|
/// 7개의 페이지 버튼을 표시하고 현재 페이지를 하이라이트.
|
||||||
/// 버튼 탭 시 해당 페이지로 이동.
|
/// 버튼 탭 시 해당 페이지로 이동.
|
||||||
@@ -31,10 +32,12 @@ class CarouselNavBar extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
height: 56,
|
height: 56,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4),
|
padding: const EdgeInsets.symmetric(horizontal: 2, vertical: 4),
|
||||||
decoration: BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
color: RetroColors.darkBrown,
|
||||||
border: Border(top: BorderSide(color: Theme.of(context).dividerColor)),
|
border: Border(
|
||||||
|
top: BorderSide(color: RetroColors.gold, width: 2),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: CarouselPage.values.map((page) {
|
children: CarouselPage.values.map((page) {
|
||||||
@@ -52,7 +55,7 @@ class CarouselNavBar extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 개별 네비게이션 버튼
|
/// 개별 네비게이션 버튼 (레트로 스타일)
|
||||||
class _NavButton extends StatelessWidget {
|
class _NavButton extends StatelessWidget {
|
||||||
const _NavButton({
|
const _NavButton({
|
||||||
required this.page,
|
required this.page,
|
||||||
@@ -67,33 +70,32 @@ class _NavButton extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final (icon, label) = _getIconAndLabel(page);
|
final (icon, label) = _getIconAndLabel(page);
|
||||||
final theme = Theme.of(context);
|
final color = isSelected ? RetroColors.gold : RetroColors.textDisabled;
|
||||||
final color = isSelected
|
final bgColor = isSelected
|
||||||
? theme.colorScheme.primary
|
? RetroColors.panelBgLight
|
||||||
: theme.colorScheme.onSurfaceVariant;
|
: Colors.transparent;
|
||||||
|
|
||||||
return InkWell(
|
return GestureDetector(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
child: Container(
|
child: Container(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 1),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||||
decoration: isSelected
|
decoration: BoxDecoration(
|
||||||
? BoxDecoration(
|
color: bgColor,
|
||||||
color: theme.colorScheme.primaryContainer.withValues(
|
border: isSelected
|
||||||
alpha: 0.5,
|
? Border.all(color: RetroColors.gold, width: 1)
|
||||||
),
|
: null,
|
||||||
borderRadius: BorderRadius.circular(8),
|
),
|
||||||
)
|
|
||||||
: null,
|
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Icon(icon, size: 20, color: color),
|
Icon(icon, size: 18, color: color),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
Text(
|
Text(
|
||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 9,
|
fontFamily: 'PressStart2P',
|
||||||
|
fontSize: 5,
|
||||||
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
|
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
|
||||||
color: color,
|
color: color,
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user