feat: boutons de rotation fine sur l'ecran de centrage + consigne de cadrage

This commit is contained in:
qlionbleusam
2026-08-04 16:06:05 +02:00
parent a4dc26fda8
commit 058bd5ff71
+72 -13
View File
@@ -27,6 +27,11 @@ class CropScreen extends StatefulWidget {
}
class _CropScreenState extends State<CropScreen> {
// Bornes et pas de la rotation, partagés par la jauge et les boutons / +.
static const double _minRotation = -15.0;
static const double _maxRotation = 15.0;
static const double _rotationStep = 0.1;
final ImageCropService _cropService = ImageCropService();
// États de transformation
@@ -113,7 +118,7 @@ class _CropScreenState extends State<CropScreen> {
const SizedBox(width: 8),
Flexible(
child: Text(
'Alignez et pivotez la cible sur la croix',
'Zoomer au maximum puis aligner votre cible',
style: TextStyle(color: Colors.white.withValues(alpha: 0.8), fontSize: 14, fontWeight: FontWeight.w500),
),
),
@@ -155,7 +160,8 @@ class _CropScreenState extends State<CropScreen> {
const SizedBox(height: 8),
// CROIX DIRECTIONNELLE — déplace la photo pixel par pixel.
// CROIX DIRECTIONNELLE — déplace la photo pixel par pixel,
// encadrée par les deux boutons de rotation fine.
_buildDirectionalPad(),
const SizedBox(height: 16),
@@ -180,12 +186,13 @@ class _CropScreenState extends State<CropScreen> {
),
Row(
children: [
const Icon(Icons.rotate_left, color: Colors.white38, size: 20),
// Les icônes de sens de rotation ont rejoint les boutons / +
// de la croix directionnelle.
Expanded(
child: Slider(
value: _rotation,
min: -15.0,
max: 15.0,
min: _minRotation,
max: _maxRotation,
divisions: 300,
label: '${_rotation.toStringAsFixed(1)}°',
activeColor: const Color(0xFF1A73E8),
@@ -197,7 +204,6 @@ class _CropScreenState extends State<CropScreen> {
},
),
),
const Icon(Icons.rotate_right, color: Colors.white38, size: 20),
const SizedBox(width: 4),
IconButton(
icon: const Icon(Icons.restart_alt, color: Colors.white54, size: 20),
@@ -363,12 +369,18 @@ 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.
// Les boutons « » et « + » de part et d'autre pivotent l'image de 0,1°.
Widget _buildDirectionalPad() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildCropSignLabel(''),
_buildRotationButton(
icon: Icons.rotate_left,
sign: '',
iconFirst: true,
tooltip: 'Pivoter vers la gauche',
onPressed: () => _rotateBy(-_rotationStep),
),
const SizedBox(width: 10),
Column(
mainAxisSize: MainAxisSize.min,
@@ -386,7 +398,13 @@ class _CropScreenState extends State<CropScreen> {
],
),
const SizedBox(width: 10),
_buildCropSignLabel('+'),
_buildRotationButton(
icon: Icons.rotate_right,
sign: '+',
iconFirst: false,
tooltip: 'Pivoter vers la droite',
onPressed: () => _rotateBy(_rotationStep),
),
],
);
}
@@ -404,10 +422,40 @@ class _CropScreenState extends State<CropScreen> {
);
}
Widget _buildCropSignLabel(String text) {
return Text(
text,
style: const TextStyle(color: Colors.white54, fontSize: 24, fontWeight: FontWeight.bold),
// Bouton de rotation : l'icône de sens est accolée au signe / +.
Widget _buildRotationButton({
required IconData icon,
required String sign,
required bool iconFirst,
required String tooltip,
required VoidCallback onPressed,
}) {
final content = [
Icon(icon, color: Colors.white70, size: 20),
const SizedBox(width: 4),
Text(
sign,
style: const TextStyle(color: Colors.white, fontSize: 22, fontWeight: FontWeight.bold),
),
];
return Tooltip(
message: tooltip,
child: Material(
color: Colors.black54,
borderRadius: BorderRadius.circular(6),
child: InkWell(
onTap: onPressed,
borderRadius: BorderRadius.circular(6),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
child: Row(
mainAxisSize: MainAxisSize.min,
children: iconFirst ? content : content.reversed.toList(),
),
),
),
),
);
}
@@ -417,6 +465,17 @@ class _CropScreenState extends State<CropScreen> {
});
}
/// Pivote l'image de [delta] degrés, dans les mêmes bornes que la jauge.
///
/// La valeur est arrondie au dixième pour rester calée sur les crans de la
/// jauge (300 divisions sur 30°) et sur l'affichage.
void _rotateBy(double delta) {
setState(() {
final value = (_rotation + delta).clamp(_minRotation, _maxRotation);
_rotation = (value * 10).roundToDouble() / 10;
});
}
void _onScaleStart(ScaleStartDetails details) {
_baseScale = _scale;
_startFocalPoint = details.focalPoint;