From 86abb645ce01cfa81aedaa18b29e3423013ca529 Mon Sep 17 00:00:00 2001 From: qlionbleusam Date: Wed, 5 Aug 2026 03:02:40 +0200 Subject: [PATCH] feat: popup de fin de session aux couleurs de l'appli avec export IA integre --- assets/icons/cloud_save.png | Bin 0 -> 29242 bytes lib/features/analysis/analysis_screen.dart | 399 +++++++++++++-------- pubspec.yaml | 6 +- 3 files changed, 256 insertions(+), 149 deletions(-) create mode 100644 assets/icons/cloud_save.png diff --git a/assets/icons/cloud_save.png b/assets/icons/cloud_save.png new file mode 100644 index 0000000000000000000000000000000000000000..1bd25b89016844a5c5bc82efd1fdc7cd17036d4c GIT binary patch literal 29242 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 ZI=BZ%o*{i)37+=|X+{vY8lJKq2R literal 0 HcmV?d00001 diff --git a/lib/features/analysis/analysis_screen.dart b/lib/features/analysis/analysis_screen.dart index a3aa4be3..a4c86543 100644 --- a/lib/features/analysis/analysis_screen.dart +++ b/lib/features/analysis/analysis_screen.dart @@ -701,169 +701,278 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> { ); } - void _showSaveSessionDialog(BuildContext context, AnalysisProvider provider) { + Future _showSaveSessionDialog( + BuildContext context, + AnalysisProvider provider, + ) async { + // L'option « Participer à l'entraînement IA » (Paramètres) est lue AVANT + // d'ouvrir la popup : elle décide de la présence du bouton d'export. + final canExport = + await WalletIdentityService().isUploadEnabled() && + provider.state == AnalysisState.success; + + if (!context.mounted) return; + showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Session Terminee'), + // Protège des petits écrans / grandes polices : la popup défile au + // lieu de déborder. + scrollable: true, + // En-tête bleu pleine largeur : le titre occupe toute la bande, d'où + // les paddings mis à zéro. + titlePadding: EdgeInsets.zero, + contentPadding: const EdgeInsets.fromLTRB(20, 16, 20, 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + clipBehavior: Clip.antiAlias, + title: Container( + width: double.infinity, + color: AppTheme.primaryColor, + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), + child: const Row( + children: [ + Icon(Icons.flag, color: Colors.white), + SizedBox(width: 10), + Text( + 'Session terminée', + style: TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + // Les boutons sont dans le contenu (et non dans `actions`) pour être + // tous à la même largeur, alignés les uns sous les autres. content: Column( mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Text('Nombre de tirs: ${provider.shotCount}'), - Text('Score total: ${provider.totalScore}'), + _buildDialogRecap(context, provider), const SizedBox(height: 16), const Text('Voulez-vous enregistrer cette session ?'), - // Export vers le backend IA : proposé ici (et non plus dans - // l'AppBar). Visible seulement si l'option est activée dans les - // Paramètres ET si l'analyse a réussi. - FutureBuilder( - future: WalletIdentityService().isUploadEnabled(), - builder: (context, snapshot) { - final isEnabled = snapshot.data ?? false; - if (!isEnabled || - provider.state != AnalysisState.success) { - return const SizedBox.shrink(); - } - return Padding( - padding: const EdgeInsets.only(top: 12), - child: OutlinedButton.icon( - icon: const Icon(Icons.cloud_upload), - label: const Text('Exporter pour IA'), - onPressed: () async { - if (provider.state != AnalysisState.success) return; + const SizedBox(height: 16), + _buildDialogButton( + icon: const Icon(Icons.add_a_photo, color: Colors.white), + label: 'AJOUTER UNE CIBLE', + color: AppTheme.secondaryColor, + onPressed: () => _saveAndAddTarget(context, provider), + ), + const SizedBox(height: 8), + _buildDialogButton( + icon: const Icon(Icons.save, color: Colors.white), + label: 'TERMINER TOUT', + color: AppTheme.primaryColor, + onPressed: () => _finishSession(context, provider), + ), + // Bouton d'export : uniquement si l'entraînement IA est autorisé. + if (canExport) ...[ + const SizedBox(height: 8), + _buildDialogButton( + icon: Image.asset( + 'assets/icons/cloud_save.png', + width: 24, + height: 24, + // L'icône est un trait noir : on la recolore en blanc pour + // qu'elle ressorte sur le bouton. + color: Colors.white, + ), + label: 'TERMINER TOUT ET EXPORTER', + color: AppTheme.warningColor, + onPressed: () => + _finishSession(context, provider, export: true), + ), + ], + const SizedBox(height: 4), + TextButton( + onPressed: () { + Navigator.pop(context); + // CORRECTION : on repart aussi de l'image SOURCE non rognée ici. + final path = _backCropImagePath(provider); + final type = provider.targetType!; - // On capture messenger et session AVANT l'await pour - // éviter tout usage de context après un gap async. - final messenger = ScaffoldMessenger.of(context); - final sp = context.read(); - - messenger.showSnackBar( - const SnackBar( - content: Text('Exportation en cours...'), - ), - ); - - final success = await provider.exportToAiBackend( - sessionId: sp.activeSessionId, - distance: sp.distance, - weapon: sp.currentWeapon, - ); - - messenger.hideCurrentSnackBar(); - messenger.showSnackBar( - SnackBar( - content: Text( - success - ? 'Export réussi vers le backend IA !' - : (provider.errorMessage ?? - 'Erreur d\'export'), - ), - backgroundColor: success - ? AppTheme.successColor - : AppTheme.errorColor, - ), - ); - }, + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => CropScreen( + imagePath: path, + targetType: type, + initialScale: widget.cropScale, + initialOffset: widget.cropOffset, + ), ), ); }, + child: const Text('ANNULER'), ), ], ), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - // CORRECTION : on repart aussi de l'image SOURCE non rognée ici. - final path = _backCropImagePath(provider); - final type = provider.targetType!; + ), + ); + } - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => CropScreen( - imagePath: path, - targetType: type, - initialScale: widget.cropScale, - initialOffset: widget.cropOffset, - ), - ), - ); - }, - child: const Text('ANNULER'), - ), - ElevatedButton( - onPressed: () async { - try { - final sessionProvider = context.read(); - final analysis = await provider.saveSession( - sessionId: sessionProvider.activeSessionId, - weaponName: sessionProvider.currentWeapon, - weaponId: sessionProvider.currentWeaponId, - distance: sessionProvider.distance, - date: sessionProvider.sessionDate, - ); - - sessionProvider.addAnalysis(analysis); - - if (context.mounted) { - Navigator.pop(context); - Navigator.pushAndRemoveUntil( - context, - MaterialPageRoute( - builder: (context) => const CaptureScreen(), - ), - (route) => route.isFirst, - ); - } - } catch (e) { - if (context.mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Erreur: $e'), - backgroundColor: AppTheme.errorColor, - ), - ); - } - } - }, - child: const Text('AJOUTER UNE CIBLE'), - ), - ElevatedButton( - onPressed: () async { - try { - final sessionProvider = context.read(); - await provider.saveSession( - sessionId: sessionProvider.activeSessionId, - weaponName: sessionProvider.currentWeapon, - weaponId: sessionProvider.currentWeaponId, - distance: sessionProvider.distance, - date: sessionProvider.sessionDate, - ); - - if (context.mounted) { - sessionProvider.endSession(); - Navigator.pop(context); - Navigator.of(context).popUntil((route) => route.isFirst); - // Fin de session : on atterrit sur les statistiques. - openMainTab(mainTabStats); - } - } catch (e) { - if (context.mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Erreur: $e'), - backgroundColor: AppTheme.errorColor, - ), - ); - } - } - }, - child: const Text('TERMINER TOUT'), - ), + /// Rappel chiffré (tirs / score) en tête de la popup de fin de session. + Widget _buildDialogRecap(BuildContext context, AnalysisProvider provider) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + decoration: BoxDecoration( + color: AppTheme.primaryColor.withValues(alpha: 0.10), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + _buildRecapValue(context, '${provider.shotCount}', 'Tirs'), + _buildRecapValue(context, '${provider.totalScore}', 'Score total'), ], ), ); } + + Widget _buildRecapValue(BuildContext context, String value, String label) { + return Column( + children: [ + Text( + value, + style: Theme.of(context).textTheme.headlineSmall?.copyWith( + fontWeight: FontWeight.bold, + color: AppTheme.primaryColor, + ), + ), + Text(label, style: Theme.of(context).textTheme.bodySmall), + ], + ); + } + + /// Bouton pleine largeur de la popup, aux couleurs du thème. + Widget _buildDialogButton({ + required Widget icon, + required String label, + required Color color, + required VoidCallback onPressed, + }) { + return ElevatedButton.icon( + icon: icon, + label: Text(label, style: const TextStyle(fontWeight: FontWeight.bold)), + style: ElevatedButton.styleFrom( + backgroundColor: color, + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 14), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + onPressed: onPressed, + ); + } + + /// Enregistre la cible courante et enchaîne sur une nouvelle capture. + Future _saveAndAddTarget( + BuildContext context, + AnalysisProvider provider, + ) async { + try { + final sessionProvider = context.read(); + final analysis = await provider.saveSession( + sessionId: sessionProvider.activeSessionId, + weaponName: sessionProvider.currentWeapon, + weaponId: sessionProvider.currentWeaponId, + distance: sessionProvider.distance, + date: sessionProvider.sessionDate, + ); + + sessionProvider.addAnalysis(analysis); + + if (context.mounted) { + Navigator.pop(context); + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute(builder: (context) => const CaptureScreen()), + (route) => route.isFirst, + ); + } + } catch (e) { + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Erreur: $e'), + backgroundColor: AppTheme.errorColor, + ), + ); + } + } + } + + /// Clôture la session et revient sur l'onglet Statistiques. + /// + /// Avec [export], la cible est en plus envoyée au backend d'entraînement IA. + /// L'enregistrement local reste prioritaire : un échec d'export n'empêche + /// jamais la session d'être sauvegardée. + Future _finishSession( + BuildContext context, + AnalysisProvider provider, { + bool export = false, + }) async { + // Messenger et session capturés AVANT les await : le contexte de la popup + // ne sera plus valide ensuite. + final messenger = ScaffoldMessenger.of(context); + final sessionProvider = context.read(); + + try { + await provider.saveSession( + sessionId: sessionProvider.activeSessionId, + weaponName: sessionProvider.currentWeapon, + weaponId: sessionProvider.currentWeaponId, + distance: sessionProvider.distance, + date: sessionProvider.sessionDate, + ); + + bool? exportSucceeded; + if (export) { + messenger.showSnackBar( + const SnackBar(content: Text('Exportation en cours...')), + ); + exportSucceeded = await provider.exportToAiBackend( + sessionId: sessionProvider.activeSessionId, + distance: sessionProvider.distance, + weapon: sessionProvider.currentWeapon, + ); + messenger.hideCurrentSnackBar(); + } + + if (context.mounted) { + sessionProvider.endSession(); + Navigator.pop(context); + Navigator.of(context).popUntil((route) => route.isFirst); + // Fin de session : on atterrit sur les statistiques. + openMainTab(mainTabStats); + } + + if (exportSucceeded != null) { + messenger.showSnackBar( + SnackBar( + content: Text( + exportSucceeded + ? 'Export réussi vers le backend IA !' + : (provider.errorMessage ?? 'Erreur d\'export'), + ), + backgroundColor: exportSucceeded + ? AppTheme.successColor + : AppTheme.errorColor, + ), + ); + } + } catch (e) { + messenger.showSnackBar( + SnackBar( + content: Text('Erreur: $e'), + backgroundColor: AppTheme.errorColor, + ), + ); + } + } } \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index a4d0b03a..b86a7964 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -93,10 +93,8 @@ flutter: # the material Icons class. uses-material-design: true - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg + assets: + - assets/icons/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/to/resolution-aware-images