shitman/lib/ui/in_game_ui.dart
zeyus f7a08a5099
All checks were successful
/ build-web (push) Successful in 3m24s
Added touch controls.
2025-08-04 11:50:47 +02:00

530 lines
17 KiB
Dart

import 'package:flutter/material.dart';
import 'package:nes_ui/nes_ui.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:shitman/game/shitman_game.dart';
import 'package:shitman/settings/app_settings.dart';
class InGameUI extends StatelessWidget with AppSettings {
static const String overlayID = 'InGameUI';
final ShitmanGame game;
InGameUI(this.game, {super.key});
@override
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
child: Stack(
children: [
// Top HUD
Positioned(
top: 20,
left: 20,
right: 20,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Stealth indicator
NesContainer(
backgroundColor: Colors.black87,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Icon(Icons.visibility_off, size: 16),
SizedBox(width: 8),
Text(
'gameplay.hidden'.tr(),
style: TextStyle(color: Colors.green),
),
],
),
),
),
// Mission objective
NesContainer(
backgroundColor: Colors.black87,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'gameplay.find_target'.tr(),
style: TextStyle(color: Colors.white),
),
),
),
// Pause button
IconButton(
icon: Icon(Icons.pause, color: Colors.white),
onPressed: () => game.overlays.add(PauseMenuUI.overlayID),
),
],
),
),
// Bottom controls hint
Positioned(
bottom: 20,
left: 20,
right: 20,
child: NesContainer(
backgroundColor: Colors.black54,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'controls.move'.tr(),
style: TextStyle(color: Colors.white),
),
Text(
'controls.place_bag'.tr(),
style: TextStyle(color: Colors.white),
),
Text(
'controls.ring_bell'.tr(),
style: TextStyle(color: Colors.white),
),
],
),
),
),
),
],
),
);
}
}
class MainMenuUI extends StatelessWidget with AppSettings {
static const String overlayID = 'MainMenu';
final ShitmanGame game;
MainMenuUI(this.game, {super.key});
@override
Widget build(BuildContext context) {
return Material(
color: Colors.black,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Game title
Text(
'game.title'.tr(),
style: Theme.of(context).textTheme.headlineLarge?.copyWith(
color: Colors.orange,
fontSize: 48,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
Text(
'game.subtitle'.tr(),
style: TextStyle(color: Colors.white70, fontSize: 16),
),
SizedBox(height: 40),
// Menu buttons
Column(
children: [
NesButton(
type: NesButtonType.primary,
onPressed: () async {
game.overlays.remove(MainMenuUI.overlayID);
game.overlays.add(InGameUI.overlayID);
await game.startGame();
},
child: Text('menu.start_mission'.tr()),
),
SizedBox(height: 16),
NesButton(
type: NesButtonType.normal,
onPressed: () {
game.overlays.remove(MainMenuUI.overlayID);
game.overlays.add(SettingsUI.overlayID);
},
child: Text('menu.settings'.tr()),
),
SizedBox(height: 16),
NesButton(
type: NesButtonType.normal,
onPressed: () async => await game.startInfiniteMode(),
child: Text('menu.infinite_mode'.tr()),
),
],
),
SizedBox(height: 40),
Text(
'game.description'.tr(),
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white54, fontSize: 12),
),
],
),
),
);
}
}
class SettingsUI extends StatefulWidget with AppSettings {
static const String overlayID = 'Settings';
final ShitmanGame game;
SettingsUI(this.game, {super.key});
@override
State<SettingsUI> createState() => _SettingsUIState();
}
class _SettingsUIState extends State<SettingsUI> with AppSettings {
bool showVisionCones = false;
bool showDetectionRadius = false;
bool debugMode = false;
bool touchControlsEnabled = false;
@override
void initState() {
super.initState();
_loadSettings();
}
void _loadSettings() {
try {
showVisionCones = widget.game.appSettings.getBool(
'game.show_vision_cones',
);
showDetectionRadius = widget.game.appSettings.getBool(
'game.show_detection_radius',
);
debugMode = widget.game.appSettings.getBool('game.debug_mode');
touchControlsEnabled = widget.game.appSettings.getBool(
'ui.touch_enabled',
);
} catch (e) {
// Settings not ready, use defaults
showVisionCones = false;
showDetectionRadius = false;
debugMode = false;
touchControlsEnabled = false;
}
}
@override
Widget build(BuildContext context) {
return Material(
color: Colors.black87,
child: Center(
child: NesContainer(
backgroundColor: Colors.black,
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'menu.settings'.tr(),
style: Theme.of(
context,
).textTheme.headlineMedium?.copyWith(color: Colors.white),
),
IconButton(
icon: Icon(Icons.close, color: Colors.white),
onPressed: () {
widget.game.overlays.remove(SettingsUI.overlayID);
widget.game.overlays.add(MainMenuUI.overlayID);
},
),
],
),
SizedBox(height: 24),
// Language selector
Row(
children: [
Text(
'settings.language_title'.tr(),
style: TextStyle(color: Colors.white),
),
SizedBox(width: 8),
Icon(Icons.language, color: Colors.white),
],
),
SizedBox(height: 8),
NesDropdownMenu<String>(
initialValue: context.locale.languageCode,
entries: [
NesDropdownMenuEntry(
value: 'en',
label: 'settings.language.english'.tr(),
),
NesDropdownMenuEntry(
value: 'da',
label: 'settings.language.danish'.tr(),
),
NesDropdownMenuEntry(
value: 'de',
label: 'settings.language.german'.tr(),
),
],
onChanged: (String? value) async {
if (value != null) {
context.setLocale(Locale(value));
// Save language preference
await widget.game.appSettings.setString('ui.language', value);
setState(() {}); // Simple setState to rebuild UI
}
},
),
SizedBox(height: 16),
// Gameplay Settings Section
Text(
'settings.gameplay'.tr(),
style: TextStyle(
color: Colors.orange,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 12),
// Vision Cones toggle
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'settings.show_vision_cones'.tr(),
style: TextStyle(color: Colors.white),
),
Text(
'settings.vision_cones_help'.tr(),
style: TextStyle(
color: Colors.white60,
fontSize: 11,
),
),
],
),
),
NesCheckBox(
value: showVisionCones,
onChange: (value) async {
setState(() {
showVisionCones = value;
});
await widget.game.appSettings.setBool(
'game.show_vision_cones',
value,
);
},
),
],
),
SizedBox(height: 8),
// Detection Radius toggle
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'settings.show_detection_radius'.tr(),
style: TextStyle(color: Colors.white),
),
Text(
'settings.detection_help'.tr(),
style: TextStyle(
color: Colors.white60,
fontSize: 11,
),
),
],
),
),
NesCheckBox(
value: showDetectionRadius,
onChange: (value) async {
setState(() {
showDetectionRadius = value;
});
await widget.game.appSettings.setBool(
'game.show_detection_radius',
value,
);
},
),
],
),
SizedBox(height: 20),
// Accessibility Section
Text(
'settings.accessibility'.tr(),
style: TextStyle(
color: Colors.orange,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 12),
// Debug mode toggle
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'ui.debug_mode'.tr(),
style: TextStyle(color: Colors.white),
),
NesCheckBox(
value: debugMode,
onChange: (value) async {
setState(() {
debugMode = value;
});
await widget.game.appSettings.setBool(
'game.debug_mode',
value,
);
widget.game.debugMode = value;
},
),
],
),
SizedBox(height: 8),
// Touch controls toggle
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'settings.touch_controls'.tr(),
style: TextStyle(color: Colors.white),
),
Text(
'settings.touch_controls_help'.tr(),
style: TextStyle(
color: Colors.white60,
fontSize: 11,
),
),
],
),
),
NesCheckBox(
value: touchControlsEnabled,
onChange: (value) async {
setState(() {
touchControlsEnabled = value;
});
await widget.game.appSettings.setBool(
'ui.touch_enabled',
value,
);
widget.game.toggleTouchControls(value);
},
),
],
),
SizedBox(height: 40),
Center(
child: NesButton(
type: NesButtonType.primary,
onPressed: () {
widget.game.overlays.remove(SettingsUI.overlayID);
widget.game.overlays.add(MainMenuUI.overlayID);
},
child: Text('menu.back_to_menu'.tr()),
),
),
],
),
),
),
),
);
}
}
class PauseMenuUI extends StatelessWidget {
static const String overlayID = 'PauseMenu';
final ShitmanGame game;
const PauseMenuUI(this.game, {super.key});
@override
Widget build(BuildContext context) {
return Material(
color: Colors.black54,
child: Center(
child: NesContainer(
backgroundColor: Colors.black,
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'ui.paused'.tr(),
style: Theme.of(
context,
).textTheme.headlineMedium?.copyWith(color: Colors.white),
),
SizedBox(height: 24),
NesButton(
type: NesButtonType.primary,
onPressed: () => game.overlays.remove(PauseMenuUI.overlayID),
child: Text('menu.resume'.tr()),
),
SizedBox(height: 12),
NesButton(
type: NesButtonType.normal,
onPressed: () {
game.overlays.remove(PauseMenuUI.overlayID);
game.overlays.remove(InGameUI.overlayID);
game.overlays.add(SettingsUI.overlayID);
},
child: Text('menu.settings'.tr()),
),
SizedBox(height: 12),
NesButton(
type: NesButtonType.warning,
onPressed: () {
game.overlays.remove(PauseMenuUI.overlayID);
game.overlays.remove(InGameUI.overlayID);
game.overlays.add(MainMenuUI.overlayID);
game.stopGame();
},
child: Text('menu.main_menu'.tr()),
),
],
),
),
),
),
);
}
}