import 'dart:typed_data'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:hl_lieferservice/feature/delivery/detail/bloc/note_bloc.dart'; import 'package:hl_lieferservice/feature/delivery/detail/bloc/note_event.dart'; import 'package:hl_lieferservice/feature/delivery/detail/bloc/note_state.dart'; import 'package:hl_lieferservice/model/customer.dart'; import 'package:flutter/material.dart'; import 'package:hl_lieferservice/model/delivery.dart'; import 'package:intl/intl.dart'; import 'package:signature/signature.dart'; class SignatureView extends StatefulWidget { const SignatureView({ super.key, required this.onSigned, required this.delivery, }); final Delivery delivery; /// Callback that is called when the user has signed. /// The parameter stores the path to the image file of the signature. final void Function( Uint8List customerSignaturePng, Uint8List driverSignaturePng, ) onSigned; @override State createState() => _SignatureViewState(); } class _SignatureViewState extends State { final SignatureController _customerController = SignatureController( penStrokeWidth: 5, penColor: Colors.black, exportBackgroundColor: Colors.white, ); final SignatureController _driverController = SignatureController( penStrokeWidth: 5, penColor: Colors.black, exportBackgroundColor: Colors.white, ); bool _isDriverSigning = false; bool _customerAccepted = false; bool _noteAccepted = false; bool _notesEmpty = true; @override void initState() { super.initState(); // only load notes if they are not already loaded final noteState = context.read().state; if (noteState is NoteInitial) { context.read().add(LoadNote(delivery: widget.delivery)); } } @override void dispose() { _customerController.dispose(); super.dispose(); } Widget _signatureField() { return Signature( controller: _isDriverSigning ? _driverController : _customerController, backgroundColor: Colors.white, ); } Widget _notes() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(bottom: 15), child: Text( "Notizen", style: Theme.of(context).textTheme.headlineSmall, ), ), BlocConsumer( listener: (context, state) { final current = state; if (current is NoteLoaded) { setState(() { _notesEmpty = current.notes.isEmpty; }); } }, builder: (context, state) { final current = state; if (current is NoteLoaded) { if (current.notes.isEmpty) { return const SizedBox( width: double.infinity, child: Center(child: Text("Keine Notizen vorhanden")), ); } return ListView.separated( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemBuilder: (context, index) { return ListTile( leading: const Icon(Icons.event_note_outlined), title: Text(current.notes[index].content), contentPadding: EdgeInsets.all(20), tileColor: Theme.of(context).colorScheme.onSecondary, ); }, separatorBuilder: (context, index) => const Divider(height: 0), itemCount: current.notes.length, ); } return SizedBox( width: double.infinity, child: Center(child: CircularProgressIndicator()), ); }, ), const Padding(padding: EdgeInsets.only(top: 25), child: Divider()), ], ); } Widget _customerCheckboxes() { return !_isDriverSigning ? Column( children: [ Padding( padding: const EdgeInsets.only(top: 25, bottom: 0), child: _notes(), ), Padding( padding: const EdgeInsets.only(top: 25.0, bottom: 0), child: Row( children: [ Checkbox( value: _noteAccepted, onChanged: _notesEmpty ? null : (value) { setState(() { _noteAccepted = value!; }); }, ), const Flexible( child: Text( "Ich nehme die oben genannten Anmerkungen zur Lieferung zur Kenntnis.", overflow: TextOverflow.fade, ), ), ], ), ), Padding( padding: const EdgeInsets.only(top: 25.0, bottom: 10.0), child: Row( children: [ Checkbox( value: _customerAccepted, onChanged: (value) { setState(() { _customerAccepted = value!; }); }, ), const Flexible( child: Text( "Ich bestätige, dass ich die Ware im ordnungsgemäßen Zustand erhalten habe und, dass die Aufstell- und Einbauarbeiten korrekt durchgeführt wurden.", overflow: TextOverflow.fade, ), ), ], ), ), ], ) : Container(); } @override Widget build(BuildContext context) { String formattedDate = DateFormat("dd.MM.yyyy").format(DateTime.now()); return Scaffold( appBar: AppBar( title: !_isDriverSigning ? const Text("Unterschrift des Kunden") : const Text("Unterschrift des Fahrers"), ), body: Padding( padding: const EdgeInsets.all(20.0), child: ListView( children: [ SizedBox( width: double.infinity, height: MediaQuery.of(context).size.height * (_isDriverSigning ? 0.75 : 0.5), child: DecoratedBox( decoration: const BoxDecoration(color: Colors.white), child: Padding( padding: const EdgeInsets.all(20.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( "Lieferung an: ${widget.delivery.customer.name}", style: const TextStyle( fontWeight: FontWeight.bold, ), ), Expanded(child: _signatureField()), ], ), ), const Divider(), Text( "${widget.delivery.customer.address.city}, den $formattedDate", ), ], ), ), ), ), _customerCheckboxes(), Padding( padding: const EdgeInsets.only(top: 25.0, bottom: 25.0), child: Center( child: FilledButton( onPressed: !(_customerAccepted && (_noteAccepted || _notesEmpty)) ? null : () async { if (!_isDriverSigning) { setState(() { _isDriverSigning = true; }); } else { widget.onSigned( (await _customerController.toPngBytes())!, (await _driverController.toPngBytes())!, ); } }, child: !_isDriverSigning ? const Text("Weiter") : const Text("Absenden"), ), ), ), ], ), ), ); } }