import 'package:flutter/material.dart'; import 'package:p_tits_pas/services/api/api_config.dart'; import 'package:p_tits_pas/widgets/common/auth_network_image.dart'; /// Cadre photo identité AM (35×45 mm) — même logique que [ValidationAmWizard]. class AdminAmPhotoFrame extends StatelessWidget { final String? photoUrl; static const double idPhotoAspectRatio = 35 / 45; const AdminAmPhotoFrame({super.key, this.photoUrl}); /// Largeur colonne photo pour remplir [height] (cadre inclus). static double columnWidthForHeight(double height) { const frame = 16.0; final innerH = (height - frame).clamp(0.0, double.infinity); return innerH * idPhotoAspectRatio + frame; } @override Widget build(BuildContext context) { final fullUrl = ApiConfig.absoluteMediaUrl(photoUrl); return LayoutBuilder( builder: (context, c) { const uniformFrame = 8.0; final maxPhotoW = (c.maxWidth - 2 * uniformFrame).clamp(0.0, double.infinity); final maxPhotoH = (c.maxHeight - 2 * uniformFrame).clamp(0.0, double.infinity); const ar = idPhotoAspectRatio; double ph = maxPhotoH; double pw = ph * ar; if (pw > maxPhotoW) { pw = maxPhotoW; ph = pw / ar; } // Cadre gris = taille photo + padding uniforme ; centré dans la colonne // (évite le vide blanc en bas quand le conteneur parent est plus haut). return Align( alignment: Alignment.topCenter, child: Container( decoration: BoxDecoration( color: Colors.grey.shade100, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.grey.shade300), ), clipBehavior: Clip.antiAlias, child: Padding( padding: const EdgeInsets.all(uniformFrame), child: ClipRRect( borderRadius: BorderRadius.circular(6), child: SizedBox( width: pw, height: ph, child: _photoContent(fullUrl, pw, ph), ), ), ), ), ); }, ); } Widget _photoContent(String fullUrl, double pw, double ph) { if (fullUrl.isEmpty) { return ColoredBox( color: Colors.grey.shade200, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.person_off_outlined, size: 36, color: Colors.grey.shade400), const SizedBox(height: 6), Text( 'Aucune photo', style: TextStyle(color: Colors.grey.shade600, fontSize: 11), ), ], ), ); } return AuthNetworkImage( url: fullUrl, width: pw, height: ph, fit: BoxFit.cover, alignment: Alignment.topCenter, loadingBuilder: (_, child, progress) { if (progress == null) return child; return ColoredBox( color: Colors.grey.shade200, child: Center( child: SizedBox( width: 22, height: 22, child: CircularProgressIndicator( strokeWidth: 2, value: progress.expectedTotalBytes != null ? progress.cumulativeBytesLoaded / (progress.expectedTotalBytes!) : null, ), ), ), ); }, errorBuilder: (_, __, ___) => ColoredBox( color: Colors.grey.shade200, child: Icon(Icons.broken_image_outlined, size: 36, color: Colors.grey.shade400), ), ); } }