123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- import 'dart:developer';
- import 'package:defer_pointer/defer_pointer.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter_canvas_editor/style/canvas_style.dart';
- import 'package:flutter_canvas_editor/widgets/elements.dart';
- import 'package:toastification/toastification.dart';
- import 'package:uuid/uuid.dart';
- import '../main.dart';
- var uuid = Uuid();
- class Editor extends ChangeNotifier {
- String? selectedElmId;
-
- bool isEditing = false;
- final textboxResizerDeferredPointerHandlerLink = DeferredPointerHandlerLink();
- // ? Canvas State
- double canvasScale = 1.0;
- final CanvasProperty canvasProperty = CanvasProperty(
- width: 780,
- height: 1000,
- );
- TransformationController canvasTransformationController = TransformationController();
- void setCanvasTransformationInitialZoom(BuildContext context) {
- final deviceWidth = MediaQuery.of(context).size.width;
- canvasScale = deviceWidth / canvasProperty.width * 0.9;
- canvasTransformationController.value = Matrix4.identity()..scale(canvasScale);
- }
- void resetCanvasTransformationScale() {
- print('canvas scale $canvasScale');
- canvasTransformationController.value = Matrix4.identity()..scale(canvasScale);
- }
- void disposeCanvasTransformationController() {
- canvasTransformationController.dispose();
- }
- List<ElementProperty> elementProperties = [
- ElementProperty(
- id: uuid.v4(),
- valueController: TextEditingController(text: '{{QRCODE}}'),
- type: ElementType.qr,
- position: ElementPosition(top: 0, left: 0),
- width: 80,
- quarterTurns: 0,
- elementKey: GlobalKey(),
- qrScale: 3
- )
- ];
- // int _reservedIdUntil = 0;
- // ? udpate canvas
- void updateCanvasProperty(BuildContext context, double width, double height) {
- canvasProperty.height = height;
- canvasProperty.width = width;
- _adjustOutOfBoundElement();
- setCanvasTransformationInitialZoom(context);
- notifyListeners();
- }
- void _adjustOutOfBoundElement() {
- for (var element in elementProperties) {
- bool isOutOfBoundFromTop = (element.position.top + 10) > canvasProperty.height;
- bool isOutOfBoundFromLeft = (element.position.left + 10) > canvasProperty.width;
- // if (isOutOfBoundFromTop | isOutOfBoundFromLeft) {
- // element.position.top = 0;
- // element.position.left = 0;
- // }
- if (isOutOfBoundFromTop) {
- element.position.top = canvasProperty.height - (element.elementKey.currentContext?.size?.height ?? 0);
- }
- if (isOutOfBoundFromLeft) {
- element.position.left = canvasProperty.width - (element.elementKey.currentContext?.size?.width ?? 0);
- }
-
- }
- }
- void populateElement(List<ElementProperty> elementProperties) {
- this.elementProperties.addAll(elementProperties);
- // _reservedIdUntil = this.elementProperties.length - 1;
- notifyListeners();
- }
- void addTextElement(){
- String id = uuid.v4();
- ElementProperty element = ElementProperty(
- id: id,
- valueController: TextEditingController(text: 'Double tap to edit text'),
- type: ElementType.text,
- position: ElementPosition(top: 0, left: 0),
- // size: ElementSize(width: 20, height: 70),
- width: 20,
- elementKey: GlobalKey(),
- quarterTurns: 0
- );
- elementProperties.add(element);
- // _reservedIdUntil = elementProperties.length - 1;r
- notifyListeners();
- selectElmById(id);
- }
- void addTextboxElement() {
- String id = uuid.v4();
- ElementProperty element = ElementProperty(
- id: id,
- valueController: TextEditingController(text: 'Double tap to edit text'),
- type: ElementType.textbox,
- position: ElementPosition(top: 0, left: 0),
- width: 70,
- quarterTurns: 0,
- elementKey: GlobalKey()
- );
- elementProperties.add(element);
- notifyListeners();
- selectElmById(id);
- }
- void updateElmPosition(Offset offset) {
- ElementProperty? element = selectedElm;
- if (element == null) return;
- // element.position = ElementPosition(top: offset.dy, left: offset.dx);
- print(offset.dx);
- element.position.top += offset.dy.round();
- element.position.left += offset.dx.round();
- notifyListeners();
- }
- void updateElmWitdh(double width) {
- ElementProperty? element = selectedElm;
- if (element == null) return;
- element.width = width;
- notifyListeners();
- }
- void toggleLockElement() {
- if (selectedElm == null) return;
- selectedElm!.isLocked = !selectedElm!.isLocked;
- notifyListeners();
- }
- void selectElmById(String id) {
- selectedElmId = id;
- notifyListeners();
- }
- void enableEdit() {
- if (selectedElm!.isLocked) {
- _showLockedToast('Cant modify locked element');
- return;
- }
- isEditing = true;
- notifyListeners();
- }
- void disableEdit() {
- isEditing = false;
- notifyListeners();
- }
- void unSelectElm() {
- selectedElmId = null;
- isEditing = false;
- notifyListeners();
- }
- bool isSelected(String id) {
- return selectedElmId == id;
- }
- // ? Getters
- String get selectedElmType {
- if (elementProperties.isNotEmpty && selectedElmId != null) {
- final selectedElm = elementProperties.firstWhere((element) => element.id == selectedElmId);
- return elementGetter(selectedElm.type);
- }
- return '';
- }
- ElementProperty? get selectedElm {
- if (elementProperties.isNotEmpty && selectedElmId != null) {
- return elementProperties.firstWhere((element) => element.id == selectedElmId);
- }
- return null;
- }
- GlobalKey? get selectedElmKey {
- if (elementProperties.isNotEmpty && selectedElmId != null) {
- return elementProperties.firstWhere((element) => element.id == selectedElmId).elementKey;
- }
- return null;
- }
- bool get shouldShowFontResizer {
- if (selectedElm == null) return false;
- if (![ElementType.text, ElementType.textbox].contains(selectedElm!.type)) return false;
- return true;
- }
- bool get shouldShowQrResizer {
- if (selectedElm == null) return false;
- if (selectedElm!.type != ElementType.qr) return false;
- return true;
- }
- bool get shouldShowDeleteElementButton {
- if (selectedElm == null) return false;
- if ([ElementType.qr].contains(selectedElm!.type)) return false;
- return true;
- }
- // ? Element overlay
- bool shouldShowTextboxResizer(String elmId) {
- if (selectedElmId == null) return false;
- if (selectedElmId != elmId ) return false;
- if (selectedElm!.type != ElementType.textbox) return false;
- return true;
- }
- bool shouldShowOverlay(String elmId) {
- if (selectedElmId == null) return false;
- if (selectedElmId != elmId ) return false;
- if (selectedElm!.type == ElementType.qr) return false;
- return true;
- }
- // Toolbar
- bool get insertElementMode{
- if (selectedElm == null) return true;
- return false;
- }
- /// Can only rotate [ElementType.text, ElementType.textBox]
- void rotate() {
- ElementProperty? element = selectedElm;
- if (element == null) return;
- if (element.isLocked) {
- _showLockedToast('Cant rotate locked element');
- return;
- }
-
- if (![ElementType.text, ElementType.textbox].contains(element.type)) return;
- if (element.type == ElementType.text) _rotateText(element);
- if (element.type == ElementType.textbox) _rotateTextBox(element);
- // Adjust Size
- // double currentElementHeight = selectedElmKey!.currentContext!.size!.height;
- // double currentElementWidth = selectedElmKey!.currentContext!.size!.width;
- // selectedElmKey!.currentContext!.size!.height = currentElementWidth;
- // selectedElmKey!.currentContext!.size!.width = currentElementHeight;
-
- notifyListeners();
- }
- void _rotateText(ElementProperty element) {
- if (element.quarterTurns < 3) {
- element.quarterTurns += 1;
- } else {
- element.quarterTurns = 0;
- }
- }
- void _rotateTextBox(ElementProperty element) {
- if (element.quarterTurns == 0) {
- element.quarterTurns = 3;
- } else {
- element.quarterTurns = 0;
- }
- }
- // FontSize Handler
- void changeFontSize(int? fontSize) {
- if (fontSize == null) return;
- if (selectedElm == null) return;
- if (selectedElm!.isLocked) {
- _showLockedToast('Cant modify locked element');
- return;
- }
- selectedElm!.fontScale = fontSize;
- notifyListeners();
- }
-
- void incrementFontSize() {
- if (selectedElm == null) return;
- final incrementTo = selectedElm!.fontScale + 1;
- if (selectedElm!.isLocked) {
- _showLockedToast('Cant modify locked element');
- return;
- }
- // check if value is allowed for resize
- if (CanvasStyle.fontSizeMap.containsKey(incrementTo)) {
- selectedElm!.fontScale = incrementTo;
- print('kepenjet increase');
- } else {
- print('cant increment');
- }
- notifyListeners();
- }
- void decrementFontSize() {
- if (selectedElm == null) return;
- final decrementTo = selectedElm!.fontScale - 1;
- if (selectedElm!.isLocked) {
- _showLockedToast('Cant modify locked element');
- return;
- }
- // check if value is allowed for resize
- if (CanvasStyle.fontSizeMap.containsKey(decrementTo)) {
- selectedElm!.fontScale = decrementTo;
- } else {
- print('cant decrement');
- }
- notifyListeners();
- }
- // Qr Size Handler
- void changeQrSize(int? fontSize) {
- if (fontSize == null) return;
- if (selectedElm == null) return;
- if (selectedElm!.isLocked) {
- _showLockedToast('Cant modify locked element');
- return;
- }
- selectedElm!.qrScale = fontSize;
- notifyListeners();
- }
-
- void incrementQrSize() {
- if (selectedElm == null) return;
- if (selectedElm!.type != ElementType.qr) return;
- final incrementTo = selectedElm!.qrScale! + 1;
- if (selectedElm!.isLocked) {
- _showLockedToast('Cant modify locked element');
- return;
- }
- // check if value is allowed for resize
- if (CanvasStyle.qrSizeMap.containsKey(incrementTo)) {
- selectedElm!.qrScale = incrementTo;
- } else {
- print('cant increment');
- }
- notifyListeners();
- }
- void decrementQrSize() {
- if (selectedElm == null) return;
- if (selectedElm!.type != ElementType.qr) return;
- final decrementTo = selectedElm!.qrScale! - 1;
- if (selectedElm!.isLocked) {
- _showLockedToast('Cant modify locked element');
- return;
- }
- // check if value is allowed for resize
- if (CanvasStyle.qrSizeMap.containsKey(decrementTo)) {
- selectedElm!.qrScale = decrementTo;
- } else {
- print('cant decrement');
- }
- notifyListeners();
- }
- // Delete Element
- Future<void> deleteElement(BuildContext context) async {
- if (selectedElm == null) return;
- if (selectedElm!.isLocked) {
- _showLockedToast('Cant delete locked element');
- return;
- }
- final shouldDelete = await showDialog(
- context: context,
- builder: (context) {
- return AlertDialog(
- title: Text('Delete Element ?'),
- content: Text('Are you sure want to delete this element ?'),
- actions: [
- TextButton(
- onPressed: () => Navigator.pop(context, false),
- child: Text('Cancel')
- ),
- TextButton(
- onPressed: () => Navigator.pop(context, true),
- child: Text('Delete')
- ),
- ],
- );
- },
- );
- if (!shouldDelete) return;
- elementProperties.removeWhere((e) => e.id == selectedElm!.id);
- unSelectElm();
- notifyListeners();
- }
- // ? snapping element
- // Offset? snapToElement(Offset newPosition) {
- // for (var element in elementProperties) {
- // if ((newPosition.dx - element.))
- // }
- // }
- // ? helper method
- void _showLockedToast(String titleText) {
- toastification.show(
- title: Text(titleText),
- description: Text('unlock to change element property'),
- closeButtonShowType: CloseButtonShowType.none,
- style: ToastificationStyle.minimal,
- type: ToastificationType.warning,
- autoCloseDuration: const Duration(seconds: 3),
- alignment: Alignment.bottomCenter,
- dragToClose: true
- );
- }
- }
|