From 3be963c8f9f31e020bb4c2feafcd083b633b8243 Mon Sep 17 00:00:00 2001 From: otsmr Date: Sat, 22 Mar 2025 15:59:30 +0100 Subject: [PATCH] fix #29 --- .../image_editor/layers/emoji_layer.dart | 162 +++++++++++------- 1 file changed, 101 insertions(+), 61 deletions(-) diff --git a/lib/src/components/image_editor/layers/emoji_layer.dart b/lib/src/components/image_editor/layers/emoji_layer.dart index 11b75d1..aabf64a 100755 --- a/lib/src/components/image_editor/layers/emoji_layer.dart +++ b/lib/src/components/image_editor/layers/emoji_layer.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:twonly/src/components/image_editor/action_button.dart'; import 'package:twonly/src/components/image_editor/data/layer.dart'; /// Emoji layer @@ -21,8 +23,10 @@ class _EmojiLayerState extends State { Offset initialOffset = Offset.zero; Offset initialFocalPoint = Offset.zero; double initialScale = 1.0; + bool deleteLayer = false; bool twoPointerWhereDown = false; - final GlobalKey _key = GlobalKey(); + final GlobalKey outlineKey = GlobalKey(); + final GlobalKey emojiKey = GlobalKey(); int pointers = 0; @override @@ -43,76 +47,112 @@ class _EmojiLayerState extends State { @override Widget build(BuildContext context) { - return Positioned( - left: widget.layerData.offset.dx, - top: widget.layerData.offset.dy, - child: Listener( - onPointerUp: (details) { - setState(() { - pointers--; - if (pointers == 0) { - twoPointerWhereDown = false; - } - }); - }, - onPointerDown: (details) { - setState(() { - pointers++; - }); - }, - child: GestureDetector( - onScaleStart: (details) { - // Store the initial scale and rotation - initialScale = widget.layerData.size; // Reset initial scale - initialRotation = widget.layerData.rotation; - initialOffset = widget.layerData.offset; - initialFocalPoint = - Offset(details.focalPoint.dx, details.focalPoint.dy); + if (widget.layerData.isDeleted) return Container(); + return Stack( + key: outlineKey, + children: [ + Positioned( + left: widget.layerData.offset.dx, + top: widget.layerData.offset.dy, + child: Listener( + onPointerUp: (details) { + setState(() { + pointers--; + if (pointers == 0) { + twoPointerWhereDown = false; + } + if (deleteLayer) { + widget.layerData.isDeleted = true; + } + }); + }, + onPointerDown: (details) { + setState(() { + pointers++; + }); + }, + child: GestureDetector( + onScaleStart: (details) { + initialScale = widget.layerData.size; + initialRotation = widget.layerData.rotation; + initialOffset = widget.layerData.offset; + initialFocalPoint = + Offset(details.focalPoint.dx, details.focalPoint.dy); - setState(() {}); - }, - onScaleUpdate: (details) { - if (twoPointerWhereDown == true && details.pointerCount != 2) { - return; - } - setState(() { - // Update the size based on the scale factor + setState(() {}); + }, + onScaleUpdate: (details) { + if (twoPointerWhereDown == true && details.pointerCount != 2) { + return; + } + final RenderBox outlineBox = + outlineKey.currentContext!.findRenderObject() as RenderBox; - twoPointerWhereDown = details.pointerCount >= 2; + final RenderBox emojiBox = + emojiKey.currentContext!.findRenderObject() as RenderBox; - widget.layerData.size = initialScale * details.scale; + bool isAtTheBottom = + (widget.layerData.offset.dy + emojiBox.size.height / 2) > + outlineBox.size.height - 80; + bool isInTheCenter = MediaQuery.of(context).size.width / 2 - + 30 < + (widget.layerData.offset.dx + + emojiBox.size.width / 2) && + MediaQuery.of(context).size.width / 2 + 20 > + (widget.layerData.offset.dx + emojiBox.size.width / 2); - // Update the rotation based on the rotation angle - widget.layerData.rotation = initialRotation + details.rotation; + if (isAtTheBottom && isInTheCenter) { + deleteLayer = true; + } else { + deleteLayer = false; + } + setState(() { + twoPointerWhereDown = details.pointerCount >= 2; + widget.layerData.size = initialScale * details.scale; + widget.layerData.rotation = + initialRotation + details.rotation; - // Update the position based on the translation - var dx = (initialOffset.dx) + - (details.focalPoint.dx - initialFocalPoint.dx); - var dy = (initialOffset.dy) + - (details.focalPoint.dy - initialFocalPoint.dy); - // var dy = details.focalPoint.dy - (renderBox.size.height / 2 + 34); - widget.layerData.offset = Offset(dx, dy); - }); - }, - onScaleEnd: (details) { - // Optionally, you can handle the end of the scale gesture here - }, - child: Transform.rotate( - key: _key, - angle: widget.layerData.rotation, - child: Container( - padding: const EdgeInsets.all(44), - color: Colors.transparent, - child: Text( - widget.layerData.text.toString(), - style: TextStyle( - fontSize: widget.layerData.size, + // Update the position based on the translation + var dx = (initialOffset.dx) + + (details.focalPoint.dx - initialFocalPoint.dx); + var dy = (initialOffset.dy) + + (details.focalPoint.dy - initialFocalPoint.dy); + widget.layerData.offset = Offset(dx, dy); + }); + }, + child: Transform.rotate( + angle: widget.layerData.rotation, + key: emojiKey, + child: Container( + padding: const EdgeInsets.all(44), + color: Colors.transparent, + child: Text( + widget.layerData.text.toString(), + style: TextStyle( + fontSize: widget.layerData.size, + ), + ), ), ), ), ), ), - ), + if (pointers > 0) + Positioned( + left: 0, + right: 0, + bottom: 20, + child: Center( + child: GestureDetector( + child: ActionButton( + FontAwesomeIcons.trashCan, + tooltipText: "", + color: deleteLayer ? Colors.red : Colors.white, + ), + ), + ), + ), + ], ); } }