new targets

This commit is contained in:
2025-12-23 16:30:36 +01:00
parent e111f0a99b
commit b727e65d14
32 changed files with 379 additions and 55 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 378 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 357 KiB

After

Width:  |  Height:  |  Size: 347 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 KiB

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 KiB

After

Width:  |  Height:  |  Size: 387 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 308 KiB

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 484 KiB

After

Width:  |  Height:  |  Size: 489 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 452 KiB

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 KiB

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 KiB

+14
View File
@@ -6,6 +6,7 @@ import 'package:path_provider/path_provider.dart'; // For getApplicationDocument
import 'target_view.dart'; // Import the TargetViewScreen import 'target_view.dart'; // Import the TargetViewScreen
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import '../utils/translations.dart'; import '../utils/translations.dart';
import '../utils/target_colors.dart';
class BookScreen extends StatefulWidget { class BookScreen extends StatefulWidget {
const BookScreen({super.key}); const BookScreen({super.key});
@@ -25,13 +26,17 @@ class _BookScreenState extends State<BookScreen> with WidgetsBindingObserver {
String _sortMode = 'date'; // or 'score' String _sortMode = 'date'; // or 'score'
String _selectedLanguage = 'English'; String _selectedLanguage = 'English';
String? _expandedFolder; // Track which folder is expanded String? _expandedFolder; // Track which folder is expanded
late Color _backgroundColor;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
WidgetsBinding.instance.addObserver(this); // Register to listen for lifecycle events WidgetsBinding.instance.addObserver(this); // Register to listen for lifecycle events
// Initialize with default target background color
_backgroundColor = TargetColors.getBackgroundColor('assets/target.png');
_loadBulletColor(); _loadBulletColor();
_loadLanguage(); _loadLanguage();
_loadSelectedTargetColor();
_loadTargetDataFiles(); // Initial load when the screen is first created _loadTargetDataFiles(); // Initial load when the screen is first created
} }
@@ -46,6 +51,14 @@ class _BookScreenState extends State<BookScreen> with WidgetsBindingObserver {
}); });
} }
Future<void> _loadSelectedTargetColor() async {
final prefs = await SharedPreferences.getInstance();
final selectedTarget = prefs.getString('selectedTarget') ?? 'assets/target.png';
setState(() {
_backgroundColor = TargetColors.getBackgroundColor(selectedTarget);
});
}
@override @override
void dispose() { void dispose() {
WidgetsBinding.instance.removeObserver(this); // Unregister from lifecycle events when disposed WidgetsBinding.instance.removeObserver(this); // Unregister from lifecycle events when disposed
@@ -895,6 +908,7 @@ Widget _buildTargetsList(String folderName) {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: _backgroundColor,
body: Column( body: Column(
children: [ children: [
// 🔽 Filter dropdown at the top (styled like tab bar) // 🔽 Filter dropdown at the top (styled like tab bar)
+16 -3
View File
@@ -6,6 +6,7 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import '../services/google_calendar_service.dart'; import '../services/google_calendar_service.dart';
import '../utils/translations.dart'; import '../utils/translations.dart';
import '../utils/target_colors.dart';
class Contact { class Contact {
final String firstName; final String firstName;
@@ -45,6 +46,7 @@ class _CalendarScreenState extends State<CalendarScreen> {
String _selectedLanguage = 'English'; String _selectedLanguage = 'English';
bool _showContacts = false; bool _showContacts = false;
bool _showDebugPreview = false; bool _showDebugPreview = false;
late Color _backgroundColor;
// Members contact list // Members contact list
final List<Contact> _contacts = [ final List<Contact> _contacts = [
@@ -69,8 +71,11 @@ class _CalendarScreenState extends State<CalendarScreen> {
void initState() { void initState() {
super.initState(); super.initState();
initializeDateFormatting('sl_SI', null); // Initialize Slovenian locale initializeDateFormatting('sl_SI', null); // Initialize Slovenian locale
// Initialize with default target background color
_backgroundColor = TargetColors.getBackgroundColor('assets/target.png');
_loadBulletColor(); _loadBulletColor();
_loadLanguage(); _loadLanguage();
_loadSelectedTargetColor();
_loadEvents(); _loadEvents();
} }
@@ -85,6 +90,14 @@ class _CalendarScreenState extends State<CalendarScreen> {
}); });
} }
Future<void> _loadSelectedTargetColor() async {
final prefs = await SharedPreferences.getInstance();
final selectedTarget = prefs.getString('selectedTarget') ?? 'assets/target.png';
setState(() {
_backgroundColor = TargetColors.getBackgroundColor(selectedTarget);
});
}
void _toggleDebugPreview() { void _toggleDebugPreview() {
setState(() { setState(() {
_showDebugPreview = !_showDebugPreview; _showDebugPreview = !_showDebugPreview;
@@ -490,12 +503,12 @@ class _CalendarScreenState extends State<CalendarScreen> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// Grey header bar with white text (matching book screen style) // Header bar with bullet color and transparency
Container( Container(
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey[900], color: accentColor.withValues(alpha: 0.6),
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
topLeft: Radius.circular(12), topLeft: Radius.circular(12),
topRight: Radius.circular(12), topRight: Radius.circular(12),
@@ -733,7 +746,7 @@ class _CalendarScreenState extends State<CalendarScreen> {
} }
return Scaffold( return Scaffold(
backgroundColor: Colors.white, backgroundColor: _backgroundColor,
body: Column( body: Column(
children: [ children: [
// Tab buttons // Tab buttons
+14
View File
@@ -6,6 +6,7 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'yolo_detector.dart'; import 'yolo_detector.dart';
import 'preview_screen.dart'; import 'preview_screen.dart';
import '../utils/translations.dart'; import '../utils/translations.dart';
import '../utils/target_colors.dart';
class CameraScreen extends StatefulWidget { class CameraScreen extends StatefulWidget {
const CameraScreen({super.key}); const CameraScreen({super.key});
@@ -23,6 +24,7 @@ class _CameraScreenState extends State<CameraScreen> {
// The variable to hold the number of bullets entered by the user (default set to 5) // The variable to hold the number of bullets entered by the user (default set to 5)
int _numberOfBullets = 5; int _numberOfBullets = 5;
String _selectedLanguage = 'English'; String _selectedLanguage = 'English';
late Color _backgroundColor;
// Brightness and contrast controls // Brightness and contrast controls
double _brightness = 0.0; // -1.0 to 1.0 double _brightness = 0.0; // -1.0 to 1.0
@@ -31,10 +33,13 @@ class _CameraScreenState extends State<CameraScreen> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// Initialize with default target background color
_backgroundColor = TargetColors.getBackgroundColor('assets/target.png');
_loadBulletCount(); _loadBulletCount();
_initCamera(); _initCamera();
_loadBulletColor(); // 👈 _loadBulletColor(); // 👈
_loadLanguage(); _loadLanguage();
_loadSelectedTargetColor();
_loadBrightnessContrast(); _loadBrightnessContrast();
YOLODetector.create().then((detector) => _yoloDetector = detector); YOLODetector.create().then((detector) => _yoloDetector = detector);
} }
@@ -64,6 +69,14 @@ class _CameraScreenState extends State<CameraScreen> {
}); });
} }
Future<void> _loadSelectedTargetColor() async {
final prefs = await SharedPreferences.getInstance();
final selectedTarget = prefs.getString('selectedTarget') ?? 'assets/target.png';
setState(() {
_backgroundColor = TargetColors.getBackgroundColor(selectedTarget);
});
}
Future<void> _loadBulletColor() async { Future<void> _loadBulletColor() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
final selected = prefs.getString('bulletColor') ?? 'Blue'; final selected = prefs.getString('bulletColor') ?? 'Blue';
@@ -445,6 +458,7 @@ Color _getColorFromName(String colorName) {
} }
return Scaffold( return Scaffold(
backgroundColor: _backgroundColor,
extendBody: true, extendBody: true,
appBar: AppBar( appBar: AppBar(
backgroundColor: Colors.grey[900], backgroundColor: Colors.grey[900],
+16
View File
@@ -8,6 +8,7 @@ import '../widgets/bottom_nav.dart';
import 'camera_screen.dart'; import 'camera_screen.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import '../utils/translations.dart'; import '../utils/translations.dart';
import '../utils/target_colors.dart';
class HomeScreen extends StatefulWidget { class HomeScreen extends StatefulWidget {
@@ -20,6 +21,8 @@ class HomeScreen extends StatefulWidget {
class _HomeScreenState extends State<HomeScreen> { class _HomeScreenState extends State<HomeScreen> {
int _selectedIndex = 1; // Default to Shooting Screen int _selectedIndex = 1; // Default to Shooting Screen
String _selectedLanguage = 'English'; String _selectedLanguage = 'English';
String _selectedTarget = 'assets/target.png';
late Color _backgroundColor;
static final List<Widget> _pages = <Widget>[ static final List<Widget> _pages = <Widget>[
BookScreen(), BookScreen(),
@@ -40,7 +43,10 @@ class _HomeScreenState extends State<HomeScreen> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// Initialize with default target background color
_backgroundColor = TargetColors.getBackgroundColor('assets/target.png');
_loadLanguage(); _loadLanguage();
_loadSelectedTarget();
} }
String _t(String key) { String _t(String key) {
@@ -54,6 +60,15 @@ class _HomeScreenState extends State<HomeScreen> {
}); });
} }
Future<void> _loadSelectedTarget() async {
final prefs = await SharedPreferences.getInstance();
final selectedTarget = prefs.getString('selectedTarget') ?? 'assets/target.png';
setState(() {
_selectedTarget = selectedTarget;
_backgroundColor = TargetColors.getBackgroundColor(selectedTarget);
});
}
void _onItemTapped(int index) { void _onItemTapped(int index) {
if (index == 2) { if (index == 2) {
_openCameraScan(); _openCameraScan();
@@ -114,6 +129,7 @@ class _HomeScreenState extends State<HomeScreen> {
), ),
], ],
), ),
backgroundColor: _backgroundColor,
body: _pages[_selectedIndex], body: _pages[_selectedIndex],
bottomNavigationBar: BottomNavBar( bottomNavigationBar: BottomNavBar(
selectedIndex: _selectedIndex, selectedIndex: _selectedIndex,
+47 -5
View File
@@ -25,7 +25,7 @@ enum PreviewMode { cameraWithDetections, mappedTarget }
class _PreviewScreenState extends State<PreviewScreen> { class _PreviewScreenState extends State<PreviewScreen> {
bool _isLoading = true; bool _isLoading = true;
PreviewMode _mode = PreviewMode.mappedTarget; PreviewMode _mode = PreviewMode.cameraWithDetections;
List<Offset> _mappedBullets = []; List<Offset> _mappedBullets = [];
late List<DetectionResult> _realImageDetections; late List<DetectionResult> _realImageDetections;
@@ -134,20 +134,62 @@ class _PreviewScreenState extends State<PreviewScreen> {
return const Color(0xFF02050A); // Very dark blue/black return const Color(0xFF02050A); // Very dark blue/black
case 'assets/targets/Target6.jpg': case 'assets/targets/Target6.jpg':
return const Color(0xFF000000); // Black return const Color(0xFFF3E7D1); // Light beige
case 'assets/targets/Target7.jpg': case 'assets/targets/Target7.jpg':
return const Color(0xFFFFD454); // Bright yellow return const Color(0xFFFFD454); // Bright yellow
case 'assets/targets/Target11.jpg': case 'assets/targets/Target8.jpg':
return const Color(0xFF1E5E81); // Dark teal blue return const Color(0xFF1E5E81); // Dark teal blue
case 'assets/targets/Target14.jpg': case 'assets/targets/Target9.jpg':
return const Color(0xFFFEFEFC); // Off-white return const Color(0xFFFEFEFC); // Off-white
case 'assets/targets/Target15.jpg': case 'assets/targets/Target10.jpg':
return const Color(0xFF98926E); // Olive green return const Color(0xFF98926E); // Olive green
case 'assets/targets/Target11.jpg':
return const Color(0xFF13132B); // Dark blue
case 'assets/targets/Target12.jpg':
return const Color(0xFFF5F4EF); // Off-white
case 'assets/targets/Target13.jpg':
return const Color(0xFF174AA5); // Blue
case 'assets/targets/Target14.jpg':
return const Color(0xFFFEE05E); // Light yellow
case 'assets/targets/Target15.jpg':
return const Color(0xFFFFFFFF); // White
case 'assets/targets/Target16.jpg':
return const Color(0xFF000000); // Black
case 'assets/targets/Target17.jpg':
return const Color(0xFF13132B); // Dark blue
case 'assets/targets/Target18.jpg':
return const Color(0xFF050608); // Very dark gray
case 'assets/targets/Target19.jpg':
return const Color(0xFFC32534); // Dark red
case 'assets/targets/Target20.jpg':
return const Color(0xFFFCF3EE); // Light beige
case 'assets/targets/Target21.jpg':
return const Color(0xFFDA6868); // Muted red
case 'assets/targets/Target22.jpg':
return const Color(0xFFFDFAF3); // Off-white
case 'assets/targets/Target23.jpg':
return const Color(0xFFFFFFFD); // White
case 'assets/targets/Target24.jpg':
return const Color(0xFFFFC4C6); // Light pink
default: default:
return Colors.grey[900]!; // Fallback to dark gray return Colors.grey[900]!; // Fallback to dark gray
} }
+31 -13
View File
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import '../utils/translations.dart'; import '../utils/translations.dart';
import '../utils/target_colors.dart';
class SettingsScreen extends StatefulWidget { class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key}); const SettingsScreen({super.key});
@@ -10,6 +11,7 @@ class SettingsScreen extends StatefulWidget {
} }
class _SettingsScreenState extends State<SettingsScreen> { class _SettingsScreenState extends State<SettingsScreen> {
Color _backgroundColor = Colors.grey[900]!;
List<String> _cameraIPs = List.generate(6, (index) => 'Not Set'); List<String> _cameraIPs = List.generate(6, (index) => 'Not Set');
final List<String> _defaultIPs = [ final List<String> _defaultIPs = [
@@ -57,9 +59,23 @@ class _SettingsScreenState extends State<SettingsScreen> {
'assets/targets/Target5.jpg', 'assets/targets/Target5.jpg',
'assets/targets/Target6.jpg', 'assets/targets/Target6.jpg',
'assets/targets/Target7.jpg', 'assets/targets/Target7.jpg',
'assets/targets/Target8.jpg',
'assets/targets/Target9.jpg',
'assets/targets/Target10.jpg',
'assets/targets/Target11.jpg', 'assets/targets/Target11.jpg',
'assets/targets/Target12.jpg',
'assets/targets/Target13.jpg',
'assets/targets/Target14.jpg', 'assets/targets/Target14.jpg',
'assets/targets/Target15.jpg', 'assets/targets/Target15.jpg',
'assets/targets/Target16.jpg',
'assets/targets/Target17.jpg',
'assets/targets/Target18.jpg',
'assets/targets/Target19.jpg',
'assets/targets/Target20.jpg',
'assets/targets/Target21.jpg',
'assets/targets/Target22.jpg',
'assets/targets/Target23.jpg',
'assets/targets/Target24.jpg',
]; ];
@override @override
@@ -155,22 +171,27 @@ Future<void> _loadSelectedTarget() async {
setState(() { setState(() {
_selectedTarget = savedTarget; _selectedTarget = savedTarget;
_backgroundColor = TargetColors.getBackgroundColor(savedTarget);
}); });
} }
Future<void> _saveSelectedTarget(String target) async { Future<void> _saveSelectedTarget(String target) async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
await prefs.setString('selectedTarget', target); await prefs.setString('selectedTarget', target);
setState(() => _selectedTarget = target); setState(() {
_selectedTarget = target;
_backgroundColor = TargetColors.getBackgroundColor(target);
});
} }
String _getTargetDisplayName(String targetPath) { String _getTargetDisplayName(String targetPath) {
if (targetPath == 'assets/target.png') { if (targetPath == 'assets/target.png') {
return 'Default Target'; return _t('Default Target');
} }
return targetPath final targetName = targetPath
.replaceAll('assets/targets/', '') .replaceAll('assets/targets/', '')
.replaceAll('.jpg', ''); .replaceAll('.jpg', '');
return _t(targetName);
} }
Future<void> _loadCameraIPs() async { Future<void> _loadCameraIPs() async {
@@ -345,7 +366,7 @@ String _getTargetDisplayName(String targetPath) {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: _backgroundColor,
body: SingleChildScrollView( body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Column( child: Column(
@@ -952,6 +973,12 @@ void _showTargetPopup() {
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey[300], color: Colors.grey[300],
borderRadius: index == 5
? const BorderRadius.only(
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12),
)
: null,
border: index < 5 border: index < 5
? Border( ? Border(
bottom: BorderSide( bottom: BorderSide(
@@ -984,15 +1011,6 @@ void _showTargetPopup() {
], ],
), ),
), ),
if (index == 5)
Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12),
),
),
),
], ],
), ),
); );
+5 -5
View File
@@ -251,7 +251,7 @@ class _SpectatorScreenState extends State<SpectatorScreen> {
), ),
) )
: ListView.builder( : ListView.builder(
padding: const EdgeInsets.fromLTRB(8, 8, 8, 24), padding: const EdgeInsets.fromLTRB(4, 4, 4, 16),
itemCount: visibleCameras.length, itemCount: visibleCameras.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final camera = visibleCameras[index]; final camera = visibleCameras[index];
@@ -262,16 +262,16 @@ class _SpectatorScreenState extends State<SpectatorScreen> {
? cameraIp ? cameraIp
: "http://$cameraIp"; : "http://$cameraIp";
// 16:9 aspect ratio = width / height // 4:3 aspect ratio = width / height (640x480 stream)
return Container( return Container(
margin: const EdgeInsets.only(bottom: 8), margin: const EdgeInsets.only(bottom: 4),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.black, color: Colors.black,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey[800]!, width: 1), border: Border.all(color: Colors.grey[800]!, width: 1),
), ),
child: AspectRatio( child: AspectRatio(
aspectRatio: 16 / 9, aspectRatio: 4 / 3,
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
child: Stack( child: Stack(
@@ -279,7 +279,7 @@ class _SpectatorScreenState extends State<SpectatorScreen> {
Mjpeg( Mjpeg(
stream: streamUrl, stream: streamUrl,
isLive: true, isLive: true,
fit: BoxFit.contain, fit: BoxFit.cover,
error: (context, error, stackTrace) { error: (context, error, stackTrace) {
return Container( return Container(
color: Colors.grey[700], color: Colors.grey[700],
+14
View File
@@ -3,6 +3,7 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'stream_screen.dart'; // Import the camera stream screen import 'stream_screen.dart'; // Import the camera stream screen
import 'spectator_screen.dart'; import 'spectator_screen.dart';
import '../utils/translations.dart'; import '../utils/translations.dart';
import '../utils/target_colors.dart';
class TargetScreen extends StatefulWidget { class TargetScreen extends StatefulWidget {
const TargetScreen({super.key}); const TargetScreen({super.key});
@@ -15,11 +16,15 @@ class _TargetScreenState extends State<TargetScreen> {
List<bool> _cameraButtonsEnabled = List<bool> _cameraButtonsEnabled =
List.generate(6, (_) => false); // Initially, all buttons are disabled List.generate(6, (_) => false); // Initially, all buttons are disabled
String _selectedLanguage = 'English'; String _selectedLanguage = 'English';
late Color _backgroundColor;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// Initialize with default target background color
_backgroundColor = TargetColors.getBackgroundColor('assets/target.png');
_loadLanguage(); _loadLanguage();
_loadSelectedTargetColor();
_loadCameraData(); _loadCameraData();
} }
@@ -34,6 +39,14 @@ class _TargetScreenState extends State<TargetScreen> {
}); });
} }
Future<void> _loadSelectedTargetColor() async {
final prefs = await SharedPreferences.getInstance();
final selectedTarget = prefs.getString('selectedTarget') ?? 'assets/target.png';
setState(() {
_backgroundColor = TargetColors.getBackgroundColor(selectedTarget);
});
}
/// Load the camera IPs from SharedPreferences and update button status /// Load the camera IPs from SharedPreferences and update button status
Future<void> _loadCameraData() async { Future<void> _loadCameraData() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
@@ -67,6 +80,7 @@ class _TargetScreenState extends State<TargetScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: _backgroundColor,
body: Padding( body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
child: Column( child: Column(
+81 -29
View File
@@ -26,6 +26,7 @@ class TargetViewScreen extends StatefulWidget {
class _TargetViewScreenState extends State<TargetViewScreen> { class _TargetViewScreenState extends State<TargetViewScreen> {
int _currentIndex = 0; int _currentIndex = 0;
List<Offset> _bullets = []; List<Offset> _bullets = [];
List<Offset> _scaledBullets = []; // Bullets scaled to display target size
int _totalScore = 0; int _totalScore = 0;
Offset? _targetCenter; Offset? _targetCenter;
Uint8List? _targetImageBytes; Uint8List? _targetImageBytes;
@@ -35,7 +36,10 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
int? _pressedScoreGroup; int? _pressedScoreGroup;
late String _targetFilePath; late String _targetFilePath;
late String targetAssetPath; late String targetAssetPath;
late String _selectedTargetPath; // For display
final double bulletSize = 19; final double bulletSize = 19;
double _scaleFactorX = 1.0; // Scale factor for X coordinate
double _scaleFactorY = 1.0; // Scale factor for Y coordinate
Color _bulletColor = Colors.blue; // default/fallback bullet color Color _bulletColor = Colors.blue; // default/fallback bullet color
String _selectedLanguage = 'English'; String _selectedLanguage = 'English';
@@ -72,7 +76,10 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
Future<void> _loadSelectedTarget() async { Future<void> _loadSelectedTarget() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
final selectedTarget = prefs.getString('selectedTarget') ?? 'assets/target.png'; final selectedTarget = prefs.getString('selectedTarget') ?? 'assets/target.png';
targetAssetPath = selectedTarget; // Always use default target for bullet positioning
targetAssetPath = 'assets/target.png';
// Store selected target for display
_selectedTargetPath = selectedTarget;
_backgroundColor = _getBackgroundColorForTarget(selectedTarget); _backgroundColor = _getBackgroundColorForTarget(selectedTarget);
} }
@@ -81,37 +88,54 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
switch (targetPath) { switch (targetPath) {
case 'assets/target.png': case 'assets/target.png':
return const Color(0xFFFFFFFF); // White return const Color(0xFFFFFFFF); // White
case 'assets/targets/Target1.jpg': case 'assets/targets/Target1.jpg':
return const Color(0xFFE8ECD5); // Light beige return const Color(0xFFE8ECD5); // Light beige
case 'assets/targets/Target2.jpg': case 'assets/targets/Target2.jpg':
return const Color(0xFFC1DF87); // Light green return const Color(0xFFC1DF87); // Light green
case 'assets/targets/Target3.jpg': case 'assets/targets/Target3.jpg':
return const Color(0xFFFEFEFE); // Off-white return const Color(0xFFFEFEFE); // Off-white
case 'assets/targets/Target4.jpg': case 'assets/targets/Target4.jpg':
return const Color(0xFFD42931); // Red return const Color(0xFFD42931); // Red
case 'assets/targets/Target5.jpg': case 'assets/targets/Target5.jpg':
return const Color(0xFF02050A); // Very dark blue/black return const Color(0xFF02050A); // Very dark blue/black
case 'assets/targets/Target6.jpg': case 'assets/targets/Target6.jpg':
return const Color(0xFF000000); // Black return const Color(0xFFF3E7D1); // Light beige
case 'assets/targets/Target7.jpg': case 'assets/targets/Target7.jpg':
return const Color(0xFFFFD454); // Bright yellow return const Color(0xFFFFD454); // Bright yellow
case 'assets/targets/Target8.jpg':
case 'assets/targets/Target11.jpg':
return const Color(0xFF1E5E81); // Dark teal blue return const Color(0xFF1E5E81); // Dark teal blue
case 'assets/targets/Target9.jpg':
case 'assets/targets/Target14.jpg':
return const Color(0xFFFEFEFC); // Off-white return const Color(0xFFFEFEFC); // Off-white
case 'assets/targets/Target10.jpg':
case 'assets/targets/Target15.jpg':
return const Color(0xFF98926E); // Olive green return const Color(0xFF98926E); // Olive green
case 'assets/targets/Target11.jpg':
return const Color(0xFF13132B); // Dark blue
case 'assets/targets/Target12.jpg':
return const Color(0xFFF5F4EF); // Off-white
case 'assets/targets/Target13.jpg':
return const Color(0xFF174AA5); // Blue
case 'assets/targets/Target14.jpg':
return const Color(0xFFFEE05E); // Light yellow
case 'assets/targets/Target15.jpg':
return const Color(0xFFFFFFFF); // White
case 'assets/targets/Target16.jpg':
return const Color(0xFF000000); // Black
case 'assets/targets/Target17.jpg':
return const Color(0xFF13132B); // Dark blue
case 'assets/targets/Target18.jpg':
return const Color(0xFF050608); // Very dark gray
case 'assets/targets/Target19.jpg':
return const Color(0xFFC32534); // Dark red
case 'assets/targets/Target20.jpg':
return const Color(0xFFFCF3EE); // Light beige
case 'assets/targets/Target21.jpg':
return const Color(0xFFDA6868); // Muted red
case 'assets/targets/Target22.jpg':
return const Color(0xFFFDFAF3); // Off-white
case 'assets/targets/Target23.jpg':
return const Color(0xFFFFFFFD); // White
case 'assets/targets/Target24.jpg':
return const Color(0xFFFFC4C6); // Light pink
default: default:
return Colors.white; // Fallback to white return Colors.white; // Fallback to white
} }
@@ -167,20 +191,33 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
Future<void> _loadJsonAndImage() async { Future<void> _loadJsonAndImage() async {
try { try {
final byteData = await rootBundle.load(targetAssetPath); // Load default target for bullet positioning reference
final bytes = byteData.buffer.asUint8List(); final defaultByteData = await rootBundle.load(targetAssetPath);
_targetImageDecoded = img.decodeImage(bytes); final defaultBytes = defaultByteData.buffer.asUint8List();
img.Image? defaultTargetDecoded = img.decodeImage(defaultBytes);
if (defaultTargetDecoded == null) {
print("Failed to decode default target image.");
return;
}
// Calculate target center from default target (for bullet positioning)
_targetCenter = Offset(
defaultTargetDecoded.width / 2,
defaultTargetDecoded.height / 2 - 1,
);
// Load selected target for display
final displayByteData = await rootBundle.load(_selectedTargetPath);
final displayBytes = displayByteData.buffer.asUint8List();
_targetImageDecoded = img.decodeImage(displayBytes);
if (_targetImageDecoded == null) { if (_targetImageDecoded == null) {
print("Failed to decode image."); print("Failed to decode display target image.");
return; return;
} }
_targetImageBytes = Uint8List.fromList(img.encodePng(_targetImageDecoded!)); _targetImageBytes = Uint8List.fromList(img.encodePng(_targetImageDecoded!));
_targetCenter = Offset(
_targetImageDecoded!.width / 2,
_targetImageDecoded!.height / 2 - 1,
);
final currentFile = widget.jsonFiles[_currentIndex]; final currentFile = widget.jsonFiles[_currentIndex];
final jsonString = await currentFile.readAsString(); final jsonString = await currentFile.readAsString();
@@ -210,6 +247,18 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
_targetFilePath = currentFile.path; _targetFilePath = currentFile.path;
// Calculate scale factors based on image dimensions
_scaleFactorX = _targetImageDecoded!.width / defaultTargetDecoded.width;
_scaleFactorY = _targetImageDecoded!.height / defaultTargetDecoded.height;
// Scale bullets to match display target size
_scaledBullets = _bullets.map((bullet) {
return Offset(
bullet.dx * _scaleFactorX,
bullet.dy * _scaleFactorY,
);
}).toList();
_totalScore = _bullets _totalScore = _bullets
.map((b) => _scoreForBullet(b, _targetCenter!)) .map((b) => _scoreForBullet(b, _targetCenter!))
.fold(0, (sum, score) => sum + score); .fold(0, (sum, score) => sum + score);
@@ -386,12 +435,15 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
height: displayHeight, height: displayHeight,
child: Image.memory(_targetImageBytes!, fit: BoxFit.fill), child: Image.memory(_targetImageBytes!, fit: BoxFit.fill),
), ),
..._bullets.asMap().entries.map((entry) { ..._scaledBullets.asMap().entries.map((entry) {
final i = entry.key; final i = entry.key;
final bullet = entry.value; final scaledBullet = entry.value;
final dx = bullet.dx * scaleX + offsetX; // Scaled bullets are already scaled to display target dimensions
final dy = bullet.dy * scaleY + offsetY; final dx = scaledBullet.dx * scaleX + offsetX;
final score = _scoreForBullet(bullet, _targetCenter ?? Offset.zero); final dy = scaledBullet.dy * scaleY + offsetY;
// Score is calculated using original bullet position and default target center
final originalBullet = _bullets[i];
final score = _scoreForBullet(originalBullet, _targetCenter ?? Offset.zero);
final isHighlighted = widget.isCombinedView final isHighlighted = widget.isCombinedView
? (_pressedScoreGroup == score) ? (_pressedScoreGroup == score)
: (i == _highlightedBulletIndex); : (i == _highlightedBulletIndex);
+35
View File
@@ -0,0 +1,35 @@
import 'package:flutter/material.dart';
class TargetColors {
static const Map<String, Color> targetBackgroundColors = {
'assets/target.png': Color(0xFFFFFFFF), // White
'assets/targets/Target1.jpg': Color(0xFFE8ECD5), // Light beige
'assets/targets/Target2.jpg': Color(0xFFC1DF87), // Light green
'assets/targets/Target3.jpg': Color(0xFFFEFEFE), // Off-white
'assets/targets/Target4.jpg': Color(0xFFD42931), // Red
'assets/targets/Target5.jpg': Color(0xFF02050A), // Very dark blue/black
'assets/targets/Target6.jpg': Color(0xFFF3E7D1), // Light beige
'assets/targets/Target7.jpg': Color(0xFFFFD454), // Bright yellow
'assets/targets/Target8.jpg': Color(0xFF1E5E81), // Dark teal blue
'assets/targets/Target9.jpg': Color(0xFFFEFEFC), // Off-white
'assets/targets/Target10.jpg': Color(0xFF98926E), // Olive green
'assets/targets/Target11.jpg': Color(0xFF13132B), // Dark blue
'assets/targets/Target12.jpg': Color(0xFFF5F4EF), // Off-white
'assets/targets/Target13.jpg': Color(0xFF174AA5), // Blue
'assets/targets/Target14.jpg': Color(0xFFFEE05E), // Light yellow
'assets/targets/Target15.jpg': Color(0xFFFFFFFF), // White
'assets/targets/Target16.jpg': Color(0xFF000000), // Black
'assets/targets/Target17.jpg': Color(0xFF13132B), // Dark blue
'assets/targets/Target18.jpg': Color(0xFF050608), // Very dark gray
'assets/targets/Target19.jpg': Color(0xFFC32534), // Dark red
'assets/targets/Target20.jpg': Color(0xFFFCF3EE), // Light beige
'assets/targets/Target21.jpg': Color(0xFFDA6868), // Muted red
'assets/targets/Target22.jpg': Color(0xFFFDFAF3), // Off-white
'assets/targets/Target23.jpg': Color(0xFFFFFFFD), // White
'assets/targets/Target24.jpg': Color(0xFFFFC4C6), // Light pink
};
static Color getBackgroundColor(String targetPath) {
return targetBackgroundColors[targetPath] ?? Colors.grey[900]!;
}
}
+106
View File
@@ -24,6 +24,112 @@ class AppTranslations {
'Slovenian': 'Izberi barvo zadetka', 'Slovenian': 'Izberi barvo zadetka',
}, },
// Target selection
'Select Target': {
'English': 'Select Target',
'Slovenian': 'Izberi tarčo',
},
'Default Target': {
'English': 'Default Target',
'Slovenian': 'Privzeta tarča',
},
'Target1': {
'English': 'Target 1',
'Slovenian': 'Tarča 1',
},
'Target2': {
'English': 'Target 2',
'Slovenian': 'Tarča 2',
},
'Target3': {
'English': 'Target 3',
'Slovenian': 'Tarča 3',
},
'Target4': {
'English': 'Target 4',
'Slovenian': 'Tarča 4',
},
'Target5': {
'English': 'Target 5',
'Slovenian': 'Tarča 5',
},
'Target6': {
'English': 'Target 6',
'Slovenian': 'Tarča 6',
},
'Target7': {
'English': 'Target 7',
'Slovenian': 'Tarča 7',
},
'Target8': {
'English': 'Target 8',
'Slovenian': 'Tarča 8',
},
'Target9': {
'English': 'Target 9',
'Slovenian': 'Tarča 9',
},
'Target10': {
'English': 'Target 10',
'Slovenian': 'Tarča 10',
},
'Target11': {
'English': 'Target 11',
'Slovenian': 'Tarča 11',
},
'Target12': {
'English': 'Target 12',
'Slovenian': 'Tarča 12',
},
'Target13': {
'English': 'Target 13',
'Slovenian': 'Tarča 13',
},
'Target14': {
'English': 'Target 14',
'Slovenian': 'Tarča 14',
},
'Target15': {
'English': 'Target 15',
'Slovenian': 'Tarča 15',
},
'Target16': {
'English': 'Target 16',
'Slovenian': 'Tarča 16',
},
'Target17': {
'English': 'Target 17',
'Slovenian': 'Tarča 17',
},
'Target18': {
'English': 'Target 18',
'Slovenian': 'Tarča 18',
},
'Target19': {
'English': 'Target 19',
'Slovenian': 'Tarča 19',
},
'Target20': {
'English': 'Target 20',
'Slovenian': 'Tarča 20',
},
'Target21': {
'English': 'Target 21',
'Slovenian': 'Tarča 21',
},
'Target22': {
'English': 'Target 22',
'Slovenian': 'Tarča 22',
},
'Target23': {
'English': 'Target 23',
'Slovenian': 'Tarča 23',
},
'Target24': {
'English': 'Target 24',
'Slovenian': 'Tarča 24',
},
// Camera settings // Camera settings
'Camera Settings': { 'Camera Settings': {
'English': 'Camera Settings', 'English': 'Camera Settings',