feat: accessoires en armurerie, comparateur de sessions stats, croix de centrage pixel par pixel

This commit is contained in:
qguillaume
2026-06-19 14:40:19 +02:00
parent 8165d3bab3
commit 9fa3a6f46d
4 changed files with 384 additions and 51 deletions

View File

@@ -101,6 +101,33 @@ class _CropScreenState extends State<CropScreen> {
? const Center(child: CircularProgressIndicator(color: Color(0xFF1A73E8)))
: Column(
children: [
// TEXTE D'AIDE — placé en haut, sous le titre, au-dessus de l'image.
Padding(
padding: const EdgeInsets.fromLTRB(20, 12, 20, 4),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.center_focus_strong, color: Color(0xFF00FF00), size: 20),
const SizedBox(width: 8),
Flexible(
child: Text(
'Alignez et pivotez la cible sur la croix',
style: TextStyle(color: Colors.white.withOpacity(0.8), fontSize: 14, fontWeight: FontWeight.w500),
),
),
],
),
const SizedBox(height: 4),
Text(
'Glissez à un doigt pour déplacer, pincez pour zoomer',
style: TextStyle(color: Colors.white.withOpacity(0.5), fontSize: 12),
),
],
),
),
// Zone interactive de crop, CARRÉE. La photo la remplit entièrement
// (BoxFit.cover) → aucun bord noir dans la zone. Le débord hors cadre
// est récupérable en déplaçant/zoomant. La sortie d'analyse reste
@@ -126,30 +153,10 @@ class _CropScreenState extends State<CropScreen> {
),
),
// TEXTE D'AIDE AJUSTÉ
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.center_focus_strong, color: Color(0xFF00FF00), size: 20),
const SizedBox(width: 8),
Text(
'Alignez et pivotez la cible sur la croix',
style: TextStyle(color: Colors.white.withOpacity(0.8), fontSize: 14, fontWeight: FontWeight.w500),
),
],
),
const SizedBox(height: 4),
Text(
'Glissez à un doigt pour déplacer, pincez pour zoomer',
style: TextStyle(color: Colors.white.withOpacity(0.5), fontSize: 12),
),
],
),
),
const SizedBox(height: 8),
// CROIX DIRECTIONNELLE — déplace la photo pixel par pixel.
_buildDirectionalPad(),
const SizedBox(height: 16),
@@ -355,6 +362,61 @@ class _CropScreenState extends State<CropScreen> {
}
}
// Croix directionnelle compacte pour déplacer la photo pixel par pixel.
// Les symboles « » et « + » de part et d'autre sont purement décoratifs.
Widget _buildDirectionalPad() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildCropSignLabel(''),
const SizedBox(width: 10),
Column(
mainAxisSize: MainAxisSize.min,
children: [
_buildCropDirButton(Icons.keyboard_arrow_up, () => _nudge(0, -1)),
Row(
mainAxisSize: MainAxisSize.min,
children: [
_buildCropDirButton(Icons.keyboard_arrow_left, () => _nudge(-1, 0)),
const SizedBox(width: 28),
_buildCropDirButton(Icons.keyboard_arrow_right, () => _nudge(1, 0)),
],
),
_buildCropDirButton(Icons.keyboard_arrow_down, () => _nudge(0, 1)),
],
),
const SizedBox(width: 10),
_buildCropSignLabel('+'),
],
);
}
Widget _buildCropDirButton(IconData icon, VoidCallback onPressed) {
return Container(
decoration: BoxDecoration(color: Colors.black54, borderRadius: BorderRadius.circular(6)),
margin: const EdgeInsets.all(2),
child: IconButton(
icon: Icon(icon, color: Colors.white, size: 22),
onPressed: onPressed,
padding: EdgeInsets.zero,
constraints: const BoxConstraints(minWidth: 32, minHeight: 32),
),
);
}
Widget _buildCropSignLabel(String text) {
return Text(
text,
style: const TextStyle(color: Colors.white54, fontSize: 24, fontWeight: FontWeight.bold),
);
}
void _nudge(double dx, double dy) {
setState(() {
_offset = _offset + Offset(dx, dy);
});
}
void _onScaleStart(ScaleStartDetails details) {
_baseScale = _scale;
_startFocalPoint = details.focalPoint;