finished bullet adjustment
This commit is contained in:
+181
-153
@@ -47,7 +47,7 @@ class _PreviewScreenState extends State<PreviewScreen> {
|
||||
final List<int> _manualBulletScores = [];
|
||||
|
||||
Color _bulletColor = Colors.blue; // default fallback
|
||||
double get _bulletOpacity => 0.7;
|
||||
double get _bulletOpacity => 0.8;
|
||||
|
||||
bool _isEditMode = false;
|
||||
int? _selectedBulletIndexInEdit;
|
||||
@@ -204,35 +204,23 @@ Color _getColorFromName(String colorName) {
|
||||
_cachedTargetImage = Uint8List.fromList(img.encodePng(_targetImageDecoded!));
|
||||
}
|
||||
|
||||
// 10. Update UI
|
||||
final missing = widget.bulletCount - mappedBullets.length;
|
||||
|
||||
// 10. Update state with mapped bullets
|
||||
setState(() {
|
||||
_mappedBullets = mappedBullets;
|
||||
_isLoading = false;
|
||||
});
|
||||
|
||||
if (missing > 0) {
|
||||
final result = await _showMismatchOptionsDialog(mappedBullets.length);
|
||||
|
||||
if (result == 'retry') {
|
||||
Navigator.pop(context); // Go back to camera screen
|
||||
} else if (result == 'manual') {
|
||||
_manualScoreEntry(); // Reuse your original manual dialog
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} catch (e, stack) {
|
||||
debugPrint("❌ Error during detection mapping: $e");
|
||||
debugPrint(stack.toString());
|
||||
setState(() => _isLoading = false);
|
||||
setState(() {
|
||||
_mappedBullets = [];
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Future<String?> _showMismatchOptionsDialog(int detectedCount) async {
|
||||
return showDialog<String>(
|
||||
context: context,
|
||||
@@ -780,6 +768,24 @@ void _moveBullet(Offset offsetDelta) {
|
||||
return autoScore + manualScore;
|
||||
}
|
||||
|
||||
Color _getBulletButtonColor(int index) {
|
||||
final isSelected = _isEditMode
|
||||
? index == _selectedBulletIndexInEdit
|
||||
: index == _highlightedBulletIndex;
|
||||
|
||||
if (isSelected) return Colors.red;
|
||||
|
||||
final manualStart = _mappedBullets.length - _manualBulletScores.length;
|
||||
final isManual = index >= manualStart;
|
||||
|
||||
if (isManual) return Colors.redAccent; // ⬅️ Light red for manual bullets
|
||||
|
||||
if (_isEditMode) return _editColor;
|
||||
|
||||
return _bulletColor;
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@@ -822,6 +828,51 @@ Widget build(BuildContext context) {
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: Stack(
|
||||
children: [
|
||||
if (_mappedBullets.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 8),
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () async {
|
||||
if (!_isEditMode && _mappedBullets.length < widget.bulletCount) {
|
||||
final result = await _showMismatchOptionsDialog(_mappedBullets.length);
|
||||
|
||||
if (result == 'retry') {
|
||||
Navigator.pop(context);
|
||||
return;
|
||||
} else if (result == 'manual') {
|
||||
_manualScoreEntry();
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_isEditMode = !_isEditMode;
|
||||
_selectedBulletIndexInEdit = null;
|
||||
});
|
||||
},
|
||||
icon: Icon(
|
||||
_isEditMode ? Icons.check : Icons.edit,
|
||||
color: Colors.white,
|
||||
size: 20,
|
||||
),
|
||||
label: Text(
|
||||
_isEditMode ? "Done Editing" : "Edit Bullets",
|
||||
style: const TextStyle(color: Colors.white, fontSize: 16),
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: _activeColor,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Expanded(
|
||||
@@ -918,6 +969,14 @@ Widget build(BuildContext context) {
|
||||
|
||||
final isHighlighted = index == _highlightedBulletIndex;
|
||||
final isSelectedForEdit = index == _selectedBulletIndexInEdit;
|
||||
final manualStart = _mappedBullets.length - _manualBulletScores.length;
|
||||
final isManual = index >= manualStart;
|
||||
|
||||
final Color bulletFillColor = isSelectedForEdit || (!_isEditMode && isHighlighted)
|
||||
? Colors.red.withOpacity(_bulletOpacity)
|
||||
: isManual
|
||||
? Colors.red.withOpacity(_bulletOpacity)
|
||||
: _activeColorWithOpacity;
|
||||
|
||||
return Positioned(
|
||||
left: dx - bulletSize / 2,
|
||||
@@ -926,17 +985,15 @@ Widget build(BuildContext context) {
|
||||
width: bulletSize,
|
||||
height: bulletSize,
|
||||
decoration: BoxDecoration(
|
||||
color: _activeColorWithOpacity,
|
||||
color: bulletFillColor,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: isSelectedForEdit
|
||||
? _bulletColor
|
||||
: (!_isEditMode && isHighlighted)
|
||||
? Colors.red
|
||||
: Colors.black,
|
||||
width: (isSelectedForEdit || (!_isEditMode && isHighlighted)) ? 3 : 1,
|
||||
color: (isSelectedForEdit || (!_isEditMode && isHighlighted))
|
||||
? Colors.red
|
||||
: Colors.black,
|
||||
width: (isSelectedForEdit || (!_isEditMode && isHighlighted)) ? 3 : 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
@@ -947,147 +1004,118 @@ Widget build(BuildContext context) {
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
if (_mappedBullets.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
child: Row(
|
||||
children: List.generate(
|
||||
_mappedBullets.length,
|
||||
(index) {
|
||||
final bullet = _mappedBullets[index];
|
||||
final isManual = index >= (_mappedBullets.length - _manualBulletScores.length);
|
||||
final score = isManual
|
||||
? _manualBulletScores[index - (_mappedBullets.length - _manualBulletScores.length)]
|
||||
: _scoreForBullet(
|
||||
bullet,
|
||||
_targetImageCenterForScoring ?? fixedRingTargetCenter,
|
||||
);
|
||||
final isSelected = index == (_isEditMode ? _selectedBulletIndexInEdit : _highlightedBulletIndex);
|
||||
Column(
|
||||
children: [
|
||||
// Score buttons
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
child: Row(
|
||||
children: List.generate(
|
||||
_mappedBullets.length,
|
||||
(index) {
|
||||
final bullet = _mappedBullets[index];
|
||||
final isManual = index >= (_mappedBullets.length - _manualBulletScores.length);
|
||||
final score = isManual
|
||||
? _manualBulletScores[index - (_mappedBullets.length - _manualBulletScores.length)]
|
||||
: _scoreForBullet(
|
||||
bullet,
|
||||
_targetImageCenterForScoring ?? fixedRingTargetCenter,
|
||||
);
|
||||
|
||||
return Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
if (_isEditMode) {
|
||||
setState(() => _selectedBulletIndexInEdit = index);
|
||||
}
|
||||
},
|
||||
onTapDown: (_) {
|
||||
if (!_isEditMode) {
|
||||
setState(() => _highlightedBulletIndex = index);
|
||||
}
|
||||
},
|
||||
onTapUp: (_) {
|
||||
if (!_isEditMode) {
|
||||
setState(() => _highlightedBulletIndex = null);
|
||||
}
|
||||
},
|
||||
onTapCancel: () {
|
||||
if (!_isEditMode) {
|
||||
setState(() => _highlightedBulletIndex = null);
|
||||
}
|
||||
},
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
height: 100,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Colors.black26,
|
||||
offset: Offset(0, 2),
|
||||
blurRadius: 6,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
height: 30,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(16),
|
||||
topRight: Radius.circular(16),
|
||||
return Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
if (_isEditMode) {
|
||||
setState(() => _selectedBulletIndexInEdit = index);
|
||||
}
|
||||
},
|
||||
onTapDown: (_) {
|
||||
if (!_isEditMode) {
|
||||
setState(() => _highlightedBulletIndex = index);
|
||||
}
|
||||
},
|
||||
onTapUp: (_) {
|
||||
if (!_isEditMode) {
|
||||
setState(() => _highlightedBulletIndex = null);
|
||||
}
|
||||
},
|
||||
onTapCancel: () {
|
||||
if (!_isEditMode) {
|
||||
setState(() => _highlightedBulletIndex = null);
|
||||
}
|
||||
},
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
height: 100,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Colors.black26,
|
||||
offset: Offset(0, 2),
|
||||
blurRadius: 6,
|
||||
),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'${index + 1}',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? _editColor
|
||||
: _activeColor,
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(16),
|
||||
bottomRight: Radius.circular(16),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
height: 30,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(16),
|
||||
topRight: Radius.circular(16),
|
||||
),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'${index + 1}',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'$score',
|
||||
style: const TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: _getBulletButtonColor(index),
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(16),
|
||||
bottomRight: Radius.circular(16),
|
||||
),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'$score',
|
||||
style: const TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
),
|
||||
|
||||
Positioned(
|
||||
top: 12,
|
||||
right: 12,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isEditMode = !_isEditMode;
|
||||
_selectedBulletIndexInEdit = null;
|
||||
});
|
||||
},
|
||||
icon: Icon(
|
||||
_isEditMode ? Icons.check : Icons.edit,
|
||||
color: Colors.white,
|
||||
size: 20,
|
||||
),
|
||||
label: Text(
|
||||
_isEditMode ? "Done" : "Edit Bullets",
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: _activeColor, // ← dynamic color depending on mode
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
elevation: 4,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
_buildEditController(),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user