import 'package:flutter/material.dart'; class FrontScreen extends StatelessWidget { const FrontScreen({super.key, this.onNewCharacter, this.onLoadSave}); /// "New character" 버튼 클릭 시 호출 final void Function(BuildContext context)? onNewCharacter; /// "Load save" 버튼 클릭 시 호출 final Future Function(BuildContext context)? onLoadSave; @override Widget build(BuildContext context) { final theme = Theme.of(context); final colorScheme = theme.colorScheme; return Scaffold( body: Container( decoration: BoxDecoration( gradient: LinearGradient( colors: [colorScheme.surfaceContainerHighest, colorScheme.surface], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: SafeArea( child: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 960), child: SingleChildScrollView( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _HeroHeader(theme: theme, colorScheme: colorScheme), const SizedBox(height: 24), _ActionRow( onNewCharacter: onNewCharacter != null ? () => onNewCharacter!(context) : () => _showPlaceholder(context), onLoadSave: onLoadSave != null ? () => onLoadSave!(context) : () => _showPlaceholder(context), ), const SizedBox(height: 24), const _StatusCards(), ], ), ), ), ), ), ), ); } } void _showPlaceholder(BuildContext context) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Core gameplay loop is coming next. See doc/progress-quest-flutter-plan.md for milestones.', ), ), ); } class _HeroHeader extends StatelessWidget { const _HeroHeader({required this.theme, required this.colorScheme}); final ThemeData theme; final ColorScheme colorScheme; @override Widget build(BuildContext context) { return DecoratedBox( decoration: BoxDecoration( borderRadius: BorderRadius.circular(18), gradient: LinearGradient( colors: [ colorScheme.primary.withValues(alpha: 0.9), colorScheme.primaryContainer, ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), boxShadow: [ BoxShadow( color: colorScheme.primary.withValues(alpha: 0.18), blurRadius: 18, offset: const Offset(0, 10), ), ], ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(Icons.auto_awesome, color: colorScheme.onPrimary), const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Ascii Never Die', style: theme.textTheme.headlineSmall?.copyWith( color: colorScheme.onPrimary, fontWeight: FontWeight.w700, ), ), const SizedBox(height: 6), Text( 'Offline Progress Quest (PQ 6.4) rebuilt with Flutter.', style: theme.textTheme.titleMedium?.copyWith( color: colorScheme.onPrimary.withValues(alpha: 0.9), ), ), ], ), ), ], ), const SizedBox(height: 14), Wrap( spacing: 8, runSpacing: 8, children: const [ _Tag(icon: Icons.cloud_off_outlined, label: 'No network'), _Tag(icon: Icons.timer_outlined, label: 'Idle RPG loop'), _Tag(icon: Icons.storage_rounded, label: 'Local saves'), ], ), ], ), ), ); } } class _ActionRow extends StatelessWidget { const _ActionRow({required this.onNewCharacter, required this.onLoadSave}); final VoidCallback onNewCharacter; final VoidCallback onLoadSave; @override Widget build(BuildContext context) { final theme = Theme.of(context); return Wrap( spacing: 12, runSpacing: 12, children: [ FilledButton.icon( onPressed: onNewCharacter, icon: const Icon(Icons.casino_outlined), label: const Text('New character'), style: FilledButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 14), textStyle: theme.textTheme.titleMedium, ), ), OutlinedButton.icon( onPressed: onLoadSave, icon: const Icon(Icons.folder_open), label: const Text('Load save'), style: OutlinedButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 14), textStyle: theme.textTheme.titleMedium, ), ), TextButton.icon( onPressed: () => _showPlaceholder(context), icon: const Icon(Icons.menu_book_outlined), label: const Text('View build plan'), ), ], ); } } class _StatusCards extends StatelessWidget { const _StatusCards(); @override Widget build(BuildContext context) { return Column( children: const [ _InfoCard( icon: Icons.route_outlined, title: 'Build roadmap', points: [ 'Port PQ 6.4 data set (Config.dfm) into Dart constants.', 'Recreate quest/task loop with deterministic RNG + saves.', 'Deliver offline-first storage (GZip JSON) across platforms.', ], ), SizedBox(height: 16), _InfoCard( icon: Icons.auto_fix_high_outlined, title: 'Tech stack', points: [ 'Flutter (Material 3) with multiplatform targets enabled.', 'path_provider + shared_preferences for local storage hooks.', 'Strict lints with package imports enforced from day one.', ], ), SizedBox(height: 16), _InfoCard( icon: Icons.checklist_rtl, title: 'Today’s focus', points: [ 'Set up scaffold + lints.', 'Wire seed theme and initial navigation shell.', 'Keep reference assets under example/pq for parity.', ], ), ], ); } } class _InfoCard extends StatelessWidget { const _InfoCard({required this.title, required this.points, this.icon}); final String title; final List points; final IconData? icon; @override Widget build(BuildContext context) { final theme = Theme.of(context); final colorScheme = theme.colorScheme; return Card( elevation: 3, shadowColor: colorScheme.shadow.withValues(alpha: 0.2), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: Padding( padding: const EdgeInsets.all(18), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ if (icon != null) ...[ Icon(icon, color: colorScheme.primary), const SizedBox(width: 10), ], Text( title, style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w700, ), ), ], ), const SizedBox(height: 10), ...points.map( (point) => Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Padding( padding: EdgeInsets.only(top: 3), child: Icon(Icons.check_circle_outline, size: 18), ), const SizedBox(width: 10), Expanded( child: Text(point, style: theme.textTheme.bodyMedium), ), ], ), ), ), ], ), ), ); } } class _Tag extends StatelessWidget { const _Tag({required this.icon, required this.label}); final IconData icon; final String label; @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return Chip( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), backgroundColor: colorScheme.onPrimary.withValues(alpha: 0.14), avatar: Icon(icon, color: colorScheme.onPrimary, size: 16), label: Text( label, style: TextStyle( color: colorScheme.onPrimary, fontWeight: FontWeight.w600, ), ), side: BorderSide.none, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, visualDensity: VisualDensity.compact, ); } }