From 5675437bc0086f4865ec15af4c29a42590ab1769 Mon Sep 17 00:00:00 2001 From: otsmr Date: Mon, 3 Feb 2025 22:18:09 +0100 Subject: [PATCH] image editor in a good state --- .../image_editor/action_button.dart | 2 +- .../components/image_editor/data/layer.dart | 16 ----- .../image_editor/layers/emoji_layer.dart | 62 ++++++++++++++----- .../image_editor/layers/image_layer.dart | 36 ----------- .../image_editor/layers_viewer.dart | 41 ++++-------- .../image_editor/modules/all_emojis.dart | 7 --- .../camera_to_share/camera_preview_view.dart | 15 ++--- .../share_image_editor_view.dart | 20 ------ 8 files changed, 67 insertions(+), 132 deletions(-) delete mode 100755 lib/src/components/image_editor/layers/image_layer.dart diff --git a/lib/src/components/image_editor/action_button.dart b/lib/src/components/image_editor/action_button.dart index 283fae6..aabc347 100644 --- a/lib/src/components/image_editor/action_button.dart +++ b/lib/src/components/image_editor/action_button.dart @@ -14,7 +14,7 @@ class ActionButton extends StatelessWidget { icon: FaIcon( icon, size: 30, - color: color, + color: color ?? Colors.white, shadows: [ Shadow( color: const Color.fromARGB(122, 0, 0, 0), diff --git a/lib/src/components/image_editor/data/layer.dart b/lib/src/components/image_editor/data/layer.dart index 6e68173..4c6f026 100755 --- a/lib/src/components/image_editor/data/layer.dart +++ b/lib/src/components/image_editor/data/layer.dart @@ -46,22 +46,6 @@ class EmojiLayerData extends Layer { }); } -/// Attributes used by [ImageLayer] -class ImageLayerData extends Layer { - ImageItem image; - double size; - - ImageLayerData({ - required this.image, - this.size = 64, - super.offset, - super.opacity, - super.rotation, - super.scale, - super.isEditing, - }); -} - /// Attributes used by [TextLayer] class TextLayerData extends Layer { String text; diff --git a/lib/src/components/image_editor/layers/emoji_layer.dart b/lib/src/components/image_editor/layers/emoji_layer.dart index 4722dde..7ce7754 100755 --- a/lib/src/components/image_editor/layers/emoji_layer.dart +++ b/lib/src/components/image_editor/layers/emoji_layer.dart @@ -17,36 +17,66 @@ class EmojiLayer extends StatefulWidget { } class _EmojiLayerState extends State { - double initialSize = 0; double initialRotation = 0; + Offset initialOffset = Offset.zero; + double initialScale = 1.0; + final GlobalKey _key = GlobalKey(); + + @override + void initState() { + super.initState(); + + if (widget.layerData.offset.dy == 0) { + // Set the initial offset to the center of the screen + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + widget.layerData.offset = Offset( + MediaQuery.of(context).size.width / 2 - 64, + MediaQuery.of(context).size.height / 2 - 64 - 100); + }); + }); + } + } @override Widget build(BuildContext context) { - initialSize = widget.layerData.size; - initialRotation = widget.layerData.rotation; - return Positioned( left: widget.layerData.offset.dx, top: widget.layerData.offset.dy, child: GestureDetector( onTap: () {}, - onScaleUpdate: (detail) { - if (detail.pointerCount == 1) { - widget.layerData.offset = Offset( - widget.layerData.offset.dx + detail.focalPointDelta.dx, - widget.layerData.offset.dy + detail.focalPointDelta.dy, - ); - } else if (detail.pointerCount == 2) { - widget.layerData.size = - initialSize + detail.scale * 5 * (detail.scale > 1 ? 1 : -1); - } + onScaleStart: (details) { + // Store the initial scale and rotation + initialScale = widget.layerData.size; // Reset initial scale + initialRotation = widget.layerData.rotation; + initialOffset = widget.layerData.offset; + }, + onScaleUpdate: (details) { + setState(() { + // Update the size based on the scale factor - setState(() {}); + widget.layerData.size = initialScale * details.scale; + + // Update the rotation based on the rotation angle + widget.layerData.rotation = initialRotation + details.rotation; + + // Update the position based on the translation + final RenderBox renderBox = + _key.currentContext?.findRenderObject() as RenderBox; + var dx = details.focalPoint.dx - (renderBox.size.width / 2); + 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(64), + padding: const EdgeInsets.all(34), + color: Colors.transparent, child: Text( widget.layerData.text.toString(), style: TextStyle( diff --git a/lib/src/components/image_editor/layers/image_layer.dart b/lib/src/components/image_editor/layers/image_layer.dart deleted file mode 100755 index d714556..0000000 --- a/lib/src/components/image_editor/layers/image_layer.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:twonly/src/components/image_editor/data/layer.dart'; - -/// Image layer that can be used to add overlay images and drawings -class ImageLayer extends StatefulWidget { - final ImageLayerData layerData; - final VoidCallback? onUpdate; - - const ImageLayer({ - super.key, - required this.layerData, - this.onUpdate, - }); - - @override - createState() => _ImageLayerState(); -} - -class _ImageLayerState extends State { - double initialSize = 0; - double initialRotation = 0; - - @override - Widget build(BuildContext context) { - initialSize = widget.layerData.size; - initialRotation = widget.layerData.rotation; - - return Positioned.fill( - child: SizedBox( - width: widget.layerData.image.width.toDouble(), - height: widget.layerData.image.height.toDouble(), - child: Image.memory(widget.layerData.image.bytes), - ), - ); - } -} diff --git a/lib/src/components/image_editor/layers_viewer.dart b/lib/src/components/image_editor/layers_viewer.dart index 28b1970..e60fdea 100644 --- a/lib/src/components/image_editor/layers_viewer.dart +++ b/lib/src/components/image_editor/layers_viewer.dart @@ -3,7 +3,6 @@ import 'package:twonly/src/components/image_editor/data/layer.dart'; import 'package:twonly/src/components/image_editor/layers/background_layer.dart'; import 'package:twonly/src/components/image_editor/layers/draw_layer.dart'; import 'package:twonly/src/components/image_editor/layers/emoji_layer.dart'; -import 'package:twonly/src/components/image_editor/layers/image_layer.dart'; import 'package:twonly/src/components/image_editor/layers/text_layer.dart'; /// View stacked layers (unbounded height, width) @@ -22,50 +21,34 @@ class LayersViewer extends StatelessWidget { return Stack( alignment: Alignment.center, children: [ - // Background and Image layers at the bottom - ...layers - .where((layerItem) => - layerItem is BackgroundLayerData || layerItem is ImageLayerData) - .map((layerItem) { - if (layerItem is BackgroundLayerData) { - return BackgroundLayer( - layerData: layerItem, - onUpdate: onUpdate, - ); - } else if (layerItem is ImageLayerData) { - return ImageLayer( - layerData: layerItem, - onUpdate: onUpdate, - ); - } - return Container(); // Fallback, should not reach here - }), - - // Draw layer (if needed, can be placed anywhere) - ...layers.whereType().map((layerItem) { - return DrawLayer( + ...layers.whereType().map((layerItem) { + return BackgroundLayer( layerData: layerItem, onUpdate: onUpdate, ); }), - - // Emoji and Text layers at the top ...layers .where((layerItem) => - layerItem is EmojiLayerData || layerItem is TextLayerData) + layerItem is EmojiLayerData || layerItem is DrawLayerData) .map((layerItem) { if (layerItem is EmojiLayerData) { return EmojiLayer( layerData: layerItem, onUpdate: onUpdate, ); - } else if (layerItem is TextLayerData) { - return TextLayer( + } else if (layerItem is DrawLayerData) { + return DrawLayer( layerData: layerItem, onUpdate: onUpdate, ); } - return Container(); // Fallback, should not reach here + return Container(); + }), + ...layers.whereType().map((layerItem) { + return TextLayer( + layerData: layerItem, + onUpdate: onUpdate, + ); }), ], ); diff --git a/lib/src/components/image_editor/modules/all_emojis.dart b/lib/src/components/image_editor/modules/all_emojis.dart index 3a9ace1..e0798f1 100755 --- a/lib/src/components/image_editor/modules/all_emojis.dart +++ b/lib/src/components/image_editor/modules/all_emojis.dart @@ -31,13 +31,6 @@ class _EmojisState extends State { ), child: Column( children: [ - const SizedBox(height: 16), - Row(mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( - ('Select Emoji'), - style: const TextStyle(color: Colors.white), - ), - ]), const SizedBox(height: 16), Container( height: 315, diff --git a/lib/src/views/camera_to_share/camera_preview_view.dart b/lib/src/views/camera_to_share/camera_preview_view.dart index d17caa5..d4b592c 100644 --- a/lib/src/views/camera_to_share/camera_preview_view.dart +++ b/lib/src/views/camera_to_share/camera_preview_view.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:camerawesome/camerawesome_plugin.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:twonly/src/components/image_editor/action_button.dart'; import 'package:twonly/src/components/media_view_sizing.dart'; import 'package:twonly/src/components/permissions_view.dart'; import 'package:twonly/src/views/camera_to_share/share_image_editor_view.dart'; @@ -173,22 +174,22 @@ class _CameraPreviewViewState extends State { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - BottomButton( - icon: FontAwesomeIcons.repeat, - onTap: () async { + ActionButton( + FontAwesomeIcons.repeat, + onPressed: () async { cameraState.switchCameraSensor( aspectRatio: CameraAspectRatios.ratio_16_9); }, ), - SizedBox(height: 20), - BottomButton( - icon: FontAwesomeIcons.bolt, + // SizedBox(height: 20), + ActionButton( + FontAwesomeIcons.bolt, color: isFlashOn ? const Color.fromARGB(255, 255, 230, 0) : const Color.fromARGB( 158, 255, 255, 255), - onTap: () async { + onPressed: () async { if (isFlashOn) { cameraState.sensorConfig .setFlashMode(FlashMode.none); diff --git a/lib/src/views/camera_to_share/share_image_editor_view.dart b/lib/src/views/camera_to_share/share_image_editor_view.dart index f553072..957e4c1 100644 --- a/lib/src/views/camera_to_share/share_image_editor_view.dart +++ b/lib/src/views/camera_to_share/share_image_editor_view.dart @@ -63,26 +63,9 @@ class _ShareImageEditorView extends State { BottomButton( icon: FontAwesomeIcons.pencil, onTap: () async { - // var drawing = await Navigator.push( - // context, - // PageRouteBuilder( - // opaque: false, - // pageBuilder: (context, a, b) => ImageEditorDrawing( - // image: currentImage, - // ), - // transitionDuration: Duration.zero, - // reverseTransitionDuration: Duration.zero, - // ), - // ); - - // if (drawing != null) { undoLayers.clear(); removedLayers.clear(); - layers.add(DrawLayerData()); - - // setState(() {}); - // } }, ), BottomButton( @@ -156,7 +139,6 @@ class _ShareImageEditorView extends State { double widthRatio = 1, heightRatio = 1, pixelRatio = 1; - /// obtain image Uint8List by merging layers Future getMergedImage() async { Uint8List? image; @@ -165,8 +147,6 @@ class _ShareImageEditorView extends State { } else if (layers.length == 1) { if (layers.first is BackgroundLayerData) { image = (layers.first as BackgroundLayerData).image.bytes; - } else if (layers.first is ImageLayerData) { - image = (layers.first as ImageLayerData).image.bytes; } } return image;