diff --git a/lib/src/components/image_editor/CREDITS.md b/lib/src/components/image_editor/CREDITS.md deleted file mode 100644 index 9cee998..0000000 --- a/lib/src/components/image_editor/CREDITS.md +++ /dev/null @@ -1 +0,0 @@ -The image editor is based on: https://github.com/hsbijarniya/image_editor_plus/tree/main diff --git a/lib/src/components/image_editor/data/editor_mode.dart b/lib/src/components/image_editor/data/editor_mode.dart deleted file mode 100644 index 2a38cba..0000000 --- a/lib/src/components/image_editor/data/editor_mode.dart +++ /dev/null @@ -1,4 +0,0 @@ -enum EditorMode { - brush, - filter, -} diff --git a/lib/src/components/image_editor/data/image_item.dart b/lib/src/components/image_editor/data/image_item.dart index 920a8cd..96d53e5 100755 --- a/lib/src/components/image_editor/data/image_item.dart +++ b/lib/src/components/image_editor/data/image_item.dart @@ -34,21 +34,4 @@ class ImageItem { return loader.complete(false); } } - - static ImageItem fromJson(Map json) { - var image = ImageItem(json['bytes']); - - image.width = json['width']; - image.height = json['height']; - - return image; - } - - Map toJson() { - return { - 'height': height, - 'width': width, - 'bytes': bytes, - }; - } } diff --git a/lib/src/components/image_editor/data/layer.dart b/lib/src/components/image_editor/data/layer.dart index 73abb08..da65d43 100755 --- a/lib/src/components/image_editor/data/layer.dart +++ b/lib/src/components/image_editor/data/layer.dart @@ -12,41 +12,6 @@ class Layer { this.rotation = 0, this.scale = 1, }); - - copyFrom(Map json) { - offset = Offset(json['offset'][0], json['offset'][1]); - opacity = json['opacity']; - rotation = json['rotation']; - scale = json['scale']; - } - - static Layer fromJson(Map json) { - switch (json['type']) { - case 'BackgroundLayer': - return BackgroundLayerData.fromJson(json); - case 'EmojiLayer': - return EmojiLayerData.fromJson(json); - case 'ImageLayer': - return ImageLayerData.fromJson(json); - case 'LinkLayer': - return LinkLayerData.fromJson(json); - case 'TextLayer': - return TextLayerData.fromJson(json); - case 'BackgroundBlurLayer': - return BackgroundBlurLayerData.fromJson(json); - default: - return Layer(); - } - } - - Map toJson() { - return { - 'offset': [offset.dx, offset.dy], - 'opacity': opacity, - 'rotation': rotation, - 'scale': scale, - }; - } } /// Attributes used by [BackgroundLayer] @@ -56,20 +21,6 @@ class BackgroundLayerData extends Layer { BackgroundLayerData({ required this.image, }); - - static BackgroundLayerData fromJson(Map json) { - return BackgroundLayerData( - image: ImageItem.fromJson(json['image']), - ); - } - - @override - Map toJson() { - return { - 'type': 'BackgroundLayer', - 'image': image.toJson(), - }; - } } /// Attributes used by [EmojiLayer] @@ -85,26 +36,6 @@ class EmojiLayerData extends Layer { super.rotation, super.scale, }); - - static EmojiLayerData fromJson(Map json) { - var layer = EmojiLayerData( - text: json['text'], - size: json['size'], - ); - - layer.copyFrom(json); - return layer; - } - - @override - Map toJson() { - return { - 'type': 'EmojiLayer', - 'text': text, - 'size': size, - ...super.toJson(), - }; - } } /// Attributes used by [ImageLayer] @@ -120,76 +51,19 @@ class ImageLayerData extends Layer { super.rotation, super.scale, }); - - static ImageLayerData fromJson(Map json) { - var layer = ImageLayerData( - image: ImageItem.fromJson(json['image']), - size: json['size'], - ); - - layer.copyFrom(json); - return layer; - } - - @override - Map toJson() { - return { - 'type': 'ImageLayer', - 'image': image.toJson(), - 'size': size, - ...super.toJson(), - }; - } } /// Attributes used by [TextLayer] class TextLayerData extends Layer { String text; - double size; - Color color, background; - double backgroundOpacity; - TextAlign align; TextLayerData({ required this.text, - this.size = 64, - this.color = Colors.white, - this.background = Colors.transparent, - this.backgroundOpacity = 0, - this.align = TextAlign.left, super.offset, super.opacity, super.rotation, super.scale, }); - - static TextLayerData fromJson(Map json) { - var layer = TextLayerData( - text: json['text'], - size: json['size'], - color: Color(json['color']), - background: Color(json['background']), - backgroundOpacity: json['backgroundOpacity'], - align: TextAlign.values.firstWhere((e) => e.name == json['align']), - ); - - layer.copyFrom(json); - return layer; - } - - @override - Map toJson() { - return { - 'type': 'TextLayer', - 'text': text, - 'size': size, - 'color': color.value, - 'background': background.value, - 'backgroundOpacity': backgroundOpacity, - 'align': align.name, - ...super.toJson(), - }; - } } /// Attributes used by [TextLayer] @@ -212,67 +86,4 @@ class LinkLayerData extends Layer { super.rotation, super.scale, }); - - static LinkLayerData fromJson(Map json) { - var layer = LinkLayerData( - text: json['text'], - size: json['size'], - color: Color(json['color']), - background: Color(json['background']), - backgroundOpacity: json['backgroundOpacity'], - align: TextAlign.values.firstWhere((e) => e.name == json['align']), - ); - - layer.copyFrom(json); - return layer; - } - - @override - Map toJson() { - return { - 'type': 'LinkLayer', - 'text': text, - 'size': size, - 'color': color.value, - 'background': background.value, - 'backgroundOpacity': backgroundOpacity, - 'align': align.name, - ...super.toJson(), - }; - } -} - -/// Attributes used by [BackgroundBlurLayer] -class BackgroundBlurLayerData extends Layer { - Color color; - double radius; - - BackgroundBlurLayerData({ - required this.color, - required this.radius, - super.offset, - super.opacity, - super.rotation, - super.scale, - }); - - static BackgroundBlurLayerData fromJson(Map json) { - var layer = BackgroundBlurLayerData( - color: Color(json['color']), - radius: json['radius'], - ); - - layer.copyFrom(json); - return layer; - } - - @override - Map toJson() { - return { - 'type': 'BackgroundBlurLayer', - 'color': color.value, - 'radius': radius, - ...super.toJson(), - }; - } } diff --git a/lib/src/components/image_editor/image_editor.dart b/lib/src/components/image_editor/image_editor.dart index a2dbe42..0bed9a3 100644 --- a/lib/src/components/image_editor/image_editor.dart +++ b/lib/src/components/image_editor/image_editor.dart @@ -1,6 +1,4 @@ import 'dart:async'; -import 'dart:math' as math; -import 'package:flex_color_picker/flex_color_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; @@ -8,75 +6,29 @@ import 'package:hand_signature/signature.dart'; import 'package:twonly/src/components/image_editor/data/image_item.dart'; import 'package:twonly/src/components/image_editor/data/layer.dart'; import 'package:twonly/src/components/image_editor/layers_viewer.dart'; -import 'package:twonly/src/components/image_editor/loading_screen.dart'; import 'package:twonly/src/components/image_editor/modules/all_emojis.dart'; -import 'package:twonly/src/components/image_editor/modules/text.dart'; -import 'package:twonly/src/components/image_editor/options.dart' as o; import 'package:screenshot/screenshot.dart'; -late Size viewportSize; -double viewportRatio = 1; +List layers = []; +List undoLayers = []; +List removedLayers = []; -List layers = [], undoLayers = [], removedLayers = []; -Map _translations = {}; - -String i18n(String sourceString) => - _translations[sourceString.toLowerCase()] ?? sourceString; - -/// Image editor with all option available class ImageEditor extends StatefulWidget { final dynamic image; final String? savePath; - final o.BrushOption? brushOption; - final o.EmojiOption? emojiOption; - final o.TextOption? textOption; const ImageEditor({ super.key, this.image, this.savePath, - this.brushOption = const o.BrushOption(), - this.emojiOption = const o.EmojiOption(), - this.textOption = const o.TextOption(), }); @override createState() => _ImageEditorState(); - - static setI18n(Map translations) { - translations.forEach((key, value) { - _translations[key.toLowerCase()] = value; - }); - } - - /// Set custom theme properties default is dark theme with white text - static ThemeData theme = ThemeData( - scaffoldBackgroundColor: Colors.black, - colorScheme: const ColorScheme.dark( - surface: Colors.black, - ), - appBarTheme: const AppBarTheme( - backgroundColor: Colors.black87, - iconTheme: IconThemeData(color: Colors.white), - systemOverlayStyle: SystemUiOverlayStyle.light, - toolbarTextStyle: TextStyle(color: Colors.white), - titleTextStyle: TextStyle(color: Colors.white), - ), - bottomNavigationBarTheme: const BottomNavigationBarThemeData( - backgroundColor: Colors.black, - ), - iconTheme: const IconThemeData( - color: Colors.white, - ), - textTheme: const TextTheme( - bodyMedium: TextStyle(color: Colors.white), - ), - ); } class _ImageEditorState extends State { ImageItem currentImage = ImageItem(); - ScreenshotController screenshotController = ScreenshotController(); @override @@ -88,65 +40,52 @@ class _ImageEditorState extends State { List get filterActions { return [ IconButton( - icon: Icon(Icons.close, size: 30), + icon: FaIcon( + FontAwesomeIcons.xmark, + size: 30, + shadows: [ + Shadow( + color: const Color.fromARGB(122, 0, 0, 0), + blurRadius: 1.0, + ) + ], + ), color: Colors.white, onPressed: () async { Navigator.pop(context); }, ), - SizedBox( - width: MediaQuery.of(context).size.width - 48, - child: Row(children: [ - IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), - icon: Icon(Icons.undo, - color: layers.length > 1 || removedLayers.isNotEmpty - ? Colors.white - : Colors.grey), - onPressed: () { - if (removedLayers.isNotEmpty) { - layers.add(removedLayers.removeLast()); - setState(() {}); - return; - } - - if (layers.length <= 1) return; // do not remove image layer - - undoLayers.add(layers.removeLast()); - - setState(() {}); - }, - ), - IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), - icon: Icon(Icons.redo, - color: undoLayers.isNotEmpty ? Colors.white : Colors.grey), - onPressed: () { - if (undoLayers.isEmpty) return; - - layers.add(undoLayers.removeLast()); - - setState(() {}); - }, - ), - IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), - icon: const Icon(Icons.check), - onPressed: () async { - resetTransformation(); - setState(() {}); - - var loadingScreen = showLoadingScreen(context); - - Uint8List? editedImageBytes = await getMergedImage(); - - loadingScreen.hide(); - - if (mounted) Navigator.pop(context, editedImageBytes); - }, - ), - ]), + Expanded(child: Container()), + IconButton( + padding: const EdgeInsets.symmetric(horizontal: 8), + icon: Icon(Icons.undo, + color: layers.length > 1 || removedLayers.isNotEmpty + ? Colors.white + : Colors.grey), + onPressed: () { + if (removedLayers.isNotEmpty) { + layers.add(removedLayers.removeLast()); + setState(() {}); + return; + } + if (layers.length <= 1) return; // do not remove image layer + undoLayers.add(layers.removeLast()); + setState(() {}); + }, ), + IconButton( + padding: const EdgeInsets.symmetric(horizontal: 8), + icon: Icon(Icons.redo, + color: undoLayers.isNotEmpty ? Colors.white : Colors.grey), + onPressed: () { + if (undoLayers.isEmpty) return; + + layers.add(undoLayers.removeLast()); + + setState(() {}); + }, + ), + const SizedBox(width: 50) ]; } @@ -159,14 +98,8 @@ class _ImageEditorState extends State { super.initState(); } - double lastScaleFactor = 1, scaleFactor = 1; double widthRatio = 1, heightRatio = 1, pixelRatio = 1; - resetTransformation() { - scaleFactor = 1; - setState(() {}); - } - /// obtain image Uint8List by merging layers Future getMergedImage() async { Uint8List? image; @@ -185,68 +118,36 @@ class _ImageEditorState extends State { @override Widget build(BuildContext context) { - viewportSize = MediaQuery.of(context).size; pixelRatio = MediaQuery.of(context).devicePixelRatio; return Stack(children: [ - GestureDetector( - onScaleUpdate: (details) { - // print(details); - - // move - if (details.pointerCount == 1) { - // print(details.focalPointDelta); - // x += details.focalPointDelta.dx; - // y += details.focalPointDelta.dy; - setState(() {}); - } - - // scale - if (details.pointerCount == 2) { - // print([details.horizontalScale, details.verticalScale]); - if (details.horizontalScale != 1) { - scaleFactor = lastScaleFactor * - math.min(details.horizontalScale, details.verticalScale); + SizedBox( + height: currentImage.height / pixelRatio, + width: currentImage.width / pixelRatio, + child: Screenshot( + controller: screenshotController, + child: LayersViewer( + layers: layers, + onUpdate: () { setState(() {}); - } - } - }, - onScaleEnd: (details) { - lastScaleFactor = scaleFactor; - }, - child: SizedBox( - height: currentImage.height / pixelRatio, - width: currentImage.width / pixelRatio, - child: Screenshot( - controller: screenshotController, - child: LayersViewer( - layers: layers, - onUpdate: () { - setState(() {}); - }, - editable: true, - ), + }, + editable: true, ), ), ), Positioned( - top: 0, + top: 5, left: 0, right: 0, - child: Container( - decoration: BoxDecoration( - color: Colors.black.withAlpha(75), - ), - child: SafeArea( - child: Row( - children: filterActions, - ), + child: SafeArea( + child: Row( + children: filterActions, ), ), ), Positioned( right: 0, - top: 50, + top: 100, child: Container( // color: Colors.black45, alignment: Alignment.bottomCenter, @@ -260,112 +161,77 @@ class _ImageEditorState extends State { // ], ), child: SafeArea( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (widget.textOption != null) - BottomButton( - icon: Icons.text_fields, - onTap: () async { - TextLayerData? layer = await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const TextEditorImage(), - ), - ); + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + BottomButton( + icon: FontAwesomeIcons.font, + onTap: () async { + undoLayers.clear(); + removedLayers.clear(); - if (layer == null) return; + layers.add( + TextLayerData( + text: "Test", + ), + ); - undoLayers.clear(); - removedLayers.clear(); + setState(() {}); + }, + ), + SizedBox(height: 20), + 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, + ), + ); - layers.add(layer); + if (drawing != null) { + undoLayers.clear(); + removedLayers.clear(); - setState(() {}); + layers.add( + ImageLayerData( + image: ImageItem(drawing), + offset: Offset(0, 0), + ), + ); + + setState(() {}); + } + }, + ), + SizedBox(height: 20), + BottomButton( + icon: FontAwesomeIcons.faceGrinWide, + onTap: () async { + EmojiLayerData? layer = await showModalBottomSheet( + context: context, + backgroundColor: Colors.black, + builder: (BuildContext context) { + return const Emojis(); }, - ), - if (widget.brushOption != null) - BottomButton( - icon: Icons.edit, - onTap: () async { - if (widget.brushOption!.translatable) { - var drawing = await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ImageEditorDrawing( - image: currentImage, - options: widget.brushOption!, - ), - ), - ); + ); - if (drawing != null) { - undoLayers.clear(); - removedLayers.clear(); + if (layer == null) return; - layers.add( - ImageLayerData( - image: ImageItem(drawing), - offset: Offset( - -currentImage.width / 4, - -currentImage.height / 4, - ), - ), - ); + undoLayers.clear(); + removedLayers.clear(); + layers.add(layer); - setState(() {}); - } - } else { - resetTransformation(); - var loadingScreen = showLoadingScreen(context); - var mergedImage = await getMergedImage(); - loadingScreen.hide(); - - if (!mounted) return; - - var drawing = await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ImageEditorDrawing( - image: ImageItem(mergedImage!), - options: widget.brushOption!, - ), - ), - ); - - if (drawing != null) { - currentImage.load(drawing); - - setState(() {}); - } - } - }, - ), - if (widget.emojiOption != null) - BottomButton( - icon: FontAwesomeIcons.faceSmile, - onTap: () async { - EmojiLayerData? layer = await showModalBottomSheet( - context: context, - backgroundColor: Colors.black, - builder: (BuildContext context) { - return const Emojies(); - }, - ); - - if (layer == null) return; - - undoLayers.clear(); - removedLayers.clear(); - layers.add(layer); - - setState(() {}); - }, - ), - ], - ), + setState(() {}); + }, + ), + ], ), ), ), @@ -422,15 +288,10 @@ class BottomButton extends StatelessWidget { /// Show image drawing surface over image class ImageEditorDrawing extends StatefulWidget { final ImageItem image; - final o.BrushOption options; const ImageEditorDrawing({ super.key, required this.image, - this.options = const o.BrushOption( - showBackground: true, - translatable: true, - ), }); @override @@ -438,9 +299,8 @@ class ImageEditorDrawing extends StatefulWidget { } class _ImageEditorDrawingState extends State { - Color pickerColor = Colors.white, - currentColor = Colors.white, - currentBackgroundColor = Colors.black; + Color pickerColor = Colors.white, currentColor = Colors.white; + var screenshotController = ScreenshotController(); final control = HandSignatureControl( @@ -452,12 +312,12 @@ class _ImageEditorDrawingState extends State { List undoList = []; bool skipNextEvent = false; - void changeColor(o.BrushColor color) { - currentColor = color.color; - currentBackgroundColor = color.background; + // void changeColor(Colors color) { + // currentColor = color.color; + // currentBackgroundColor = color.background; - setState(() {}); - } + // setState(() {}); + // } @override void initState() { @@ -478,186 +338,156 @@ class _ImageEditorDrawingState extends State { @override Widget build(BuildContext context) { - return Theme( - data: ImageEditor.theme, - child: Scaffold( - appBar: AppBar( - automaticallyImplyLeading: false, - actions: [ - IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), - icon: const Icon(Icons.clear), - onPressed: () { - Navigator.pop(context); - }, - ), - const Spacer(), - IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), - icon: Icon( - Icons.undo, - color: control.paths.isNotEmpty - ? Colors.white - : Colors.white.withAlpha(80), - ), - onPressed: () { - if (control.paths.isEmpty) return; - skipNextEvent = true; - undoList.add(control.paths.last); - control.stepBack(); - setState(() {}); - }, - ), - IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), - icon: Icon( - Icons.redo, - color: undoList.isNotEmpty - ? Colors.white - : Colors.white.withAlpha(80), - ), - onPressed: () { - if (undoList.isEmpty) return; + final colors = [ + Colors.black, + Colors.white, + Colors.blue, + Colors.green, + Colors.pink, + Colors.purple, + Colors.brown, + Colors.indigo, + ]; - control.paths.add(undoList.removeLast()); - setState(() {}); - }, - ), - IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), - icon: const Icon(Icons.check), - onPressed: () async { - if (control.paths.isEmpty) return Navigator.pop(context); - - if (widget.options.translatable) { - var data = await control.toImage( - color: currentColor, - height: widget.image.height, - width: widget.image.width, - ); - - if (!mounted) return; - - return Navigator.pop(context, data!.buffer.asUint8List()); - } - - var loadingScreen = showLoadingScreen(context); - var image = await screenshotController.capture(); - loadingScreen.hide(); - - if (!mounted) return; - - return Navigator.pop(context, image); - }, - ), - ], - ), - body: Screenshot( - controller: screenshotController, - child: Container( - height: MediaQuery.of(context).size.height, - width: MediaQuery.of(context).size.width, - decoration: BoxDecoration( - color: - widget.options.showBackground ? null : currentBackgroundColor, - image: widget.options.showBackground - ? DecorationImage( - image: Image.memory(widget.image.bytes).image, - fit: BoxFit.contain, - ) - : null, - ), - child: HandSignature( - control: control, - color: currentColor, - width: 1.0, - maxWidth: 7.0, - type: SignatureDrawType.shape, - ), - ), - ), - bottomNavigationBar: SafeArea( - child: Container( - height: 80, - decoration: const BoxDecoration( - boxShadow: [ - BoxShadow(blurRadius: 2), - ], - ), - child: ListView( - scrollDirection: Axis.horizontal, - children: [ - ColorButton( - color: Colors.yellow, - onTap: (color) { - showModalBottomSheet( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topRight: Radius.circular(10), - topLeft: Radius.circular(10), - ), - ), - context: context, - backgroundColor: Colors.transparent, - builder: (context) { - return Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.black87, - borderRadius: BorderRadius.only( - topLeft: Radius.circular( - MediaQuery.of(context).size.width / 2, - ), - topRight: Radius.circular( - MediaQuery.of(context).size.width / 2, - ), - ), - ), - child: SingleChildScrollView( - child: ColorPicker( - wheelDiameter: - MediaQuery.of(context).size.width - 64, - color: currentColor, - pickersEnabled: const { - ColorPickerType.both: false, - ColorPickerType.primary: false, - ColorPickerType.accent: false, - ColorPickerType.bw: false, - ColorPickerType.custom: false, - ColorPickerType.customSecondary: false, - ColorPickerType.wheel: true, - }, - enableShadesSelection: false, - onColorChanged: (color) { - currentColor = color; - setState(() {}); - }, - ), - ), - ); - }, - ); - }, + return Scaffold( + backgroundColor: Colors.red.withAlpha(0), + body: SafeArea( + child: Stack( + fit: StackFit.expand, + children: [ + Positioned.fill( + top: 0, + child: Container( + height: 600, + width: 300, + decoration: BoxDecoration( + color: const Color.fromARGB(0, 210, 7, 7), ), - for (var color in widget.options.colors) - ColorButton( - color: color.color, - onTap: (color) { - currentColor = color; + // child: Container(), + child: Screenshot( + controller: screenshotController, + // image: widget.options.showBackground + // ? DecorationImage( + // image: Image.memory(widget.image.bytes).image, + // fit: BoxFit.contain, + // ) + // : null, + // child: Container(), + child: HandSignature( + control: control, + color: currentColor, + width: 1.0, + maxWidth: 7.0, + type: SignatureDrawType.shape, + ), + ), + ), + ), + Positioned( + top: 100, + right: 50, + child: Column( + children: [ + IconButton( + padding: const EdgeInsets.symmetric(horizontal: 8), + icon: const Icon(Icons.clear), + onPressed: () { + Navigator.pop(context); + }, + ), + IconButton( + padding: const EdgeInsets.symmetric(horizontal: 8), + icon: Icon( + Icons.undo, + color: control.paths.isNotEmpty + ? Colors.white + : Colors.white.withAlpha(80), + ), + onPressed: () { + if (control.paths.isEmpty) return; + skipNextEvent = true; + undoList.add(control.paths.last); + control.stepBack(); setState(() {}); }, - isSelected: color.color == currentColor, ), - ], + IconButton( + padding: const EdgeInsets.symmetric(horizontal: 8), + icon: Icon( + Icons.redo, + color: undoList.isNotEmpty + ? Colors.white + : Colors.white.withAlpha(80), + ), + onPressed: () { + if (undoList.isEmpty) return; + + control.paths.add(undoList.removeLast()); + setState(() {}); + }, + ), + IconButton( + padding: const EdgeInsets.symmetric(horizontal: 8), + icon: const Icon(Icons.check), + onPressed: () async { + if (control.paths.isEmpty) return Navigator.pop(context); + + var data = await control.toImage( + color: currentColor, + height: widget.image.height, + width: widget.image.width, + ); + + if (!mounted) return; + + return Navigator.pop(context, data!.buffer.asUint8List()); + + // var loadingScreen = showLoadingScreen(context); + // var image = await screenshotController.capture(); + // loadingScreen.hide(); + + // if (!mounted) return; + + // return Navigator.pop(context, image); + }, + ), + ], + ), ), - ), + Positioned( + right: 0, + top: 50, + child: Container( + child: Container( + // height: 80, + padding: EdgeInsets.symmetric(vertical: 10), + decoration: BoxDecoration( + color: const Color.fromARGB(130, 0, 0, 0), + borderRadius: BorderRadius.all(Radius.circular(10)), + ), + child: Column( + children: [ + for (var color in colors) + ColorButton( + color: color, + onTap: (color) { + currentColor = color; + setState(() {}); + }, + isSelected: color == currentColor, + ), + ], + ), + ), + ), + ), + ], ), ), ); } } -/// Button used in bottomNavigationBar in ImageEditorDrawing class ColorButton extends StatelessWidget { final Color color; final Function(Color) onTap; @@ -677,15 +507,15 @@ class ColorButton extends StatelessWidget { onTap(color); }, child: Container( - height: 34, - width: 34, - margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 23), + height: 17, + width: 17, + margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(16), border: Border.all( color: isSelected ? Colors.white : Colors.white54, - width: isSelected ? 3 : 1, + width: isSelected ? 2 : 1, ), ), ), diff --git a/lib/src/components/image_editor/layers/background_blur_layer.dart b/lib/src/components/image_editor/layers/background_blur_layer.dart deleted file mode 100755 index 56f975e..0000000 --- a/lib/src/components/image_editor/layers/background_blur_layer.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/material.dart'; -import 'package:twonly/src/components/image_editor/data/layer.dart'; - -/// Image layer to blur background using BackdropFilter -class BackgroundBlurLayer extends StatefulWidget { - final BackgroundBlurLayerData layerData; - final VoidCallback? onUpdate; - final bool editable; - - const BackgroundBlurLayer({ - super.key, - required this.layerData, - this.onUpdate, - this.editable = false, - }); - - @override - State createState() => _BackgroundBlurLayerState(); -} - -class _BackgroundBlurLayerState extends State { - @override - Widget build(BuildContext context) { - return Positioned.fill( - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: widget.layerData.radius, - sigmaY: widget.layerData.radius, - ), - child: Container( - color: widget.layerData.color - .withAlpha((widget.layerData.opacity * 100).toInt()), - ), - ), - ); - } -} diff --git a/lib/src/components/image_editor/layers/emoji_layer.dart b/lib/src/components/image_editor/layers/emoji_layer.dart index 77a6b9d..e966a40 100755 --- a/lib/src/components/image_editor/layers/emoji_layer.dart +++ b/lib/src/components/image_editor/layers/emoji_layer.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:twonly/src/components/image_editor/data/layer.dart'; -import 'package:twonly/src/components/image_editor/image_editor.dart'; -import 'package:twonly/src/components/image_editor/modules/emoji_layer_overlay.dart'; /// Emoji layer class EmojiLayer extends StatefulWidget { @@ -33,30 +31,7 @@ class _EmojiLayerState extends State { left: widget.layerData.offset.dx, top: widget.layerData.offset.dy, child: GestureDetector( - onTap: widget.editable - ? () { - showModalBottomSheet( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topRight: Radius.circular(10), - topLeft: Radius.circular(10), - ), - ), - context: context, - backgroundColor: Colors.transparent, - builder: (context) { - return EmojiLayerOverlay( - index: layers.indexOf(widget.layerData), - layer: widget.layerData, - onUpdate: () { - if (widget.onUpdate != null) widget.onUpdate!(); - setState(() {}); - }, - ); - }, - ); - } - : null, + onTap: widget.editable ? () {} : null, onScaleUpdate: widget.editable ? (detail) { if (detail.pointerCount == 1) { diff --git a/lib/src/components/image_editor/layers/image_layer.dart b/lib/src/components/image_editor/layers/image_layer.dart index e7590ee..22d7207 100755 --- a/lib/src/components/image_editor/layers/image_layer.dart +++ b/lib/src/components/image_editor/layers/image_layer.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:twonly/src/components/image_editor/data/layer.dart'; -import 'package:twonly/src/components/image_editor/image_editor.dart'; -import 'package:twonly/src/components/image_editor/modules/image_layer_overlay.dart'; /// Image layer that can be used to add overlay images and drawings class ImageLayer extends StatefulWidget { @@ -29,73 +27,11 @@ class _ImageLayerState extends State { initialSize = widget.layerData.size; initialRotation = widget.layerData.rotation; - return Positioned( - left: widget.layerData.offset.dx, - top: widget.layerData.offset.dy, - child: GestureDetector( - onTap: widget.editable - ? () { - showModalBottomSheet( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topRight: Radius.circular(10), - topLeft: Radius.circular(10), - ), - ), - context: context, - backgroundColor: Colors.transparent, - builder: (context) { - return ImageLayerOverlay( - index: layers.indexOf(widget.layerData), - layerData: widget.layerData, - onUpdate: () { - if (widget.onUpdate != null) widget.onUpdate!(); - setState(() {}); - }, - ); - }, - ); - } - : null, - onScaleUpdate: widget.editable - ? (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.scale = detail.scale; - } - - setState(() {}); - } - : null, - child: Transform( - transform: Matrix4( - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 1, - 0, - 1 / widget.layerData.scale, - ), - child: SizedBox( - width: widget.layerData.image.width.toDouble(), - height: widget.layerData.image.height.toDouble(), - child: Image.memory(widget.layerData.image.bytes), - ), - ), + 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/text_layer.dart b/lib/src/components/image_editor/layers/text_layer.dart index d5ca3e8..6cf47ed 100755 --- a/lib/src/components/image_editor/layers/text_layer.dart +++ b/lib/src/components/image_editor/layers/text_layer.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:twonly/src/components/image_editor/data/layer.dart'; -import 'package:twonly/src/components/image_editor/image_editor.dart'; -import 'package:twonly/src/components/image_editor/modules/text_layer_overlay.dart'; /// Text layer class TextLayer extends StatefulWidget { @@ -20,79 +18,38 @@ class TextLayer extends StatefulWidget { } class _TextViewState extends State { - double initialSize = 0; double initialRotation = 0; @override Widget build(BuildContext context) { - initialSize = widget.layerData.size; - initialRotation = widget.layerData.rotation; - return Positioned( - left: widget.layerData.offset.dx, + left: 0, + right: 0, top: widget.layerData.offset.dy, child: GestureDetector( - onTap: widget.editable - ? () { - showModalBottomSheet( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topRight: Radius.circular(10), - topLeft: Radius.circular(10), - ), - ), - context: context, - backgroundColor: Colors.transparent, - builder: (context) { - return TextLayerOverlay( - index: layers.indexOf(widget.layerData), - layer: widget.layerData, - onUpdate: () { - if (widget.onUpdate != null) widget.onUpdate!(); - setState(() {}); - }, - ); - }, - ); - } - : null, + onTap: widget.editable ? () {} : null, onScaleUpdate: widget.editable ? (detail) { if (detail.pointerCount == 1) { widget.layerData.offset = Offset( - widget.layerData.offset.dx + detail.focalPointDelta.dx, + 0, widget.layerData.offset.dy + detail.focalPointDelta.dy, ); - } else if (detail.pointerCount == 2) { - widget.layerData.size = - initialSize + detail.scale * (detail.scale > 1 ? 1 : -1); - - // print('angle'); - // print(detail.rotation); - widget.layerData.rotation = detail.rotation; } setState(() {}); } : null, - child: Transform.rotate( - angle: widget.layerData.rotation, - child: Container( - padding: const EdgeInsets.all(64), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: widget.layerData.background - .withOpacity(widget.layerData.backgroundOpacity), - borderRadius: BorderRadius.circular(8), - ), - child: Text( - widget.layerData.text.toString(), - textAlign: widget.layerData.align, - style: TextStyle( - color: widget.layerData.color, - fontSize: widget.layerData.size, - ), - ), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: Colors.black.withAlpha(100), + ), + child: Text( + widget.layerData.text.toString(), + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontSize: 20, ), ), ), diff --git a/lib/src/components/image_editor/layers_viewer.dart b/lib/src/components/image_editor/layers_viewer.dart index e443a47..985e684 100644 --- a/lib/src/components/image_editor/layers_viewer.dart +++ b/lib/src/components/image_editor/layers_viewer.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:twonly/src/components/image_editor/data/layer.dart'; -import 'package:twonly/src/components/image_editor/layers/background_blur_layer.dart'; import 'package:twonly/src/components/image_editor/layers/background_layer.dart'; import 'package:twonly/src/components/image_editor/layers/emoji_layer.dart'; import 'package:twonly/src/components/image_editor/layers/image_layer.dart'; @@ -42,15 +41,6 @@ class LayersViewer extends StatelessWidget { ); } - // Background blur layer - if (layerItem is BackgroundBlurLayerData && layerItem.radius > 0) { - return BackgroundBlurLayer( - layerData: layerItem, - onUpdate: onUpdate, - editable: editable, - ); - } - // Emoji layer if (layerItem is EmojiLayerData) { return EmojiLayer( diff --git a/lib/src/components/image_editor/loading_screen.dart b/lib/src/components/image_editor/loading_screen.dart deleted file mode 100644 index 098a76c..0000000 --- a/lib/src/components/image_editor/loading_screen.dart +++ /dev/null @@ -1,131 +0,0 @@ -import 'package:flutter/material.dart'; - -LoadingScreenHandler showLoadingScreen( - BuildContext context, { - String? text, - Color? color, -}) { - var handler = LoadingScreenHandler( - color: color, - text: text, - context: context, - ); - - showDialog( - context: context, - builder: (BuildContext context) => LoadingScreenBody( - handler: handler, - ), - ); - - return handler; -} - -class LoadingScreen { - final Color? color; - final GlobalKey globalKey; - - LoadingScreen({ - this.color, - required this.globalKey, - }); - - LoadingScreenHandler show({ - String? text, - }) { - return showLoadingScreen( - globalKey.currentContext!, - text: text, - color: color, - ); - } -} - -@protected -class LoadingScreenHandler { - String? id, text; - Color? color; - double? _progress; - late void Function() refresh; - BuildContext context; - bool expired = false; - - LoadingScreenHandler({ - required this.context, - this.id, - this.color, - this.text, - double? progress, - void Function()? refresh, - }) { - this.refresh = refresh ?? () {}; - this.progress = progress; - } - - double? get progress => _progress; - set progress(double? value) { - _progress = value; - refresh(); - } - - hide() { - if (expired) return; - - expired = true; - - Navigator.pop(context); - } -} - -@protected -class LoadingScreenBody extends StatefulWidget { - final LoadingScreenHandler handler; - const LoadingScreenBody({super.key, required this.handler}); - - @override - State createState() => _LoadingScreenBodyState(); -} - -class _LoadingScreenBodyState extends State { - @override - void initState() { - widget.handler.refresh = () { - if (mounted) { - setState(() {}); - } - }; - - super.initState(); - } - - @override - Widget build(BuildContext context) { - widget.handler.context = context; - - return Scaffold( - backgroundColor: const Color.fromRGBO(0, 0, 0, 0), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - CircularProgressIndicator( - color: widget.handler.color ?? Colors.white, - value: widget.handler.progress, - semanticsLabel: widget.handler.text, - ), - if (widget.handler.progress != null) const SizedBox(height: 8), - if (widget.handler.progress != null) - Text( - '${(widget.handler.progress! * 100).toStringAsFixed(2)}%', - style: TextStyle( - color: widget.handler.color ?? Colors.white, - fontSize: 12, - ), - ), - ], - ), - ), - ); - } -} diff --git a/lib/src/components/image_editor/modules/all_emojis.dart b/lib/src/components/image_editor/modules/all_emojis.dart index f519f5a..3a9ace1 100755 --- a/lib/src/components/image_editor/modules/all_emojis.dart +++ b/lib/src/components/image_editor/modules/all_emojis.dart @@ -1,16 +1,15 @@ import 'package:flutter/material.dart'; import 'package:twonly/src/components/image_editor/data/data.dart'; import 'package:twonly/src/components/image_editor/data/layer.dart'; -import 'package:twonly/src/components/image_editor/image_editor.dart'; -class Emojies extends StatefulWidget { - const Emojies({super.key}); +class Emojis extends StatefulWidget { + const Emojis({super.key}); @override - createState() => _EmojiesState(); + createState() => _EmojisState(); } -class _EmojiesState extends State { +class _EmojisState extends State { @override Widget build(BuildContext context) { return SingleChildScrollView( @@ -35,7 +34,7 @@ class _EmojiesState extends State { const SizedBox(height: 16), Row(mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - i18n('Select Emoji'), + ('Select Emoji'), style: const TextStyle(color: Colors.white), ), ]), diff --git a/lib/src/components/image_editor/modules/color_pickers_slider.dart b/lib/src/components/image_editor/modules/color_pickers_slider.dart deleted file mode 100755 index 9cd695b..0000000 --- a/lib/src/components/image_editor/modules/color_pickers_slider.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:twonly/src/components/image_editor/image_editor.dart'; -import 'colors_picker.dart'; - -class ColorPickersSlider extends StatefulWidget { - const ColorPickersSlider({super.key}); - - @override - createState() => _ColorPickersSliderState(); -} - -class _ColorPickersSliderState extends State { - @override - Widget build(BuildContext context) { - return Container( - decoration: const BoxDecoration( - borderRadius: BorderRadius.only( - topRight: Radius.circular(10), topLeft: Radius.circular(10)), - ), - padding: const EdgeInsets.all(20), - height: 240, - child: Column( - children: [ - Center( - child: Text( - i18n('Slider Filter Color').toUpperCase(), - style: const TextStyle(color: Colors.white), - ), - ), - const SizedBox(height: 20), - Text(i18n('Slider Color'), - style: const TextStyle(color: Colors.white)), - // const SizedBox(height: 10), - Row( - children: [ - Expanded( - child: BarColorPicker( - width: 300, - thumbColor: Colors.white, - cornerRadius: 10, - pickMode: PickMode.color, - colorListener: (int value) { - setState(() { - // currentColor = Color(value); - }); - }, - ), - ), - TextButton( - onPressed: () {}, - child: Text(i18n('Reset'), - style: const TextStyle(color: Colors.white)), - ) - ], - ), - const SizedBox(height: 5), - Text(i18n('Slider Opicity'), - style: const TextStyle(color: Colors.white)), - const SizedBox(height: 10), - Row(children: [ - Expanded( - child: Slider( - value: 0.1, - min: 0.0, - max: 1.0, - onChanged: (v) {}, - ), - ), - TextButton( - onPressed: () {}, - child: Text(i18n('Reset'), - style: const TextStyle(color: Colors.white)), - ) - ]), - ], - ), - ); - } -} diff --git a/lib/src/components/image_editor/modules/colors_picker.dart b/lib/src/components/image_editor/modules/colors_picker.dart deleted file mode 100755 index fdf59cc..0000000 --- a/lib/src/components/image_editor/modules/colors_picker.dart +++ /dev/null @@ -1,353 +0,0 @@ -import 'dart:math'; -import 'package:flutter/material.dart'; - -enum PickMode { - color, - grey, -} - -/// A listener which receives an color in int representation. as used -/// by [BarColorPicker.colorListener] and [CircleColorPicker.colorListener]. -typedef ColorListener = void Function(int value); - -/// Constant color of thumb shadow -const _kThumbShadowColor = Color(0x44000000); - -/// A padding used to calculate bar height(thumbRadius * 2 - kBarPadding). -const _kBarPadding = 4; - -/// A bar color picker -class BarColorPicker extends StatefulWidget { - /// mode enum of pick a normal color or pick a grey color - final PickMode pickMode; - - /// width of bar, if this widget is horizontal, than - /// bar width is this value, if this widget is vertical - /// bar height is this value - final double width; - - /// A listener receives color pick events. - final ColorListener colorListener; - - /// corner radius of the picker bar, for each corners - final double cornerRadius; - - /// specifies the bar orientation - final bool horizontal; - - /// thumb fill color - final Color thumbColor; - - /// radius of thumb - final double thumbRadius; - - /// initial color of this color picker. - final Color initialColor; - - const BarColorPicker({ - super.key, - this.pickMode = PickMode.color, - this.horizontal = true, - this.width = 200, - this.cornerRadius = 0.0, - this.thumbRadius = 8, - this.initialColor = const Color(0xffff0000), - this.thumbColor = Colors.black, - required this.colorListener, - }); - - @override - createState() => _BarColorPickerState(); -} - -class _BarColorPickerState extends State { - double percent = 0.0; - late List colors; - late double barWidth, barHeight; - - @override - void initState() { - super.initState(); - if (widget.horizontal) { - barWidth = widget.width; - barHeight = widget.thumbRadius * 2 - _kBarPadding; - } else { - barWidth = widget.thumbRadius * 2 - _kBarPadding; - barHeight = widget.width; - } - switch (widget.pickMode) { - case PickMode.color: - colors = const [ - Color(0xffff0000), - Color(0xffffff00), - Color(0xff00ff00), - Color(0xff00ffff), - Color(0xff0000ff), - Color(0xffff00ff), - Color(0xffff0000) - ]; - break; - case PickMode.grey: - colors = const [Color(0xff000000), Color(0xffffffff)]; - break; - } - percent = HSVColor.fromColor(widget.initialColor).hue / 360; - } - - @override - Widget build(BuildContext context) { - final thumbRadius = widget.thumbRadius; - final horizontal = widget.horizontal; - - double? thumbLeft, thumbTop; - if (horizontal) { - thumbLeft = barWidth * percent; - } else { - thumbTop = barHeight * percent; - } - // build thumb - var thumb = Positioned( - left: thumbLeft, - top: thumbTop, - child: Container( - padding: EdgeInsets.zero, - width: thumbRadius * 2, - height: thumbRadius * 2, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(thumbRadius), - boxShadow: const [ - BoxShadow( - color: _kThumbShadowColor, - spreadRadius: 2, - blurRadius: 3, - ) - ], - color: widget.thumbColor, - ), - ), - ); - - // build frame - double frameWidth, frameHeight; - if (horizontal) { - frameWidth = barWidth + thumbRadius * 2; - frameHeight = thumbRadius * 2; - } else { - frameWidth = thumbRadius * 2; - frameHeight = barHeight + thumbRadius * 2; - } - Widget frame = SizedBox(width: frameWidth, height: frameHeight); - - // build content - Gradient gradient; - double left, top; - if (horizontal) { - gradient = LinearGradient(colors: colors); - left = thumbRadius; - top = (thumbRadius * 2 - barHeight) / 2; - } else { - gradient = LinearGradient( - colors: colors, - begin: Alignment.topCenter, - end: Alignment.bottomCenter); - left = (thumbRadius * 2 - barWidth) / 2; - top = thumbRadius; - } - var content = Positioned( - left: left, - top: top, - child: Container( - padding: EdgeInsets.zero, - width: barWidth, - height: barHeight, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(widget.cornerRadius), - gradient: gradient, - ), - child: const Text(''), - ), - ); - - return GestureDetector( - onPanDown: (details) => handleTouch(details.globalPosition, context), - onPanStart: (details) => handleTouch(details.globalPosition, context), - onPanUpdate: (details) => handleTouch(details.globalPosition, context), - child: Stack(children: [frame, content, thumb]), - ); - } - - /// calculate colors picked from palette and update our states. - void handleTouch(Offset globalPosition, BuildContext context) { - var box = context.findRenderObject() as RenderBox; - var localPosition = box.globalToLocal(globalPosition); - double percent; - if (widget.horizontal) { - percent = (localPosition.dx - widget.thumbRadius) / barWidth; - } else { - percent = (localPosition.dy - widget.thumbRadius) / barHeight; - } - percent = min(max(0.0, percent), 1.0); - setState(() { - this.percent = percent; - }); - switch (widget.pickMode) { - case PickMode.color: - var color = HSVColor.fromAHSV(1.0, percent * 360, 1.0, 1.0).toColor(); - widget.colorListener(color.value); - break; - case PickMode.grey: - final channel = (0xff * percent).toInt(); - widget.colorListener( - Color.fromARGB(0xff, channel, channel, channel).value); - break; - } - } -} - -/// A circle palette color picker. -class CircleColorPicker extends StatefulWidget { - // radius of the color palette, note that radius * 2 is not the final - // width of this widget, instead is (radius + thumbRadius) * 2. - final double radius; - - /// thumb fill color. - final Color thumbColor; - - /// radius of thumb. - final double thumbRadius; - - /// A listener receives color pick events. - final ColorListener colorListener; - - /// initial color of this color picker. - final Color initialColor; - - const CircleColorPicker({ - super.key, - this.radius = 120, - this.initialColor = const Color(0xffff0000), - this.thumbColor = Colors.black, - this.thumbRadius = 8, - required this.colorListener, - }); - - @override - State createState() { - return _CircleColorPickerState(); - } -} - -class _CircleColorPickerState extends State { - static const List colors = [ - Color(0xffff0000), - Color(0xffffff00), - Color(0xff00ff00), - Color(0xff00ffff), - Color(0xff0000ff), - Color(0xffff00ff), - Color(0xffff0000) - ]; - - late double thumbDistanceToCenter; - late double thumbRadians; - - @override - void initState() { - super.initState(); - thumbDistanceToCenter = widget.radius; - final hue = HSVColor.fromColor(widget.initialColor).hue; - thumbRadians = degreesToRadians(270 - hue); - } - - @override - Widget build(BuildContext context) { - final radius = widget.radius; - final thumbRadius = widget.thumbRadius; - - // compute thumb center coordinate - final thumbCenterX = radius + thumbDistanceToCenter * sin(thumbRadians); - final thumbCenterY = radius + thumbDistanceToCenter * cos(thumbRadians); - - // build thumb widget - Widget thumb = Positioned( - child: Positioned( - left: thumbCenterX, - top: thumbCenterY, - child: Container( - padding: EdgeInsets.zero, - width: thumbRadius * 2, - height: thumbRadius * 2, - decoration: BoxDecoration( - boxShadow: const [ - BoxShadow( - color: _kThumbShadowColor, - spreadRadius: 2, - blurRadius: 3, - ) - ], - borderRadius: BorderRadius.circular(thumbRadius), - color: widget.thumbColor, - ), - ), - ), - ); - - return GestureDetector( - behavior: HitTestBehavior.opaque, - onPanDown: (details) => handleTouch(details.globalPosition, context), - onPanStart: (details) => handleTouch(details.globalPosition, context), - onPanUpdate: (details) => handleTouch(details.globalPosition, context), - child: Stack( - children: [ - SizedBox( - width: (radius + thumbRadius) * 2, - height: (radius + thumbRadius) * 2), - Positioned( - left: thumbRadius, - top: thumbRadius, - child: Container( - padding: EdgeInsets.zero, - width: radius * 2, - height: radius * 2, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(radius), - gradient: const SweepGradient(colors: colors), - ), - child: const Text(''), - ), - ), - thumb - ], - ), - ); - } - - /// calculate colors picked from palette and update our states. - void handleTouch(Offset globalPosition, BuildContext context) { - var box = context.findRenderObject() as RenderBox; - var localPosition = box.globalToLocal(globalPosition); - final centerX = box.size.width / 2; - final centerY = box.size.height / 2; - final deltaX = localPosition.dx - centerX; - final deltaY = localPosition.dy - centerY; - final distanceToCenter = sqrt(deltaX * deltaX + deltaY * deltaY); - var theta = atan2(deltaX, deltaY); - var degree = 270 - radiansToDegrees(theta); - if (degree < 0) degree = 360 + degree; - widget.colorListener(HSVColor.fromAHSV(1, degree, 1, 1).toColor().value); - setState(() { - thumbDistanceToCenter = min(distanceToCenter, widget.radius); - thumbRadians = theta; - }); - } - - /// convert an angle value from radian to degree representation. - double radiansToDegrees(double radians) { - return (radians + pi) / pi * 180; - } - - /// convert an angle value from degree to radian representation. - double degreesToRadians(double degrees) { - return degrees / 180 * pi - pi; - } -} diff --git a/lib/src/components/image_editor/modules/emoji_layer_overlay.dart b/lib/src/components/image_editor/modules/emoji_layer_overlay.dart deleted file mode 100755 index 1e2a70b..0000000 --- a/lib/src/components/image_editor/modules/emoji_layer_overlay.dart +++ /dev/null @@ -1,91 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:twonly/src/components/image_editor/data/layer.dart'; -import 'package:twonly/src/components/image_editor/image_editor.dart'; - -class EmojiLayerOverlay extends StatefulWidget { - final int index; - final EmojiLayerData layer; - final Function onUpdate; - - const EmojiLayerOverlay({ - super.key, - required this.layer, - required this.index, - required this.onUpdate, - }); - - @override - createState() => _EmojiLayerOverlayState(); -} - -class _EmojiLayerOverlayState extends State { - double slider = 0.0; - - @override - void initState() { - // slider = widget.sizevalue; - - super.initState(); - } - - @override - Widget build(BuildContext context) { - return Container( - height: 200, - decoration: const BoxDecoration( - color: Colors.black87, - borderRadius: BorderRadius.only( - topRight: Radius.circular(10), topLeft: Radius.circular(10)), - ), - child: Column( - children: [ - const SizedBox(height: 10), - Center( - child: Text( - i18n('Size Adjust').toUpperCase(), - style: const TextStyle(color: Colors.white), - ), - ), - Slider( - activeColor: Colors.white, - inactiveColor: Colors.grey, - value: widget.layer.size, - min: 0.0, - max: 100.0, - onChangeEnd: (v) { - setState(() { - widget.layer.size = v.toDouble(); - widget.onUpdate(); - }); - }, - onChanged: (v) { - setState(() { - slider = v; - // print(v.toDouble()); - widget.layer.size = v.toDouble(); - widget.onUpdate(); - }); - }), - const SizedBox(height: 10), - Row(children: [ - Expanded( - child: TextButton( - onPressed: () { - removedLayers.add(layers.removeAt(widget.index)); - Navigator.pop(context); - widget.onUpdate(); - // back(context); - // setState(() {}); - }, - child: Text( - i18n('Remove'), - style: const TextStyle(color: Colors.white), - ), - ), - ), - ]), - ], - ), - ); - } -} diff --git a/lib/src/components/image_editor/modules/image_layer_overlay.dart b/lib/src/components/image_editor/modules/image_layer_overlay.dart deleted file mode 100755 index 284094d..0000000 --- a/lib/src/components/image_editor/modules/image_layer_overlay.dart +++ /dev/null @@ -1,92 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:twonly/src/components/image_editor/data/layer.dart'; -import 'package:twonly/src/components/image_editor/image_editor.dart'; - -class ImageLayerOverlay extends StatefulWidget { - final int index; - final ImageLayerData layerData; - final Function onUpdate; - - const ImageLayerOverlay({ - super.key, - required this.layerData, - required this.index, - required this.onUpdate, - }); - - @override - createState() => _ImageLayerOverlayState(); -} - -class _ImageLayerOverlayState extends State { - double slider = 0.0; - - @override - void initState() { - // slider = widget.sizevalue; - - super.initState(); - } - - @override - Widget build(BuildContext context) { - return Container( - height: 200, - decoration: const BoxDecoration( - color: Colors.black87, - borderRadius: BorderRadius.only( - topRight: Radius.circular(10), topLeft: Radius.circular(10)), - ), - child: Column( - children: [ - const SizedBox(height: 10), - Center( - child: Text( - i18n('Size Adjust').toUpperCase(), - style: const TextStyle(color: Colors.white), - ), - ), - Slider( - activeColor: Colors.white, - inactiveColor: Colors.grey, - value: widget.layerData.scale, - min: 0, - max: 2, - divisions: 100, - onChangeEnd: (v) { - setState(() { - widget.layerData.scale = v.toDouble(); - widget.onUpdate(); - }); - }, - onChanged: (v) { - setState(() { - slider = v; - // print(v.toDouble()); - widget.layerData.scale = v.toDouble(); - widget.onUpdate(); - }); - }), - const SizedBox(height: 10), - Row(children: [ - Expanded( - child: TextButton( - onPressed: () { - removedLayers.add(layers.removeAt(widget.index)); - Navigator.pop(context); - widget.onUpdate(); - // back(context); - // setState(() {}); - }, - child: Text( - i18n('Remove'), - style: const TextStyle(color: Colors.white), - ), - ), - ), - ]), - ], - ), - ); - } -} diff --git a/lib/src/components/image_editor/modules/text.dart b/lib/src/components/image_editor/modules/text.dart deleted file mode 100755 index e2ccb1c..0000000 --- a/lib/src/components/image_editor/modules/text.dart +++ /dev/null @@ -1,110 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:twonly/src/components/image_editor/data/layer.dart'; -import 'package:twonly/src/components/image_editor/image_editor.dart'; - -class TextEditorImage extends StatefulWidget { - const TextEditorImage({super.key}); - - @override - createState() => _TextEditorImageState(); -} - -class _TextEditorImageState extends State { - TextEditingController name = TextEditingController(); - Color currentColor = Colors.white; - double slider = 32.0; - TextAlign align = TextAlign.left; - - @override - Widget build(BuildContext context) { - var size = MediaQuery.of(context).size; - - return Theme( - data: ThemeData.dark(), - child: Scaffold( - appBar: AppBar( - actions: [ - IconButton( - icon: Icon(FontAwesomeIcons.alignLeft, - color: align == TextAlign.left - ? Colors.white - : Colors.white.withAlpha(80)), - onPressed: () { - setState(() { - align = TextAlign.left; - }); - }, - ), - IconButton( - icon: Icon(FontAwesomeIcons.alignCenter, - color: align == TextAlign.center - ? Colors.white - : Colors.white.withAlpha(80)), - onPressed: () { - setState(() { - align = TextAlign.center; - }); - }, - ), - IconButton( - icon: Icon(FontAwesomeIcons.alignRight, - color: align == TextAlign.right - ? Colors.white - : Colors.white.withAlpha(80)), - onPressed: () { - setState(() { - align = TextAlign.right; - }); - }, - ), - IconButton( - icon: const Icon(Icons.check), - onPressed: () { - Navigator.pop( - context, - TextLayerData( - background: Colors.transparent, - text: name.text, - color: currentColor, - size: slider.toDouble(), - align: align, - ), - ); - }, - color: Colors.white, - padding: const EdgeInsets.all(15), - ) - ], - ), - body: SafeArea( - child: SingleChildScrollView( - child: Column(children: [ - SizedBox( - height: size.height / 2.2, - child: TextField( - controller: name, - decoration: InputDecoration( - border: InputBorder.none, - contentPadding: const EdgeInsets.all(10), - hintText: i18n('Insert Your Message'), - hintStyle: const TextStyle(color: Colors.white), - alignLabelWithHint: true, - ), - scrollPadding: const EdgeInsets.all(20.0), - keyboardType: TextInputType.multiline, - minLines: 5, - maxLines: 99999, - style: TextStyle( - color: currentColor, - ), - autofocus: true, - ), - ), - ]), - ), - ), - ), - ); - } -} diff --git a/lib/src/components/image_editor/modules/text_layer_overlay.dart b/lib/src/components/image_editor/modules/text_layer_overlay.dart deleted file mode 100755 index 6f25093..0000000 --- a/lib/src/components/image_editor/modules/text_layer_overlay.dart +++ /dev/null @@ -1,242 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:twonly/src/components/image_editor/data/layer.dart'; -import 'package:twonly/src/components/image_editor/image_editor.dart'; -import 'colors_picker.dart'; - -class TextLayerOverlay extends StatefulWidget { - final int index; - final TextLayerData layer; - final Function onUpdate; - - const TextLayerOverlay({ - super.key, - required this.layer, - required this.index, - required this.onUpdate, - }); - - @override - createState() => _TextLayerOverlayState(); -} - -class _TextLayerOverlayState extends State { - double slider = 0.0; - - @override - void initState() { - // slider = widget.sizevalue; - - super.initState(); - } - - @override - Widget build(BuildContext context) { - return Container( - height: 450, - decoration: const BoxDecoration( - color: Colors.black87, - borderRadius: BorderRadius.only( - topRight: Radius.circular(10), - topLeft: Radius.circular(10), - ), - ), - child: Column( - children: [ - const SizedBox(height: 10), - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - ), - child: - Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Container( - padding: const EdgeInsets.only(left: 16), - child: Text( - i18n('Size'), - style: const TextStyle(color: Colors.white), - ), - ), - Row(children: [ - const SizedBox(width: 8), - Expanded( - child: Slider( - thumbColor: Colors.white, - value: widget.layer.size, - min: 0.0, - max: 100.0, - onChangeEnd: (v) { - setState(() { - widget.layer.size = v.toDouble(); - widget.onUpdate(); - }); - }, - onChanged: (v) { - setState(() { - slider = v; - // print(v.toDouble()); - widget.layer.size = v.toDouble(); - widget.onUpdate(); - }); - }, - ), - ), - TextButton( - onPressed: () { - setState(() { - widget.layer.backgroundOpacity = 0.5; - widget.onUpdate(); - }); - }, - child: Text( - i18n('Reset'), - style: const TextStyle(color: Colors.white), - ), - ), - const SizedBox(width: 16), - ]), - const SizedBox(height: 20), - Container( - padding: const EdgeInsets.only(left: 16), - child: Text( - i18n('Color'), - style: const TextStyle(color: Colors.white), - ), - ), - Row(children: [ - const SizedBox(width: 16), - Expanded( - child: BarColorPicker( - width: 300, - thumbColor: Colors.white, - initialColor: widget.layer.color, - cornerRadius: 10, - pickMode: PickMode.color, - colorListener: (int value) { - setState(() { - widget.layer.color = Color(value); - widget.onUpdate(); - }); - }, - ), - ), - TextButton( - onPressed: () { - setState(() { - widget.layer.color = Colors.black; - widget.onUpdate(); - }); - }, - child: Text(i18n('Reset'), - style: const TextStyle(color: Colors.white)), - ), - const SizedBox(width: 16), - ]), - const SizedBox(height: 20), - Container( - padding: const EdgeInsets.only(left: 16), - child: Text( - i18n('Background Color'), - style: const TextStyle(color: Colors.white), - ), - ), - Row(children: [ - const SizedBox(width: 16), - Expanded( - child: BarColorPicker( - width: 300, - initialColor: widget.layer.background, - thumbColor: Colors.white, - cornerRadius: 10, - pickMode: PickMode.color, - colorListener: (int value) { - setState(() { - widget.layer.background = Color(value); - if (widget.layer.backgroundOpacity == 0) { - widget.layer.backgroundOpacity = 0.5; - } - - widget.onUpdate(); - }); - }, - ), - ), - TextButton( - onPressed: () { - setState(() { - widget.layer.background = Colors.transparent; - widget.layer.backgroundOpacity = 0; - widget.onUpdate(); - }); - }, - child: Text( - i18n('Reset'), - style: const TextStyle(color: Colors.white), - ), - ), - const SizedBox(width: 16), - ]), - const SizedBox(height: 20), - Container( - padding: const EdgeInsets.only(left: 16), - child: Text( - i18n('Background Opacity'), - style: const TextStyle(color: Colors.white), - ), - ), - Row(children: [ - const SizedBox(width: 8), - Expanded( - child: Slider( - min: 0, - max: 1, - divisions: 100, - value: widget.layer.backgroundOpacity, - thumbColor: Colors.white, - onChanged: (double value) { - setState(() { - widget.layer.backgroundOpacity = value; - widget.onUpdate(); - }); - }, - ), - ), - TextButton( - onPressed: () { - setState(() { - widget.layer.backgroundOpacity = 0; - widget.onUpdate(); - }); - }, - child: Text( - i18n('Reset'), - style: const TextStyle(color: Colors.white), - ), - ), - const SizedBox(width: 16), - ]), - ]), - ), - const SizedBox(height: 10), - Row(children: [ - Expanded( - child: TextButton( - onPressed: () { - removedLayers.add(layers.removeAt(widget.index)); - - Navigator.pop(context); - widget.onUpdate(); - // back(context); - // setState(() {}); - }, - child: Text( - i18n('Remove'), - style: const TextStyle(color: Colors.white), - ), - ), - ), - ]), - ], - ), - ); - } -} diff --git a/lib/src/components/image_editor/options.dart b/lib/src/components/image_editor/options.dart deleted file mode 100644 index b6327fe..0000000 --- a/lib/src/components/image_editor/options.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:flutter/material.dart'; - -class BrushOption { - /// show background image on draw screen - final bool showBackground; - - /// User will able to move, zoom drawn image - /// Note: Layer may not be placed precisely - final bool translatable; - final List colors; - - const BrushOption({ - this.showBackground = true, - this.translatable = false, - this.colors = const [ - BrushColor(color: Colors.black, background: Colors.white), - BrushColor(color: Colors.white), - BrushColor(color: Colors.blue), - BrushColor(color: Colors.green), - BrushColor(color: Colors.pink), - BrushColor(color: Colors.purple), - BrushColor(color: Colors.brown), - BrushColor(color: Colors.indigo), - ], - }); -} - -class BrushColor { - /// Color of brush - final Color color; - - /// Background color while brush is active only be used when showBackground is false - final Color background; - - const BrushColor({ - required this.color, - this.background = Colors.black, - }); -} - -class EmojiOption { - const EmojiOption(); -} - -class TextOption { - const TextOption(); -} diff --git a/pubspec.lock b/pubspec.lock index 55d1a86..68e729c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -310,22 +310,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" - flex_color_picker: - dependency: "direct main" - description: - name: flex_color_picker - sha256: c083b79f1c57eaeed9f464368be376951230b3cb1876323b784626152a86e480 - url: "https://pub.dev" - source: hosted - version: "3.7.0" - flex_seed_scheme: - dependency: transitive - description: - name: flex_seed_scheme - sha256: d3ba3c5c92d2d79d45e94b4c6c71d01fac3c15017da1545880c53864da5dfeb0 - url: "https://pub.dev" - source: hosted - version: "3.5.0" flutter: dependency: "direct main" description: flutter @@ -1233,4 +1217,4 @@ packages: version: "3.1.3" sdks: dart: ">=3.6.0 <4.0.0" - flutter: ">=3.27.0" + flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index 3c74961..b82a8c5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,6 @@ dependencies: connectivity_plus: ^6.1.2 cv: ^1.1.3 fixnum: ^1.1.1 - flex_color_picker: ^3.7.0 flutter: sdk: flutter flutter_image_compress: ^2.4.0