191 lines
7.4 KiB
Dart
191 lines
7.4 KiB
Dart
import 'dart:typed_data';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:pdf_signature/l10n/app_localizations.dart';
|
|
|
|
import '../../../../data/services/export_providers.dart';
|
|
import '../view_model/view_model.dart';
|
|
import 'image_editor_dialog.dart';
|
|
import 'signature_card.dart';
|
|
|
|
/// Data for drag-and-drop is in signature_drag_data.dart
|
|
|
|
class SignatureDrawer extends ConsumerStatefulWidget {
|
|
const SignatureDrawer({
|
|
super.key,
|
|
required this.disabled,
|
|
required this.onLoadSignatureFromFile,
|
|
required this.onOpenDrawCanvas,
|
|
});
|
|
|
|
final bool disabled;
|
|
// Return the loaded bytes (if any) so we can add the exact image to the library immediately.
|
|
final Future<Uint8List?> Function() onLoadSignatureFromFile;
|
|
// Return the drawn bytes (if any) so we can add it to the library immediately.
|
|
final Future<Uint8List?> Function() onOpenDrawCanvas;
|
|
|
|
@override
|
|
ConsumerState<SignatureDrawer> createState() => _SignatureDrawerState();
|
|
}
|
|
|
|
class _SignatureDrawerState extends ConsumerState<SignatureDrawer> {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final l = AppLocalizations.of(context);
|
|
final sig = ref.watch(signatureProvider);
|
|
final processed = ref.watch(processedSignatureImageProvider);
|
|
final bytes = processed ?? sig.imageBytes;
|
|
final library = ref.watch(signatureLibraryProvider);
|
|
final isExporting = ref.watch(exportingProvider);
|
|
final disabled = widget.disabled || isExporting;
|
|
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
if (library.isNotEmpty) ...[
|
|
for (final a in library) ...[
|
|
Card(
|
|
margin: EdgeInsets.zero,
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(12),
|
|
child: SignatureCard(
|
|
key: ValueKey('sig_card_${a.id}'),
|
|
asset:
|
|
(sig.assetId == a.id)
|
|
? SignatureAsset(
|
|
id: a.id,
|
|
bytes: (processed ?? a.bytes),
|
|
name: a.name,
|
|
)
|
|
: a,
|
|
rotationDeg: (sig.assetId == a.id) ? sig.rotation : 0.0,
|
|
disabled: disabled,
|
|
onDelete:
|
|
() => ref
|
|
.read(signatureLibraryProvider.notifier)
|
|
.remove(a.id),
|
|
onAdjust: () async {
|
|
ref
|
|
.read(signatureProvider.notifier)
|
|
.setImageFromLibrary(assetId: a.id);
|
|
if (!mounted) return;
|
|
await showDialog(
|
|
context: context,
|
|
builder: (_) => const ImageEditorDialog(),
|
|
);
|
|
},
|
|
onTap: () {
|
|
// Never reassign placed signatures via tap; only set active overlay source
|
|
ref
|
|
.read(signatureProvider.notifier)
|
|
.setImageFromLibrary(assetId: a.id);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
],
|
|
],
|
|
if (library.isEmpty)
|
|
Card(
|
|
margin: EdgeInsets.zero,
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(12),
|
|
child:
|
|
bytes == null
|
|
? Text(l.noSignatureLoaded)
|
|
: SignatureCard(
|
|
asset: SignatureAsset(id: '', bytes: bytes, name: ''),
|
|
rotationDeg: sig.rotation,
|
|
disabled: disabled,
|
|
useCurrentBytesForDrag: true,
|
|
onDelete: () {
|
|
ref
|
|
.read(signatureProvider.notifier)
|
|
.clearActiveOverlay();
|
|
ref.read(signatureProvider.notifier).clearImage();
|
|
},
|
|
onAdjust: () async {
|
|
if (!mounted) return;
|
|
await showDialog(
|
|
context: context,
|
|
builder: (_) => const ImageEditorDialog(),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
Card(
|
|
margin: EdgeInsets.zero,
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(12),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
Text(
|
|
l.createNewSignature,
|
|
style: Theme.of(context).textTheme.titleSmall,
|
|
),
|
|
const SizedBox(height: 8),
|
|
Wrap(
|
|
spacing: 8,
|
|
runSpacing: 8,
|
|
children: [
|
|
OutlinedButton.icon(
|
|
key: const Key('btn_drawer_load_signature'),
|
|
onPressed:
|
|
disabled
|
|
? null
|
|
: () async {
|
|
final loaded =
|
|
await widget.onLoadSignatureFromFile();
|
|
final b =
|
|
loaded ??
|
|
ref.read(processedSignatureImageProvider) ??
|
|
ref.read(signatureProvider).imageBytes;
|
|
if (b != null) {
|
|
final id = ref
|
|
.read(signatureLibraryProvider.notifier)
|
|
.add(b, name: 'image');
|
|
ref
|
|
.read(signatureProvider.notifier)
|
|
.setImageFromLibrary(assetId: id);
|
|
}
|
|
},
|
|
icon: const Icon(Icons.image_outlined),
|
|
label: Text(l.loadSignatureFromFile),
|
|
),
|
|
OutlinedButton.icon(
|
|
key: const Key('btn_drawer_draw_signature'),
|
|
onPressed:
|
|
disabled
|
|
? null
|
|
: () async {
|
|
final drawn = await widget.onOpenDrawCanvas();
|
|
final b =
|
|
drawn ??
|
|
ref.read(processedSignatureImageProvider) ??
|
|
ref.read(signatureProvider).imageBytes;
|
|
if (b != null) {
|
|
final id = ref
|
|
.read(signatureLibraryProvider.notifier)
|
|
.add(b, name: 'drawing');
|
|
ref
|
|
.read(signatureProvider.notifier)
|
|
.setImageFromLibrary(assetId: id);
|
|
}
|
|
},
|
|
icon: const Icon(Icons.gesture),
|
|
label: Text(l.drawSignature),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|