boh
This commit is contained in:
@@ -1,14 +1,20 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flux/core/blocs/session/session_cubit.dart';
|
||||
import 'package:flux/core/widgets/shared_forms/customer_section.dart';
|
||||
import 'package:flux/core/widgets/shared_forms/model_section.dart';
|
||||
import 'package:flux/core/widgets/shared_forms/shared_files_section.dart';
|
||||
import 'package:flux/features/attachments/blocs/attachments_bloc.dart';
|
||||
import 'package:flux/features/company/models/company_model.dart';
|
||||
import 'package:flux/features/tickets/blocs/ticket_form_cubit.dart';
|
||||
import 'package:flux/features/tickets/blocs/ticket_form_state.dart';
|
||||
import 'package:flux/features/tickets/models/ticket_model.dart';
|
||||
import 'package:flux/core/widgets/shared_forms/staff_section.dart';
|
||||
import 'package:flux/features/tickets/models/ticket_status_extension.dart';
|
||||
import 'package:flux/features/tickets/utils/ticket_pdf_service.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:pdf/pdf.dart';
|
||||
import 'package:printing/printing.dart';
|
||||
|
||||
class TicketFormScreen extends StatefulWidget {
|
||||
final TicketModel? existingTicket;
|
||||
@@ -93,10 +99,10 @@ class _TicketFormScreenState extends State<TicketFormScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
void _saveTicket({required bool keepAdding}) {
|
||||
void _saveTicket() {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
_flushControllersToCubit();
|
||||
context.read<TicketFormCubit>().saveTicket(keepAdding: keepAdding);
|
||||
context.read<TicketFormCubit>().saveTicket();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +127,110 @@ class _TicketFormScreenState extends State<TicketFormScreen> {
|
||||
return newId;
|
||||
}
|
||||
|
||||
void _showSuccessActions(
|
||||
BuildContext context,
|
||||
TicketModel ticket,
|
||||
CompanyModel company,
|
||||
) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isDismissible: false, // Costringiamo l'operatore a una scelta conscia
|
||||
isScrollControlled: true,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
|
||||
),
|
||||
builder: (context) => SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: 40,
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const Icon(Icons.check_circle, color: Colors.green, size: 64),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
"Ticket Salvato!",
|
||||
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"Rif: ${ticket.referenceId}",
|
||||
style: TextStyle(color: Colors.grey[600], fontSize: 18),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
|
||||
// Griglia delle Azioni
|
||||
GridView.count(
|
||||
crossAxisCount: 2,
|
||||
shrinkWrap: true,
|
||||
mainAxisSpacing: 16,
|
||||
crossAxisSpacing: 16,
|
||||
childAspectRatio: 1.5,
|
||||
children: [
|
||||
_ActionButton(
|
||||
icon: Icons.print,
|
||||
label: "Ricevuta A4",
|
||||
onTap: () async {
|
||||
// 1. Costruiamo la struttura (velocissimo)
|
||||
final doc = await TicketPdfService()
|
||||
.generateTicketReceipt(ticket, company);
|
||||
|
||||
// 2. Lanciamo layoutPdf esattamente come facevi tu!
|
||||
await Printing.layoutPdf(
|
||||
name: 'Ricevuta_${ticket.referenceId}.pdf',
|
||||
onLayout: (PdfPageFormat format) async =>
|
||||
doc.save(), // La magia è qui!
|
||||
);
|
||||
},
|
||||
),
|
||||
if (company.labelFormat != LabelFormat.none)
|
||||
_ActionButton(
|
||||
icon: Icons.label,
|
||||
label: "Etichetta",
|
||||
onTap: () async {
|
||||
final doc = await TicketPdfService().generateLabelPdf(
|
||||
ticket,
|
||||
company,
|
||||
);
|
||||
await Printing.layoutPdf(
|
||||
name: 'Etichetta_${ticket.referenceId}.pdf',
|
||||
onLayout: (PdfPageFormat format) async => doc.save(),
|
||||
);
|
||||
},
|
||||
),
|
||||
_ActionButton(
|
||||
icon: Icons.email,
|
||||
label: "Invia Email",
|
||||
onTap: ticket.customerEmail != null ? () {} : null,
|
||||
),
|
||||
_ActionButton(
|
||||
icon: Icons.close,
|
||||
label: "Chiudi",
|
||||
color: Colors.blue[900],
|
||||
textColor: Colors.white,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
@@ -133,22 +243,13 @@ class _TicketFormScreenState extends State<TicketFormScreen> {
|
||||
}
|
||||
|
||||
if (state.status == TicketFormStatus.success) {
|
||||
Navigator.of(context).pop();
|
||||
} else if (state.status == TicketFormStatus.successAndAddAnother) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Scheda salvata! Inserisci la prossima.'),
|
||||
),
|
||||
_showSuccessActions(
|
||||
context,
|
||||
state.ticket,
|
||||
GetIt.I.get<SessionCubit>().state.company!,
|
||||
);
|
||||
_altPhoneCtrl.clear();
|
||||
_serialCtrl.clear();
|
||||
_requestCtrl.clear();
|
||||
_accessoriesCtrl.clear();
|
||||
_publicNotesCtrl.clear();
|
||||
_internalNotesCtrl.clear();
|
||||
_priceCtrl.clear();
|
||||
_costCtrl.clear();
|
||||
_isInitialized = false;
|
||||
} else if (state.status == TicketFormStatus.pop) {
|
||||
Navigator.of(context).pop();
|
||||
} else if (state.status == TicketFormStatus.failure) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
@@ -229,23 +330,23 @@ class _TicketFormScreenState extends State<TicketFormScreen> {
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: OutlinedButton(
|
||||
onPressed: state.status == TicketFormStatus.saving
|
||||
child: ElevatedButton(
|
||||
onPressed: state.ticket.id == null
|
||||
? null
|
||||
: () => _saveTicket(keepAdding: true),
|
||||
child: const Text(
|
||||
'Salva e Aggiungi Altro',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
: () => _showSuccessActions(
|
||||
context,
|
||||
ticket,
|
||||
GetIt.I.get<SessionCubit>().state.company!,
|
||||
),
|
||||
child: const Text('Ricevuta'),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: ElevatedButton(
|
||||
onPressed: state.status == TicketFormStatus.saving
|
||||
? null
|
||||
: () => _saveTicket(keepAdding: false),
|
||||
: () => _saveTicket(),
|
||||
child: state.status == TicketFormStatus.saving
|
||||
? const SizedBox(
|
||||
width: 20,
|
||||
@@ -378,7 +479,7 @@ class _TicketFormScreenState extends State<TicketFormScreen> {
|
||||
modelName: ticket.targetModelName,
|
||||
onModelSelected: (id, name) => context
|
||||
.read<TicketFormCubit>()
|
||||
.updateModel(modelId: id, modelName: name),
|
||||
.updateTargetModel(modelId: id, modelName: name),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
@@ -597,3 +698,55 @@ class _TicketFormScreenState extends State<TicketFormScreen> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Widget helper per i bottoni dell'Action Hub
|
||||
class _ActionButton extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final String label;
|
||||
final VoidCallback? onTap;
|
||||
final Color? color;
|
||||
final Color? textColor;
|
||||
|
||||
const _ActionButton({
|
||||
required this.icon,
|
||||
required this.label,
|
||||
this.onTap,
|
||||
this.color,
|
||||
this.textColor,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: onTap == null ? Colors.grey[100] : (color ?? Colors.grey[200]),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
color: onTap == null
|
||||
? Colors.grey
|
||||
: (textColor ?? Colors.blue[900]),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: onTap == null
|
||||
? Colors.grey
|
||||
: (textColor ?? Colors.blue[900]),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user