new targets
This commit is contained in:
@@ -6,6 +6,7 @@ import 'package:path_provider/path_provider.dart'; // For getApplicationDocument
|
||||
import 'target_view.dart'; // Import the TargetViewScreen
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import '../utils/translations.dart';
|
||||
import '../utils/target_colors.dart';
|
||||
|
||||
class BookScreen extends StatefulWidget {
|
||||
const BookScreen({super.key});
|
||||
@@ -25,13 +26,17 @@ class _BookScreenState extends State<BookScreen> with WidgetsBindingObserver {
|
||||
String _sortMode = 'date'; // or 'score'
|
||||
String _selectedLanguage = 'English';
|
||||
String? _expandedFolder; // Track which folder is expanded
|
||||
late Color _backgroundColor;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addObserver(this); // Register to listen for lifecycle events
|
||||
// Initialize with default target background color
|
||||
_backgroundColor = TargetColors.getBackgroundColor('assets/target.png');
|
||||
_loadBulletColor();
|
||||
_loadLanguage();
|
||||
_loadSelectedTargetColor();
|
||||
_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
|
||||
void dispose() {
|
||||
WidgetsBinding.instance.removeObserver(this); // Unregister from lifecycle events when disposed
|
||||
@@ -895,6 +908,7 @@ Widget _buildTargetsList(String folderName) {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: _backgroundColor,
|
||||
body: Column(
|
||||
children: [
|
||||
// 🔽 Filter dropdown at the top (styled like tab bar)
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import '../services/google_calendar_service.dart';
|
||||
import '../utils/translations.dart';
|
||||
import '../utils/target_colors.dart';
|
||||
|
||||
class Contact {
|
||||
final String firstName;
|
||||
@@ -45,6 +46,7 @@ class _CalendarScreenState extends State<CalendarScreen> {
|
||||
String _selectedLanguage = 'English';
|
||||
bool _showContacts = false;
|
||||
bool _showDebugPreview = false;
|
||||
late Color _backgroundColor;
|
||||
|
||||
// Members contact list
|
||||
final List<Contact> _contacts = [
|
||||
@@ -69,8 +71,11 @@ class _CalendarScreenState extends State<CalendarScreen> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
initializeDateFormatting('sl_SI', null); // Initialize Slovenian locale
|
||||
// Initialize with default target background color
|
||||
_backgroundColor = TargetColors.getBackgroundColor('assets/target.png');
|
||||
_loadBulletColor();
|
||||
_loadLanguage();
|
||||
_loadSelectedTargetColor();
|
||||
_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() {
|
||||
setState(() {
|
||||
_showDebugPreview = !_showDebugPreview;
|
||||
@@ -490,12 +503,12 @@ class _CalendarScreenState extends State<CalendarScreen> {
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Grey header bar with white text (matching book screen style)
|
||||
// Header bar with bullet color and transparency
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[900],
|
||||
color: accentColor.withValues(alpha: 0.6),
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(12),
|
||||
topRight: Radius.circular(12),
|
||||
@@ -733,7 +746,7 @@ class _CalendarScreenState extends State<CalendarScreen> {
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: _backgroundColor,
|
||||
body: Column(
|
||||
children: [
|
||||
// Tab buttons
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'yolo_detector.dart';
|
||||
import 'preview_screen.dart';
|
||||
import '../utils/translations.dart';
|
||||
import '../utils/target_colors.dart';
|
||||
|
||||
class CameraScreen extends StatefulWidget {
|
||||
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)
|
||||
int _numberOfBullets = 5;
|
||||
String _selectedLanguage = 'English';
|
||||
late Color _backgroundColor;
|
||||
|
||||
// Brightness and contrast controls
|
||||
double _brightness = 0.0; // -1.0 to 1.0
|
||||
@@ -31,10 +33,13 @@ class _CameraScreenState extends State<CameraScreen> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// Initialize with default target background color
|
||||
_backgroundColor = TargetColors.getBackgroundColor('assets/target.png');
|
||||
_loadBulletCount();
|
||||
_initCamera();
|
||||
_loadBulletColor(); // 👈
|
||||
_loadLanguage();
|
||||
_loadSelectedTargetColor();
|
||||
_loadBrightnessContrast();
|
||||
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 {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final selected = prefs.getString('bulletColor') ?? 'Blue';
|
||||
@@ -445,6 +458,7 @@ Color _getColorFromName(String colorName) {
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: _backgroundColor,
|
||||
extendBody: true,
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.grey[900],
|
||||
|
||||
@@ -8,6 +8,7 @@ import '../widgets/bottom_nav.dart';
|
||||
import 'camera_screen.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import '../utils/translations.dart';
|
||||
import '../utils/target_colors.dart';
|
||||
|
||||
|
||||
class HomeScreen extends StatefulWidget {
|
||||
@@ -20,6 +21,8 @@ class HomeScreen extends StatefulWidget {
|
||||
class _HomeScreenState extends State<HomeScreen> {
|
||||
int _selectedIndex = 1; // Default to Shooting Screen
|
||||
String _selectedLanguage = 'English';
|
||||
String _selectedTarget = 'assets/target.png';
|
||||
late Color _backgroundColor;
|
||||
|
||||
static final List<Widget> _pages = <Widget>[
|
||||
BookScreen(),
|
||||
@@ -40,7 +43,10 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// Initialize with default target background color
|
||||
_backgroundColor = TargetColors.getBackgroundColor('assets/target.png');
|
||||
_loadLanguage();
|
||||
_loadSelectedTarget();
|
||||
}
|
||||
|
||||
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) {
|
||||
if (index == 2) {
|
||||
_openCameraScan();
|
||||
@@ -114,6 +129,7 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
backgroundColor: _backgroundColor,
|
||||
body: _pages[_selectedIndex],
|
||||
bottomNavigationBar: BottomNavBar(
|
||||
selectedIndex: _selectedIndex,
|
||||
|
||||
@@ -25,7 +25,7 @@ enum PreviewMode { cameraWithDetections, mappedTarget }
|
||||
|
||||
class _PreviewScreenState extends State<PreviewScreen> {
|
||||
bool _isLoading = true;
|
||||
PreviewMode _mode = PreviewMode.mappedTarget;
|
||||
PreviewMode _mode = PreviewMode.cameraWithDetections;
|
||||
|
||||
List<Offset> _mappedBullets = [];
|
||||
late List<DetectionResult> _realImageDetections;
|
||||
@@ -134,20 +134,62 @@ class _PreviewScreenState extends State<PreviewScreen> {
|
||||
return const Color(0xFF02050A); // Very dark blue/black
|
||||
|
||||
case 'assets/targets/Target6.jpg':
|
||||
return const Color(0xFF000000); // Black
|
||||
return const Color(0xFFF3E7D1); // Light beige
|
||||
|
||||
case 'assets/targets/Target7.jpg':
|
||||
return const Color(0xFFFFD454); // Bright yellow
|
||||
|
||||
case 'assets/targets/Target11.jpg':
|
||||
case 'assets/targets/Target8.jpg':
|
||||
return const Color(0xFF1E5E81); // Dark teal blue
|
||||
|
||||
case 'assets/targets/Target14.jpg':
|
||||
case 'assets/targets/Target9.jpg':
|
||||
return const Color(0xFFFEFEFC); // Off-white
|
||||
|
||||
case 'assets/targets/Target15.jpg':
|
||||
case 'assets/targets/Target10.jpg':
|
||||
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:
|
||||
return Colors.grey[900]!; // Fallback to dark gray
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import '../utils/translations.dart';
|
||||
import '../utils/target_colors.dart';
|
||||
|
||||
class SettingsScreen extends StatefulWidget {
|
||||
const SettingsScreen({super.key});
|
||||
@@ -10,6 +11,7 @@ class SettingsScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _SettingsScreenState extends State<SettingsScreen> {
|
||||
Color _backgroundColor = Colors.grey[900]!;
|
||||
List<String> _cameraIPs = List.generate(6, (index) => 'Not Set');
|
||||
|
||||
final List<String> _defaultIPs = [
|
||||
@@ -57,9 +59,23 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
'assets/targets/Target5.jpg',
|
||||
'assets/targets/Target6.jpg',
|
||||
'assets/targets/Target7.jpg',
|
||||
'assets/targets/Target8.jpg',
|
||||
'assets/targets/Target9.jpg',
|
||||
'assets/targets/Target10.jpg',
|
||||
'assets/targets/Target11.jpg',
|
||||
'assets/targets/Target12.jpg',
|
||||
'assets/targets/Target13.jpg',
|
||||
'assets/targets/Target14.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
|
||||
@@ -155,22 +171,27 @@ Future<void> _loadSelectedTarget() async {
|
||||
|
||||
setState(() {
|
||||
_selectedTarget = savedTarget;
|
||||
_backgroundColor = TargetColors.getBackgroundColor(savedTarget);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _saveSelectedTarget(String target) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString('selectedTarget', target);
|
||||
setState(() => _selectedTarget = target);
|
||||
setState(() {
|
||||
_selectedTarget = target;
|
||||
_backgroundColor = TargetColors.getBackgroundColor(target);
|
||||
});
|
||||
}
|
||||
|
||||
String _getTargetDisplayName(String targetPath) {
|
||||
if (targetPath == 'assets/target.png') {
|
||||
return 'Default Target';
|
||||
return _t('Default Target');
|
||||
}
|
||||
return targetPath
|
||||
final targetName = targetPath
|
||||
.replaceAll('assets/targets/', '')
|
||||
.replaceAll('.jpg', '');
|
||||
return _t(targetName);
|
||||
}
|
||||
|
||||
Future<void> _loadCameraIPs() async {
|
||||
@@ -345,7 +366,7 @@ String _getTargetDisplayName(String targetPath) {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
||||
backgroundColor: _backgroundColor,
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||
child: Column(
|
||||
@@ -952,6 +973,12 @@ void _showTargetPopup() {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
borderRadius: index == 5
|
||||
? const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(12),
|
||||
bottomRight: Radius.circular(12),
|
||||
)
|
||||
: null,
|
||||
border: index < 5
|
||||
? Border(
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -251,7 +251,7 @@ class _SpectatorScreenState extends State<SpectatorScreen> {
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
padding: const EdgeInsets.fromLTRB(8, 8, 8, 24),
|
||||
padding: const EdgeInsets.fromLTRB(4, 4, 4, 16),
|
||||
itemCount: visibleCameras.length,
|
||||
itemBuilder: (context, index) {
|
||||
final camera = visibleCameras[index];
|
||||
@@ -262,16 +262,16 @@ class _SpectatorScreenState extends State<SpectatorScreen> {
|
||||
? cameraIp
|
||||
: "http://$cameraIp";
|
||||
|
||||
// 16:9 aspect ratio = width / height
|
||||
// 4:3 aspect ratio = width / height (640x480 stream)
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
margin: const EdgeInsets.only(bottom: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: Colors.grey[800]!, width: 1),
|
||||
),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 16 / 9,
|
||||
aspectRatio: 4 / 3,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Stack(
|
||||
@@ -279,7 +279,7 @@ class _SpectatorScreenState extends State<SpectatorScreen> {
|
||||
Mjpeg(
|
||||
stream: streamUrl,
|
||||
isLive: true,
|
||||
fit: BoxFit.contain,
|
||||
fit: BoxFit.cover,
|
||||
error: (context, error, stackTrace) {
|
||||
return Container(
|
||||
color: Colors.grey[700],
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'stream_screen.dart'; // Import the camera stream screen
|
||||
import 'spectator_screen.dart';
|
||||
import '../utils/translations.dart';
|
||||
import '../utils/target_colors.dart';
|
||||
|
||||
class TargetScreen extends StatefulWidget {
|
||||
const TargetScreen({super.key});
|
||||
@@ -15,11 +16,15 @@ class _TargetScreenState extends State<TargetScreen> {
|
||||
List<bool> _cameraButtonsEnabled =
|
||||
List.generate(6, (_) => false); // Initially, all buttons are disabled
|
||||
String _selectedLanguage = 'English';
|
||||
late Color _backgroundColor;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// Initialize with default target background color
|
||||
_backgroundColor = TargetColors.getBackgroundColor('assets/target.png');
|
||||
_loadLanguage();
|
||||
_loadSelectedTargetColor();
|
||||
_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
|
||||
Future<void> _loadCameraData() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
@@ -67,6 +80,7 @@ class _TargetScreenState extends State<TargetScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: _backgroundColor,
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
|
||||
child: Column(
|
||||
|
||||
@@ -26,6 +26,7 @@ class TargetViewScreen extends StatefulWidget {
|
||||
class _TargetViewScreenState extends State<TargetViewScreen> {
|
||||
int _currentIndex = 0;
|
||||
List<Offset> _bullets = [];
|
||||
List<Offset> _scaledBullets = []; // Bullets scaled to display target size
|
||||
int _totalScore = 0;
|
||||
Offset? _targetCenter;
|
||||
Uint8List? _targetImageBytes;
|
||||
@@ -35,7 +36,10 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
|
||||
int? _pressedScoreGroup;
|
||||
late String _targetFilePath;
|
||||
late String targetAssetPath;
|
||||
late String _selectedTargetPath; // For display
|
||||
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
|
||||
String _selectedLanguage = 'English';
|
||||
@@ -72,7 +76,10 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
|
||||
Future<void> _loadSelectedTarget() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -81,37 +88,54 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
|
||||
switch (targetPath) {
|
||||
case 'assets/target.png':
|
||||
return const Color(0xFFFFFFFF); // White
|
||||
|
||||
case 'assets/targets/Target1.jpg':
|
||||
return const Color(0xFFE8ECD5); // Light beige
|
||||
|
||||
case 'assets/targets/Target2.jpg':
|
||||
return const Color(0xFFC1DF87); // Light green
|
||||
|
||||
case 'assets/targets/Target3.jpg':
|
||||
return const Color(0xFFFEFEFE); // Off-white
|
||||
|
||||
case 'assets/targets/Target4.jpg':
|
||||
return const Color(0xFFD42931); // Red
|
||||
|
||||
case 'assets/targets/Target5.jpg':
|
||||
return const Color(0xFF02050A); // Very dark blue/black
|
||||
|
||||
case 'assets/targets/Target6.jpg':
|
||||
return const Color(0xFF000000); // Black
|
||||
|
||||
return const Color(0xFFF3E7D1); // Light beige
|
||||
case 'assets/targets/Target7.jpg':
|
||||
return const Color(0xFFFFD454); // Bright yellow
|
||||
|
||||
case 'assets/targets/Target11.jpg':
|
||||
case 'assets/targets/Target8.jpg':
|
||||
return const Color(0xFF1E5E81); // Dark teal blue
|
||||
|
||||
case 'assets/targets/Target14.jpg':
|
||||
case 'assets/targets/Target9.jpg':
|
||||
return const Color(0xFFFEFEFC); // Off-white
|
||||
|
||||
case 'assets/targets/Target15.jpg':
|
||||
case 'assets/targets/Target10.jpg':
|
||||
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:
|
||||
return Colors.white; // Fallback to white
|
||||
}
|
||||
@@ -167,20 +191,33 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
|
||||
|
||||
Future<void> _loadJsonAndImage() async {
|
||||
try {
|
||||
final byteData = await rootBundle.load(targetAssetPath);
|
||||
final bytes = byteData.buffer.asUint8List();
|
||||
_targetImageDecoded = img.decodeImage(bytes);
|
||||
// Load default target for bullet positioning reference
|
||||
final defaultByteData = await rootBundle.load(targetAssetPath);
|
||||
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) {
|
||||
print("Failed to decode image.");
|
||||
print("Failed to decode display target image.");
|
||||
return;
|
||||
}
|
||||
|
||||
_targetImageBytes = Uint8List.fromList(img.encodePng(_targetImageDecoded!));
|
||||
_targetCenter = Offset(
|
||||
_targetImageDecoded!.width / 2,
|
||||
_targetImageDecoded!.height / 2 - 1,
|
||||
);
|
||||
|
||||
final currentFile = widget.jsonFiles[_currentIndex];
|
||||
final jsonString = await currentFile.readAsString();
|
||||
@@ -210,6 +247,18 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
|
||||
|
||||
_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
|
||||
.map((b) => _scoreForBullet(b, _targetCenter!))
|
||||
.fold(0, (sum, score) => sum + score);
|
||||
@@ -386,12 +435,15 @@ class _TargetViewScreenState extends State<TargetViewScreen> {
|
||||
height: displayHeight,
|
||||
child: Image.memory(_targetImageBytes!, fit: BoxFit.fill),
|
||||
),
|
||||
..._bullets.asMap().entries.map((entry) {
|
||||
..._scaledBullets.asMap().entries.map((entry) {
|
||||
final i = entry.key;
|
||||
final bullet = entry.value;
|
||||
final dx = bullet.dx * scaleX + offsetX;
|
||||
final dy = bullet.dy * scaleY + offsetY;
|
||||
final score = _scoreForBullet(bullet, _targetCenter ?? Offset.zero);
|
||||
final scaledBullet = entry.value;
|
||||
// Scaled bullets are already scaled to display target dimensions
|
||||
final dx = scaledBullet.dx * scaleX + offsetX;
|
||||
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
|
||||
? (_pressedScoreGroup == score)
|
||||
: (i == _highlightedBulletIndex);
|
||||
|
||||
Reference in New Issue
Block a user