This commit is contained in:
2025-10-16 17:42:46 +02:00
parent dc86955721
commit 2e3a69a23e
12 changed files with 1421 additions and 604 deletions
+118 -40
View File
@@ -8,6 +8,7 @@ import 'yolo_detector.dart';
import 'dart:convert'; // For JSON encoding
import 'dart:math';
import 'package:shared_preferences/shared_preferences.dart';
import '../utils/translations.dart';
class PreviewScreen extends StatefulWidget {
final String imagePath;
@@ -56,6 +57,7 @@ class _PreviewScreenState extends State<PreviewScreen> {
Color get _activeColor => _isEditMode ? _editColor : _bulletColor;
Color get _activeColorWithOpacity => _activeColor.withOpacity(_bulletOpacity);
String _selectedLanguage = 'English';
@override
void initState() {
@@ -63,9 +65,21 @@ class _PreviewScreenState extends State<PreviewScreen> {
_realImageDetections = widget.detections;
_targetImageFuture = _loadAndDecodeTargetImage();
_loadBulletColor(); // 👈 Add this
_loadLanguage();
_runDetectionAndMapping();
}
String _t(String key) {
return AppTranslations.translate(key, _selectedLanguage);
}
Future<void> _loadLanguage() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_selectedLanguage = prefs.getString('language') ?? 'English';
});
}
Future<void> _loadBulletColor() async {
final prefs = await SharedPreferences.getInstance();
final selectedColor = prefs.getString('bulletColor') ?? 'Blue';
@@ -241,9 +255,9 @@ void _manualScoreEntry() {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'Enter Missing Bullet Scores',
style: TextStyle(
Text(
_t('Enter Missing Bullet Scores'),
style: const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
@@ -263,7 +277,7 @@ void _manualScoreEntry() {
keyboardType: TextInputType.number,
style: const TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: 'Bullet Score ${_mappedBullets.length + index + 1}',
labelText: '${_t('Bullet Score')} ${_mappedBullets.length + index + 1}',
labelStyle: const TextStyle(color: Colors.white54),
filled: true,
fillColor: Colors.grey[800],
@@ -308,7 +322,7 @@ void _manualScoreEntry() {
borderRadius: BorderRadius.circular(12),
),
),
child: const Text('Add Bullets'),
child: Text(_t('Add Bullets')),
),
),
],
@@ -355,9 +369,10 @@ void _manualScoreEntry() {
// Use timestamp for a unique file name
final now = DateTime.now();
final dateString = "${now.year}-${now.month}-${now.day}";
final dateString = "${now.day.toString().padLeft(2, '0')}/${now.month.toString().padLeft(2, '0')}/${now.year}";
final dateStringFile = "${now.year}-${now.month}-${now.day}";
final timeString = "${now.hour}-${now.minute}-${now.second}";
final fileName = "target_${dateString}_$timeString.json";
final fileName = "target_${dateStringFile}_$timeString.json";
final filePath = '${saveDirectory.path}/$fileName';
// Prepare target data to save
@@ -500,20 +515,25 @@ void _moveBullet(Offset offsetDelta) {
int trainingCount = 1;
int tournamentCount = 1;
// Get localized folder names
final trainingWord = _t('Training');
final tournamentWord = _t('Tournament');
for (var folder in folders) {
final name = folder.path.split('/').last;
if (name.startsWith('Training')) {
final num = int.tryParse(name.replaceAll('Training ', ''));
// Check for both English and Slovenian names
if (name.startsWith('Training') || name.startsWith('Trening')) {
final num = int.tryParse(name.replaceAll('Training ', '').replaceAll('Trening ', ''));
if (num != null && num >= trainingCount) trainingCount = num + 1;
}
if (name.startsWith('Tournament')) {
final num = int.tryParse(name.replaceAll('Tournament ', ''));
if (name.startsWith('Tournament') || name.startsWith('Tekmovanje')) {
final num = int.tryParse(name.replaceAll('Tournament ', '').replaceAll('Tekmovanje ', ''));
if (num != null && num >= tournamentCount) tournamentCount = num + 1;
}
}
final String nextTraining = 'Training $trainingCount';
final String nextTournament = 'Tournament $tournamentCount';
final String nextTraining = '$trainingWord $trainingCount';
final String nextTournament = '$tournamentWord $tournamentCount';
return showDialog<String>(
context: context,
@@ -526,9 +546,9 @@ void _moveBullet(Offset offsetDelta) {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'Save Target Data',
style: TextStyle(
Text(
_t('Save Target Data'),
style: const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
@@ -536,7 +556,7 @@ void _moveBullet(Offset offsetDelta) {
),
const SizedBox(height: 24),
// 🎯 Training Button
// 🎯 Training Button (New folder)
SizedBox(
width: double.infinity,
child: ElevatedButton(
@@ -554,12 +574,24 @@ void _moveBullet(Offset offsetDelta) {
borderRadius: BorderRadius.circular(12),
),
),
child: Text('🎯 Save to "$nextTraining"'),
child: Column(
children: [
Text(
'🎯 $nextTraining',
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
const SizedBox(height: 4),
Text(
_t('New folder'),
style: const TextStyle(fontSize: 12, color: Colors.white70),
),
],
),
),
),
const SizedBox(height: 12),
// 🏆 Tournament Button
// 🏆 Tournament Button (New folder)
SizedBox(
width: double.infinity,
child: ElevatedButton(
@@ -577,7 +609,19 @@ void _moveBullet(Offset offsetDelta) {
borderRadius: BorderRadius.circular(12),
),
),
child: Text('🏆 Save to "$nextTournament"'),
child: Column(
children: [
Text(
'🏆 $nextTournament',
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
const SizedBox(height: 4),
Text(
_t('New folder'),
style: const TextStyle(fontSize: 12, color: Colors.white70),
),
],
),
),
),
if (lastFolder != null) ...[
@@ -613,13 +657,13 @@ void _moveBullet(Offset offsetDelta) {
child: Column(
children: [
Text(
'${lastIsTournament ? "🏆" : "🎯"} Save to "$lastFolder"',
style: const TextStyle(fontWeight: FontWeight.bold),
'${lastIsTournament ? "🏆" : "🎯"} $lastFolder',
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
const SizedBox(height: 4),
const Text(
'Last used folder',
style: TextStyle(fontSize: 12, color: Colors.white70),
Text(
_t('Last used folder'),
style: const TextStyle(fontSize: 12, color: Colors.white70),
),
],
),
@@ -715,9 +759,9 @@ Widget build(BuildContext context) {
appBar: AppBar(
backgroundColor: Colors.grey[900],
iconTheme: const IconThemeData(color: Colors.white),
title: const Text(
'Detection Preview',
style: TextStyle(color: Colors.white),
title: Text(
_t('Detection Preview'),
style: const TextStyle(color: Colors.white),
),
actions: [
IconButton(
@@ -735,14 +779,14 @@ Widget build(BuildContext context) {
});
},
tooltip: _mode == PreviewMode.mappedTarget
? "Show Camera Detections"
: "Show Mapped Target",
? _t("Show Camera Detections")
: _t("Show Mapped Target"),
),
IconButton(
icon: const Icon(Icons.save),
color: Colors.white,
onPressed: _saveTargetData,
tooltip: "Save Target Data",
tooltip: _t("Save Target Data"),
),
],
),
@@ -1045,17 +1089,51 @@ Widget build(BuildContext context) {
),
bottomNavigationBar: BottomAppBar(
color: Colors.grey[900],
padding: EdgeInsets.zero,
child: SizedBox(
height: 56,
child: Center(
child: Text(
"🎯 Total Score: $_totalScore",
style: const TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.white,
height: 150,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Left side - Label (darker grey)
const Padding(
padding: EdgeInsets.only(right: 16),
child: FittedBox(
fit: BoxFit.scaleDown,
child: Text(
"🎯 Total Score:",
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
),
),
// Right side - Score badge (grey with rounded corners)
Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
decoration: BoxDecoration(
color: Colors.grey[800],
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: Colors.grey[700]!,
width: 2,
),
),
child: FittedBox(
fit: BoxFit.scaleDown,
child: Text(
"$_totalScore",
style: const TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
),
],
),
),
),