This commit is contained in:
2025-12-07 13:44:51 +09:00
parent 30c84a48ac
commit d3fca333cb
29 changed files with 1437 additions and 137 deletions
+50 -16
View File
@@ -538,8 +538,29 @@ class _BattleScreenState extends State<BattleScreen> {
color: Colors.black54,
child: Center(
child: SimpleDialog(
title: const Text("Victory! Choose a Reward"),
title: Row(
children: [
const Text("Victory! Choose a Reward"),
const Spacer(),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.monetization_on, color: Colors.amber, size: 18),
const SizedBox(width: 4),
Text(
"${battleProvider.lastGoldReward} G",
style: TextStyle(
color: Colors.amber,
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
],
),
],
),
children: battleProvider.rewardOptions.map((item) {
bool isSkip = item.id == "reward_skip";
return SimpleDialogOption(
onPressed: () {
battleProvider.selectReward(item);
@@ -549,30 +570,43 @@ class _BattleScreenState extends State<BattleScreen> {
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.blueGrey[700],
borderRadius: BorderRadius.circular(4),
border: Border.all(color: Colors.grey),
if (!isSkip)
Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.blueGrey[700],
borderRadius: BorderRadius.circular(
4),
border: Border.all(
color: item.rarity !=
ItemRarity.magic
? ItemUtils.getRarityColor(
item.rarity,
)
: Colors.grey,
),
),
child: Icon(
ItemUtils.getIcon(item.slot),
color: ItemUtils.getColor(item.slot),
size: 24,
),
),
child: Icon(
ItemUtils.getIcon(item.slot),
color: ItemUtils.getColor(item.slot),
size: 24,
),
),
const SizedBox(width: 12),
if (!isSkip) const SizedBox(width: 12),
Text(
item.name,
style: const TextStyle(
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
color: isSkip
? Colors.grey
: ItemUtils.getRarityColor(
item.rarity),
),
),
],
),
_buildItemStatText(item),
if (!isSkip) _buildItemStatText(item),
Text(
item.description,
style: const TextStyle(
+29 -2
View File
@@ -93,6 +93,17 @@ class InventoryScreen extends StatelessWidget {
color: item != null
? Colors.blueGrey[600]
: Colors.grey[800],
shape: item != null &&
item.rarity != ItemRarity.magic
? RoundedRectangleBorder(
side: BorderSide(
color:
ItemUtils.getRarityColor(item.rarity),
width: 2.0,
),
borderRadius: BorderRadius.circular(4.0),
)
: null,
child: Stack(
children: [
// Slot Name (Top Right)
@@ -143,7 +154,9 @@ class InventoryScreen extends StatelessWidget {
fontSize: 11,
fontWeight: FontWeight.bold,
color: item != null
? Colors.white
? ItemUtils.getRarityColor(
item.rarity,
)
: Colors.grey,
),
maxLines: 2,
@@ -206,6 +219,17 @@ class InventoryScreen extends StatelessWidget {
},
child: Card(
color: Colors.blueGrey[700],
shape: item.rarity != ItemRarity.magic
? RoundedRectangleBorder(
side: BorderSide(
color: ItemUtils.getRarityColor(
item.rarity,
),
width: 2.0,
),
borderRadius: BorderRadius.circular(4.0),
)
: null,
child: Stack(
children: [
// Faded Icon in Top-Left
@@ -233,9 +257,12 @@ class InventoryScreen extends StatelessWidget {
child: Text(
item.name,
textAlign: TextAlign.center,
style: const TextStyle(
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
color: ItemUtils.getRarityColor(
item.rarity,
),
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
+115 -48
View File
@@ -1,10 +1,54 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'character_selection_screen.dart';
import 'main_wrapper.dart';
import '../widgets/responsive_container.dart';
import '../game/save_manager.dart';
import '../providers/battle_provider.dart';
class MainMenuScreen extends StatelessWidget {
class MainMenuScreen extends StatefulWidget {
const MainMenuScreen({super.key});
@override
State<MainMenuScreen> createState() => _MainMenuScreenState();
}
class _MainMenuScreenState extends State<MainMenuScreen> {
bool _hasSave = false;
bool _isLoading = true;
@override
void initState() {
super.initState();
_checkSaveData();
}
Future<void> _checkSaveData() async {
final hasSave = await SaveManager.hasSaveData();
if (mounted) {
setState(() {
_hasSave = hasSave;
_isLoading = false;
});
}
}
Future<void> _continueGame() async {
final data = await SaveManager.loadGame();
if (data != null && mounted) {
context.read<BattleProvider>().loadFromSave(data);
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => const MainWrapper()),
);
} else {
// Handle load error
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Failed to load save data.')),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -18,55 +62,78 @@ class MainMenuScreen extends StatelessWidget {
),
),
child: ResponsiveContainer(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.gavel, size: 100, color: Colors.amber),
const SizedBox(height: 20),
const Text(
"COLOSSEUM'S CHOICE",
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
letterSpacing: 2.0,
color: Colors.white,
),
),
const SizedBox(height: 10),
const Text(
"Rise as a Legend",
style: TextStyle(
fontSize: 16,
color: Colors.grey,
fontStyle: FontStyle.italic,
),
),
const SizedBox(height: 60),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const CharacterSelectionScreen(),
child: _isLoading
? const Center(child: CircularProgressIndicator())
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.gavel, size: 100, color: Colors.amber),
const SizedBox(height: 20),
const Text(
"COLOSSEUM'S CHOICE",
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
letterSpacing: 2.0,
color: Colors.white,
),
),
);
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 50,
vertical: 15,
),
backgroundColor: Colors.amber[700],
foregroundColor: Colors.black,
textStyle: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
const SizedBox(height: 10),
const Text(
"Rise as a Legend",
style: TextStyle(
fontSize: 16,
color: Colors.grey,
fontStyle: FontStyle.italic,
),
),
const SizedBox(height: 60),
if (_hasSave) ...[
ElevatedButton(
onPressed: _continueGame,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 50,
vertical: 15,
),
backgroundColor: Colors.blueAccent,
foregroundColor: Colors.white,
textStyle: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
child: const Text("CONTINUE"),
),
const SizedBox(height: 20),
],
ElevatedButton(
onPressed: () {
// Warn if save exists? Or just overwrite on save.
// For now, simpler flow.
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const CharacterSelectionScreen(),
),
);
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 50,
vertical: 15,
),
backgroundColor: Colors.amber[700],
foregroundColor: Colors.black,
textStyle: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
child: const Text("NEW GAME"),
),
],
),
child: const Text("START GAME"),
),
],
),
),
),
);
+10 -1
View File
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'battle_screen.dart';
import 'inventory_screen.dart';
import 'settings_screen.dart';
import '../widgets/responsive_container.dart';
class MainWrapper extends StatefulWidget {
@@ -13,7 +14,11 @@ class MainWrapper extends StatefulWidget {
class _MainWrapperState extends State<MainWrapper> {
int _currentIndex = 0;
final List<Widget> _screens = [const BattleScreen(), const InventoryScreen()];
final List<Widget> _screens = [
const BattleScreen(),
const InventoryScreen(),
const SettingsScreen(),
];
@override
Widget build(BuildContext context) {
@@ -39,6 +44,10 @@ class _MainWrapperState extends State<MainWrapper> {
icon: Icon(Icons.backpack),
label: 'Inventory',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Settings',
),
],
),
),
+111
View File
@@ -0,0 +1,111 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/battle_provider.dart';
import 'main_menu_screen.dart';
class SettingsScreen extends StatelessWidget {
const SettingsScreen({super.key});
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Settings',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
const SizedBox(height: 40),
// Placeholder for future settings
const Text(
'Effect Intensity: Normal',
style: TextStyle(color: Colors.white70),
),
const SizedBox(height: 20),
const Text(
'Volume: 100%',
style: TextStyle(color: Colors.white70),
),
const SizedBox(height: 40),
// Restart Button
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange,
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 12),
),
onPressed: () {
_showConfirmationDialog(
context,
title: 'Restart Game?',
content: 'All progress will be lost. Are you sure?',
onConfirm: () {
context.read<BattleProvider>().initializeBattle();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Game Restarted!')),
);
// Optionally switch tab back to Battle (index 0)
// But MainWrapper controls the index.
// We can't easily switch tab from here without a callback or Provider.
// For now, just restart logic is enough.
},
);
},
child: const Text('Restart Game'),
),
const SizedBox(height: 20),
// Return to Main Menu Button
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 12),
),
onPressed: () {
_showConfirmationDialog(
context,
title: 'Return to Main Menu?',
content: 'Unsaved progress may be lost. (Progress is saved automatically after each stage)',
onConfirm: () {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => const MainMenuScreen()),
(route) => false,
);
},
);
},
child: const Text('Return to Main Menu'),
),
],
),
);
}
void _showConfirmationDialog(BuildContext context, {required String title, required String content, required VoidCallback onConfirm}) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(title),
content: Text(content),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Cancel'),
),
TextButton(
onPressed: () {
Navigator.pop(context);
onConfirm();
},
child: const Text('Confirm', style: TextStyle(color: Colors.red)),
),
],
),
);
}
}