feat: boutons de rotation fine sur l'ecran de centrage + consigne de cadrage
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user