From 9689a089cc33bcb49c32f73da0a47595feb3c2f5 Mon Sep 17 00:00:00 2001 From: mark-cachy Date: Thu, 23 Apr 2026 19:13:05 +0200 Subject: [PATCH] df Co-authored-by: Copilot --- lib/core/widgets/qr_upload_dialog.dart | 93 +++++++++++++++++++ .../customers/ui/customer_detail_screen.dart | 62 ++++++++++++- 2 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 lib/core/widgets/qr_upload_dialog.dart diff --git a/lib/core/widgets/qr_upload_dialog.dart b/lib/core/widgets/qr_upload_dialog.dart new file mode 100644 index 0000000..32ea978 --- /dev/null +++ b/lib/core/widgets/qr_upload_dialog.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; +import 'package:qr_flutter/qr_flutter.dart'; + +class QrUploadDialog extends StatelessWidget { + final String deepLinkUrl; + final String title; + + const QrUploadDialog({ + super.key, + required this.deepLinkUrl, + required this.title, + }); + + @override + Widget build(BuildContext context) { + // Usiamo i colori del tema per renderlo coerente col tuo design + final theme = Theme.of(context); + + return AlertDialog( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), + backgroundColor: theme.colorScheme.surface, + title: Column( + children: [ + Icon( + Icons.qr_code_scanner, + size: 48, + color: theme.colorScheme.primary, + ), + const SizedBox(height: 16), + Text( + title, + textAlign: TextAlign.center, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ], + ), + content: SizedBox( + height: 400, + width: 350, + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, // Fondamentale per i dialog + children: [ + const Text( + "Inquadra questo codice con la fotocamera del tuo telefono per scattare e caricare i documenti direttamente qui.", + textAlign: TextAlign.center, + style: TextStyle(fontSize: 14, color: Colors.grey), + ), + const SizedBox(height: 24), + // IL CUORE DELLA MAGIA + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors + .white, // Lo sfondo bianco salva la vita sui temi scuri + borderRadius: BorderRadius.circular(16), + ), + child: QrImageView( + data: deepLinkUrl, + version: QrVersions.auto, + size: 200.0, + //Opzionale: puoi metterci il logo di FLUX in mezzo! + embeddedImage: const AssetImage('assets/images/logo.png'), + embeddedImageStyle: const QrEmbeddedImageStyle( + size: Size(40, 40), + ), + ), + ), + const SizedBox(height: 16), + Text( + "In attesa di file...", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: theme.colorScheme.primary, + ), + ), + const SizedBox(height: 8), + const LinearProgressIndicator(), // Per far capire che è "in ascolto" + ], + ), + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text("CHIUDI"), + ), + ], + actionsAlignment: MainAxisAlignment.center, + ); + } +} diff --git a/lib/features/customers/ui/customer_detail_screen.dart b/lib/features/customers/ui/customer_detail_screen.dart index bdea03f..d4c79d7 100644 --- a/lib/features/customers/ui/customer_detail_screen.dart +++ b/lib/features/customers/ui/customer_detail_screen.dart @@ -1,9 +1,11 @@ import 'package:flutter/material.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/theme/theme.dart'; import 'package:flux/core/widgets/image_viewer_widget.dart'; import 'package:flux/core/widgets/pdf_viewer_widget.dart'; +import 'package:flux/core/widgets/qr_upload_dialog.dart'; import 'package:flux/features/customers/blocs/customer_files_bloc.dart'; import 'package:flux/features/customers/models/customer_model.dart'; import 'package:flux/features/customers/models/customer_file_model.dart'; @@ -157,10 +159,57 @@ class _CustomerDetailScreenState extends State { color: context.accent, ), ), - ElevatedButton.icon( - onPressed: _pickAndUpload, - icon: const Icon(Icons.add_circle_outline), - label: const Text("CARICA FILE"), + // ZONA BOTTONI: Li mettiamo in una Row + Row( + children: [ + // Bottone classico: c'è sempre (carica da disco locale) + ElevatedButton.icon( + onPressed: _pickAndUpload, + icon: const Icon(Icons.add_circle_outline), + label: const Text("CARICA FILE"), + ), + const SizedBox(width: 12), + ElevatedButton.icon( + onPressed: state.selectedFiles.isEmpty + ? null + : () => _showDeleteConfirmationDialog( + context: context, + files: state.selectedFiles, + ), + icon: const Icon(Icons.delete_outline), + label: const Text("ELIMINA FILE"), + ), + + // Controlliamo se siamo su Desktop/Web per mostrare il QR + if (!context.read().state.isMobileDevice) ...[ + const SizedBox( + width: 12, + ), // Un po' di respiro tra i bottoni + ElevatedButton.icon( + onPressed: () { + showDialog( + context: context, + builder: (context) => QrUploadDialog( + // L'URL dinamico che il telefono digerirà! + deepLinkUrl: + 'fluxapp://customer/${widget.customer.id}?action=camera', + title: 'Scatta per ${widget.customer.nome}', + ), + ); + }, + icon: const Icon(Icons.qr_code), + label: const Text("GENERA QR"), + style: ElevatedButton.styleFrom( + // Lo facciamo di un colore leggermente diverso per distinguerlo + backgroundColor: context.accent.withValues( + alpha: 0.1, + ), + foregroundColor: context.accent, + elevation: 0, + ), + ), + ], + ], ), ], ), @@ -211,6 +260,11 @@ class _CustomerDetailScreenState extends State { ), ); } + + void _showDeleteConfirmationDialog({ + required BuildContext context, + required List files, + }) {} } class _FileCard extends StatelessWidget {