Updated app with modfications and new UI for graphs
This commit is contained in:
+185
-127
@@ -149,19 +149,52 @@ class _PreviewScreenState extends State<PreviewScreen> {
|
||||
|
||||
Color get _editColor => Colors.deepOrangeAccent;
|
||||
Color get _activeColor => _isEditMode ? _editColor : _bulletColor;
|
||||
Color get _activeColorWithOpacity => _activeColor.withValues(alpha: _bulletOpacity);
|
||||
Color get _activeColorWithOpacity =>
|
||||
_activeColor.withValues(alpha: _bulletOpacity);
|
||||
|
||||
String _selectedLanguage = 'English';
|
||||
Color _backgroundColor = Colors.grey[900]!;
|
||||
|
||||
String _currentFolderName = '';
|
||||
String _currentDate = '';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_realImageDetections = widget.detections;
|
||||
targetAssetPath = 'assets/target.png'; // Default
|
||||
_loadCurrentFolderInfo();
|
||||
_initializeScreen();
|
||||
}
|
||||
|
||||
Future<void> _loadCurrentFolderInfo() async {
|
||||
try {
|
||||
final directory = await getApplicationDocumentsDirectory();
|
||||
final saveDirectory = Directory('${directory.path}/saved_images');
|
||||
|
||||
if (await saveDirectory.exists()) {
|
||||
final folders =
|
||||
saveDirectory.listSync().whereType<Directory>().toList();
|
||||
if (folders.isNotEmpty) {
|
||||
// Sort by modification date to get the most recent folder
|
||||
folders.sort(
|
||||
(a, b) => b.statSync().changed.compareTo(a.statSync().changed));
|
||||
final lastFolder = folders.first.path.split('/').last;
|
||||
final today = DateTime.now();
|
||||
final formattedDate =
|
||||
"${today.day.toString().padLeft(2, '0')}-${today.month.toString().padLeft(2, '0')}-${today.year.toString().substring(2)}"; // DD-MM-YY format
|
||||
|
||||
setState(() {
|
||||
_currentFolderName = lastFolder;
|
||||
_currentDate = formattedDate;
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print("Error loading current folder info: $e");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _initializeScreen() async {
|
||||
await Future.wait([
|
||||
_loadDefaultTarget(), // Load default target for scale reference
|
||||
@@ -316,7 +349,7 @@ class _PreviewScreenState extends State<PreviewScreen> {
|
||||
return const Color(0xFF000000); // Black
|
||||
|
||||
case 'assets/targets/Target24.jpg':
|
||||
return const Color(0xFF000000); // Black
|
||||
return const Color(0xFFb7b7b7); // Gray
|
||||
|
||||
case 'assets/targets/Target25.jpg':
|
||||
return const Color(0xFF040308); // Very dark gray
|
||||
@@ -822,7 +855,8 @@ class _PreviewScreenState extends State<PreviewScreen> {
|
||||
return null;
|
||||
}
|
||||
|
||||
folders.sort((a, b) => b.statSync().changed.compareTo(a.statSync().changed));
|
||||
folders
|
||||
.sort((a, b) => b.statSync().changed.compareTo(a.statSync().changed));
|
||||
return folders.first.path.split('/').last;
|
||||
}
|
||||
|
||||
@@ -1283,6 +1317,29 @@ class _PreviewScreenState extends State<PreviewScreen> {
|
||||
_t('Detection Preview'),
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
_mode == PreviewMode.mappedTarget
|
||||
? Icons.camera_alt
|
||||
: Icons.center_focus_strong,
|
||||
color: Colors.white,
|
||||
size: 24,
|
||||
),
|
||||
onPressed: () async {
|
||||
setState(() {
|
||||
_mode = _mode == PreviewMode.mappedTarget
|
||||
? PreviewMode.cameraWithDetections
|
||||
: PreviewMode.mappedTarget;
|
||||
});
|
||||
await _loadSelectedTarget();
|
||||
},
|
||||
tooltip: _mode == PreviewMode.mappedTarget
|
||||
? _t("Show Camera Detections")
|
||||
: _t("Show Mapped Target"),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
),
|
||||
body: _isLoading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
@@ -1290,6 +1347,38 @@ class _PreviewScreenState extends State<PreviewScreen> {
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
// Training/Tournament Banner
|
||||
Container(
|
||||
color: Colors.grey[300],
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16, vertical: 10),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
_currentFolderName.isNotEmpty
|
||||
? _currentFolderName
|
||||
: 'No training selected',
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
if (_currentDate.isNotEmpty)
|
||||
Text(
|
||||
_currentDate,
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 11,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
@@ -1362,7 +1451,8 @@ class _PreviewScreenState extends State<PreviewScreen> {
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Container(
|
||||
color: Colors.green.withValues(alpha: 0.5),
|
||||
color: Colors.green
|
||||
.withValues(alpha: 0.5),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 4, vertical: 2),
|
||||
child: Text(
|
||||
@@ -1422,11 +1512,11 @@ class _PreviewScreenState extends State<PreviewScreen> {
|
||||
final Color bulletFillColor =
|
||||
isSelectedForEdit ||
|
||||
(!_isEditMode && isHighlighted)
|
||||
? Colors.red
|
||||
.withValues(alpha: _bulletOpacity)
|
||||
? Colors.red.withValues(
|
||||
alpha: _bulletOpacity)
|
||||
: isManual
|
||||
? Colors.red
|
||||
.withValues(alpha: _bulletOpacity)
|
||||
? Colors.red.withValues(
|
||||
alpha: _bulletOpacity)
|
||||
: _activeColorWithOpacity;
|
||||
|
||||
return Positioned(
|
||||
@@ -1459,7 +1549,7 @@ class _PreviewScreenState extends State<PreviewScreen> {
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: 24),
|
||||
if (_mappedBullets.isNotEmpty)
|
||||
Column(
|
||||
children: [
|
||||
@@ -1711,46 +1801,32 @@ class _PreviewScreenState extends State<PreviewScreen> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Top bar - Total Score
|
||||
BottomAppBar(
|
||||
color: Colors.grey[900],
|
||||
padding: EdgeInsets.zero,
|
||||
child: SizedBox(
|
||||
height: 60,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.track_changes,
|
||||
size: 24, color: Colors.white),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
_t("Total score:"),
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Text(
|
||||
"$_totalScore",
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
color: Colors.grey[300],
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(Icons.track_changes, size: 20, color: Colors.black),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
_t("Total score:"),
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
"$_totalScore",
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Bottom bar - Action Buttons
|
||||
@@ -1760,96 +1836,78 @@ class _PreviewScreenState extends State<PreviewScreen> {
|
||||
child: SizedBox(
|
||||
height: 60,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
// Toggle view button
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
_mode == PreviewMode.mappedTarget
|
||||
? Icons.camera_alt
|
||||
: Icons.center_focus_strong,
|
||||
color: Colors.white,
|
||||
size: 24,
|
||||
),
|
||||
onPressed: () async {
|
||||
setState(() {
|
||||
_mode = _mode == PreviewMode.mappedTarget
|
||||
? PreviewMode.cameraWithDetections
|
||||
: PreviewMode.mappedTarget;
|
||||
});
|
||||
await _loadSelectedTarget();
|
||||
},
|
||||
tooltip: _mode == PreviewMode.mappedTarget
|
||||
? _t("Show Camera Detections")
|
||||
: _t("Show Mapped Target"),
|
||||
),
|
||||
// Split Save button
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: SizedBox(
|
||||
width: 120,
|
||||
height: 40,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
// Plus button (left, no background)
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: IconButton(
|
||||
icon: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
// Save to last folder
|
||||
Expanded(
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: _saveToLastFolder,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(8),
|
||||
bottomLeft: Radius.circular(8),
|
||||
),
|
||||
child: const Icon(Icons.save,
|
||||
color: Colors.black, size: 20),
|
||||
),
|
||||
),
|
||||
),
|
||||
// Divider
|
||||
Container(
|
||||
width: 1,
|
||||
color: Colors.grey[300],
|
||||
),
|
||||
// New folder
|
||||
Expanded(
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: _saveTargetDataWithDialog,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topRight: Radius.circular(8),
|
||||
bottomRight: Radius.circular(8),
|
||||
),
|
||||
child: Icon(Icons.add,
|
||||
color: Colors.black, size: 24),
|
||||
const Icon(Icons.folder, color: Colors.white, size: 24),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
padding: const EdgeInsets.all(2),
|
||||
child: const Icon(Icons.add, color: Colors.grey, size: 10),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
onPressed: _saveTargetDataWithDialog,
|
||||
),
|
||||
),
|
||||
),
|
||||
// Edit button
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
_isEditMode ? Icons.check : Icons.edit,
|
||||
color: _isEditMode ? Colors.red : Colors.white,
|
||||
size: 24,
|
||||
// Save button (center with white background)
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: SizedBox(
|
||||
width: 60,
|
||||
height: 40,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: _saveToLastFolder,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: const Icon(Icons.save,
|
||||
color: Colors.black, size: 20),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// Edit button (right)
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: IconButton(
|
||||
icon: Icon(
|
||||
_isEditMode ? Icons.check : Icons.edit,
|
||||
color: _isEditMode ? Colors.red : Colors.white,
|
||||
size: 24,
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isEditMode = !_isEditMode;
|
||||
_selectedBulletIndexInEdit = null;
|
||||
});
|
||||
},
|
||||
tooltip: _isEditMode ? _t("Done Editing") : _t("Edit Mode"),
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isEditMode = !_isEditMode;
|
||||
_selectedBulletIndexInEdit = null;
|
||||
});
|
||||
},
|
||||
tooltip: _isEditMode ? _t("Done Editing") : _t("Edit Mode"),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user