|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import 'package:signature/signature.dart';
|
|
|
|
|
import 'package:test_sa/controllers/api_routes/urls.dart';
|
|
|
|
|
import 'package:test_sa/extensions/context_extension.dart';
|
|
|
|
|
import 'package:test_sa/extensions/int_extensions.dart';
|
|
|
|
|
import 'package:test_sa/extensions/text_extensions.dart';
|
|
|
|
|
import 'package:test_sa/extensions/widget_extensions.dart';
|
|
|
|
|
import 'package:test_sa/new_views/app_style/app_color.dart';
|
|
|
|
|
|
|
|
|
|
import '../loaders/image_loader.dart';
|
|
|
|
|
|
|
|
|
|
class ESignature extends StatefulWidget {
|
|
|
|
|
final String? oldSignature;
|
|
|
|
|
final Uint8List? newSignature;
|
|
|
|
|
final Function(Uint8List?)? onSaved;
|
|
|
|
|
final Color? backgroundColor;
|
|
|
|
|
final Function(Uint8List)? onChange;
|
|
|
|
|
final bool showShadow;
|
|
|
|
|
final String title;
|
|
|
|
|
|
|
|
|
|
const ESignature({Key? key, required this.title, required this.oldSignature, this.backgroundColor, this.onSaved, this.onChange, this.showShadow = true, required this.newSignature})
|
|
|
|
|
: super(key: key);
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
State<ESignature> createState() => _ESignatureState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class _ESignatureState extends State<ESignature> {
|
|
|
|
|
// Initialise a controller. It will contains signature points, stroke width and pen color.
|
|
|
|
|
SignatureController? _controller;
|
|
|
|
|
|
|
|
|
|
Uint8List? signature;
|
|
|
|
|
|
|
|
|
|
bool _editable = false;
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
void initState() {
|
|
|
|
|
if (widget.newSignature != null) {
|
|
|
|
|
signature = widget.newSignature;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
super.initState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
void dispose() {
|
|
|
|
|
_controller?.dispose();
|
|
|
|
|
super.dispose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
_controller ??= SignatureController(
|
|
|
|
|
penStrokeWidth: 2,
|
|
|
|
|
penColor: context.isDark ? Colors.white : Colors.black,
|
|
|
|
|
exportBackgroundColor: AppColor.background(context),
|
|
|
|
|
);
|
|
|
|
|
return FormField<String>(onSaved: (_) async {
|
|
|
|
|
if (widget.onSaved != null) widget.onSaved!(signature);
|
|
|
|
|
}, builder: (FormFieldState<String> state) {
|
|
|
|
|
return Column(
|
|
|
|
|
children: [
|
|
|
|
|
Container(
|
|
|
|
|
width: MediaQuery.of(context).size.width,
|
|
|
|
|
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight),
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: widget.backgroundColor ?? (context.isDark ? AppColor.background(context) : Colors.white),
|
|
|
|
|
borderRadius: _editable ? const BorderRadius.only(topLeft: Radius.circular(10), topRight: Radius.circular(10)) : BorderRadius.circular(10),
|
|
|
|
|
boxShadow: widget.showShadow ? [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)] : null,
|
|
|
|
|
),
|
|
|
|
|
child: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
|
|
children: [
|
|
|
|
|
Row(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
|
children: [
|
|
|
|
|
widget.title.tinyFont(context).paddingOnly(top: 8),
|
|
|
|
|
(!_editable
|
|
|
|
|
? "edit".toSvgAsset(width: 48).paddingOnly(top: 8)
|
|
|
|
|
: Container(
|
|
|
|
|
width: 48.toScreenWidth,
|
|
|
|
|
height: 48.toScreenWidth,
|
|
|
|
|
decoration: BoxDecoration(borderRadius: BorderRadius.circular(100), border: Border.all(color: AppColor.neutral30)),
|
|
|
|
|
padding: const EdgeInsets.all(11),
|
|
|
|
|
margin: const EdgeInsets.only(top: 8),
|
|
|
|
|
child: "done".toSvgAsset(width: 26),
|
|
|
|
|
))
|
|
|
|
|
.onPress(() async {
|
|
|
|
|
if (_editable) {
|
|
|
|
|
signature = await _controller!.toPngBytes();
|
|
|
|
|
if (widget.onChange != null && signature != null) {
|
|
|
|
|
widget.onChange!(signature!);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_editable = !_editable;
|
|
|
|
|
setState(() {});
|
|
|
|
|
}),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
((widget.oldSignature != null || signature != null) && !_editable)
|
|
|
|
|
? Container(
|
|
|
|
|
height: 135.toScreenHeight,
|
|
|
|
|
width: MediaQuery.of(context).size.width,
|
|
|
|
|
padding: const EdgeInsets.only(bottom: 8),
|
|
|
|
|
child: signature != null ? Image.memory(signature!) : ImageLoader(showDefaultIcon: true, boxFit: BoxFit.contain, url: URLs.getFileUrl(widget.oldSignature) ?? ''),
|
|
|
|
|
)
|
|
|
|
|
: AbsorbPointer(
|
|
|
|
|
absorbing: !_editable,
|
|
|
|
|
child: Signature(
|
|
|
|
|
controller: _controller!,
|
|
|
|
|
height: 135.toScreenHeight,
|
|
|
|
|
width: MediaQuery.of(context).size.width - 64.toScreenWidth,
|
|
|
|
|
backgroundColor: Colors.transparent,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
if (_editable)
|
|
|
|
|
Container(
|
|
|
|
|
decoration: const BoxDecoration(
|
|
|
|
|
color: AppColor.neutral30,
|
|
|
|
|
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(10), bottomRight: Radius.circular(10)),
|
|
|
|
|
),
|
|
|
|
|
child: Row(
|
|
|
|
|
children: [
|
|
|
|
|
"clear".toSvgAsset(width: 14).paddingOnly(start: 16).onPress(() {
|
|
|
|
|
_controller!.clear();
|
|
|
|
|
}),
|
|
|
|
|
35.width,
|
|
|
|
|
"back".toSvgAsset(width: 17).onPress(() {
|
|
|
|
|
_controller!.undo();
|
|
|
|
|
}),
|
|
|
|
|
27.width,
|
|
|
|
|
"redo".toSvgAsset(width: 17).onPress(() {
|
|
|
|
|
_controller!.redo();
|
|
|
|
|
}),
|
|
|
|
|
// IconButton(
|
|
|
|
|
// onPressed: () {
|
|
|
|
|
// _unpaint = !_unpaint;
|
|
|
|
|
// setState(() {});
|
|
|
|
|
// },
|
|
|
|
|
// icon: Icon(
|
|
|
|
|
// _unpaint ? Icons.draw : Icons.ac_unit,
|
|
|
|
|
// color: _unpaint ? AColors.orange : null,
|
|
|
|
|
// )),
|
|
|
|
|
// const Spacer(),
|
|
|
|
|
// IconButton(
|
|
|
|
|
// onPressed: () async {
|
|
|
|
|
// signature = await _controller.toPngBytes();
|
|
|
|
|
// if (widget.onChange != null) {
|
|
|
|
|
// widget.onChange(signature);
|
|
|
|
|
// }
|
|
|
|
|
// setState(() {});
|
|
|
|
|
// },
|
|
|
|
|
// icon: const Icon(Icons.check)),
|
|
|
|
|
],
|
|
|
|
|
).paddingOnly(top: 12, bottom: 12),
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|