V1.0.0
This commit is contained in:
+118
-40
@@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user